786 lines
18 KiB

  1. /*
  2. * neercs console-based window manager
  3. * Copyright (c) 2008-2010 Pascal Terjan <pterjan@linuxfr.org>
  4. * 2008-2010 Sam Hocevar <sam@hocevar.net>
  5. * All Rights Reserved
  6. *
  7. * This program is free software. It comes without any warranty, to
  8. * the extent permitted by applicable law. You can redistribute it
  9. * and/or modify it under the terms of the Do What The Fuck You Want
  10. * To Public License, Version 2, as published by Sam Hocevar. See
  11. * http://sam.zoy.org/wtfpl/COPYING for more details.
  12. */
  13. #include "config.h"
  14. #include <errno.h>
  15. #include <fcntl.h>
  16. #include <limits.h>
  17. #include <stdio.h>
  18. #include <stdlib.h>
  19. #include <string.h>
  20. #if defined USE_GRAB
  21. # include <sys/ioctl.h>
  22. # include <sys/ptrace.h>
  23. # include <sys/stat.h>
  24. # include <sys/syscall.h>
  25. # include <sys/user.h>
  26. # include <sys/wait.h>
  27. #endif
  28. #include "neercs.h"
  29. #include "mytrace.h"
  30. #if defined USE_GRAB
  31. static int memcpy_from_target(struct mytrace *t,
  32. char *dest, long src, size_t n);
  33. static int memcpy_into_target(struct mytrace *t,
  34. long dest, char const *src, size_t n);
  35. static long remote_syscall(struct mytrace *t, long call,
  36. long arg1, long arg2, long arg3);
  37. # if defined DEBUG
  38. static void print_registers(pid_t pid);
  39. # else
  40. # define print_registers(x) do {} while(0)
  41. # endif
  42. #define X(x) #x
  43. #define STRINGIFY(x) X(x)
  44. #define SYSCALL_X86 0x80cd /* CD 80 = int $0x80 */
  45. #define SYSCALL_X86_NEW 0xf3eb /* EB F3 = jmp <__kernel_vsyscall+0x3> */
  46. #define SYSENTER 0x340f /* 0F 34 = sysenter */
  47. #define SYSCALL_AMD64 0x050fL /* 0F 05 = syscall */
  48. #if defined __x86_64__
  49. # define RAX rax
  50. # define RBX rbx
  51. # define RCX rcx
  52. # define RDX rdx
  53. # define RSP rsp
  54. # define RBP rbp
  55. # define RIP rip
  56. # define RDI rdi
  57. # define RSI rsi
  58. # define FMT "%016lx"
  59. #else
  60. # define RAX eax
  61. # define RBX ebx
  62. # define RCX ecx
  63. # define RDX edx
  64. # define RSP esp
  65. # define RBP ebp
  66. # define RIP eip
  67. # define RDI edi
  68. # define RSI esi
  69. # define FMT "%08lx"
  70. #endif
  71. #define MYCALL_OPEN 0
  72. #define MYCALL_CLOSE 1
  73. #define MYCALL_WRITE 2
  74. #define MYCALL_DUP2 3
  75. #define MYCALL_SETPGID 4
  76. #define MYCALL_SETSID 5
  77. #define MYCALL_KILL 6
  78. #define MYCALL_FORK 7
  79. #define MYCALL_EXIT 8
  80. #define MYCALL_EXECVE 9
  81. #define MYCALL_IOCTL 10
  82. #if defined __x86_64__
  83. /* from unistd_32.h on an amd64 system */
  84. int syscalls32[] = { 5, 6, 4, 63, 57, 66, 37, 2, 1, 11, 54 };
  85. int syscalls64[] =
  86. #else
  87. int syscalls32[] =
  88. #endif
  89. { SYS_open, SYS_close, SYS_write, SYS_dup2, SYS_setpgid, SYS_setsid,
  90. SYS_kill, SYS_fork, SYS_exit, SYS_execve, SYS_ioctl
  91. };
  92. char const *syscallnames[] =
  93. { "open", "close", "write", "dup2", "setpgid", "setsid", "kill", "fork",
  94. "exit", "execve", "ioctl"
  95. };
  96. #endif /* USE_GRAB */
  97. struct mytrace
  98. {
  99. pid_t pid, child;
  100. };
  101. struct mytrace *mytrace_attach(long int pid)
  102. {
  103. #if defined USE_GRAB
  104. struct mytrace *t;
  105. int status;
  106. if (ptrace(PTRACE_ATTACH, pid, 0, 0) < 0)
  107. {
  108. perror("PTRACE_ATTACH (attach)");
  109. return NULL;
  110. }
  111. if (waitpid(pid, &status, 0) < 0)
  112. {
  113. perror("waitpid");
  114. return NULL;
  115. }
  116. if (!WIFSTOPPED(status))
  117. {
  118. fprintf(stderr, "traced process was not stopped\n");
  119. ptrace(PTRACE_DETACH, pid, 0, 0);
  120. return NULL;
  121. }
  122. t = malloc(sizeof(struct mytrace));
  123. t->pid = pid;
  124. t->child = 0;
  125. return t;
  126. #else
  127. errno = ENOSYS;
  128. return NULL;
  129. #endif
  130. }
  131. struct mytrace *mytrace_fork(struct mytrace *t)
  132. {
  133. #if defined USE_GRAB
  134. struct mytrace *child;
  135. ptrace(PTRACE_SETOPTIONS, t->pid, NULL, PTRACE_O_TRACEFORK);
  136. remote_syscall(t, MYCALL_FORK, 0, 0, 0);
  137. waitpid(t->child, NULL, 0);
  138. child = malloc(sizeof(struct mytrace));
  139. child->pid = t->child;
  140. child->child = 0;
  141. return child;
  142. #else
  143. errno = ENOSYS;
  144. return NULL;
  145. #endif
  146. }
  147. int mytrace_detach(struct mytrace *t)
  148. {
  149. #if defined USE_GRAB
  150. ptrace(PTRACE_DETACH, t->pid, 0, 0);
  151. free(t);
  152. return 0;
  153. #else
  154. errno = ENOSYS;
  155. return -1;
  156. #endif
  157. }
  158. long mytrace_getpid(struct mytrace *t)
  159. {
  160. #if defined USE_GRAB
  161. return t->pid;
  162. #else
  163. errno = ENOSYS;
  164. return -1;
  165. #endif
  166. }
  167. int mytrace_open(struct mytrace *t, char const *path, int mode)
  168. {
  169. #if defined USE_GRAB
  170. char backup_data[4096];
  171. struct user_regs_struct regs;
  172. size_t size = strlen(path) + 1;
  173. int ret, err;
  174. if (ptrace(PTRACE_GETREGS, t->pid, NULL, &regs) < 0)
  175. {
  176. perror("PTRACE_GETREGS (open)\n");
  177. return -1;
  178. }
  179. /* Backup the data that we will use */
  180. if (memcpy_from_target(t, backup_data, regs.RSP, size) < 0)
  181. return -1;
  182. memcpy_into_target(t, regs.RSP, path, size);
  183. ret = remote_syscall(t, MYCALL_OPEN, regs.RSP, O_RDWR, 0755);
  184. err = errno;
  185. /* Restore the data */
  186. memcpy_into_target(t, regs.RSP, backup_data, size);
  187. errno = err;
  188. return ret;
  189. #else
  190. errno = ENOSYS;
  191. return -1;
  192. #endif
  193. }
  194. int mytrace_close(struct mytrace *t, int fd)
  195. {
  196. #if defined USE_GRAB
  197. return remote_syscall(t, MYCALL_CLOSE, fd, 0, 0);
  198. #else
  199. errno = ENOSYS;
  200. return -1;
  201. #endif
  202. }
  203. int mytrace_write(struct mytrace *t, int fd, char const *data, size_t len)
  204. {
  205. #if defined USE_GRAB
  206. struct user_regs_struct regs;
  207. char *backup_data;
  208. int ret, err;
  209. if (ptrace(PTRACE_GETREGS, t->pid, NULL, &regs) < 0)
  210. {
  211. perror("PTRACE_GETREGS (write)\n");
  212. return -1;
  213. }
  214. backup_data = malloc(len);
  215. /* Backup the data that we will use */
  216. if (memcpy_from_target(t, backup_data, regs.RSP, len) < 0)
  217. return -1;
  218. memcpy_into_target(t, regs.RSP, data, len);
  219. ret = remote_syscall(t, MYCALL_WRITE, fd, regs.RSP, len);
  220. err = errno;
  221. /* Restore the data */
  222. memcpy_into_target(t, regs.RSP, backup_data, len);
  223. errno = err;
  224. return ret;
  225. #else
  226. errno = ENOSYS;
  227. return -1;
  228. #endif
  229. }
  230. int mytrace_dup2(struct mytrace *t, int oldfd, int newfd)
  231. {
  232. #if defined USE_GRAB
  233. return remote_syscall(t, MYCALL_DUP2, oldfd, newfd, 0);
  234. #else
  235. errno = ENOSYS;
  236. return -1;
  237. #endif
  238. }
  239. int mytrace_setpgid(struct mytrace *t, long pid, long pgid)
  240. {
  241. #if defined USE_GRAB
  242. return remote_syscall(t, MYCALL_SETPGID, pid, pgid, 0);
  243. #else
  244. errno = ENOSYS;
  245. return -1;
  246. #endif
  247. }
  248. int mytrace_setsid(struct mytrace *t)
  249. {
  250. #if defined USE_GRAB
  251. return remote_syscall(t, MYCALL_SETSID, 0, 0, 0);
  252. #else
  253. errno = ENOSYS;
  254. return -1;
  255. #endif
  256. }
  257. int mytrace_kill(struct mytrace *t, long pid, int sig)
  258. {
  259. #if defined USE_GRAB
  260. return remote_syscall(t, MYCALL_KILL, pid, sig, 0);
  261. #else
  262. errno = ENOSYS;
  263. return -1;
  264. #endif
  265. }
  266. int mytrace_exit(struct mytrace *t, int status)
  267. {
  268. #if defined USE_GRAB
  269. ptrace(PTRACE_SETOPTIONS, t->pid, NULL, PTRACE_O_TRACEEXIT);
  270. return remote_syscall(t, MYCALL_EXIT, status, 0, 0);
  271. #else
  272. errno = ENOSYS;
  273. return -1;
  274. #endif
  275. }
  276. int mytrace_exec(struct mytrace *t, char const *command)
  277. {
  278. #if defined USE_GRAB
  279. struct user_regs_struct regs;
  280. char *env, *p;
  281. long p2, envaddr, argvaddr, envptraddr;
  282. char envpath[PATH_MAX + 1];
  283. ssize_t envsize = 16 * 1024;
  284. int ret, fd, l, l2;
  285. char *nullp = NULL;
  286. ssize_t r;
  287. ptrace(PTRACE_SETOPTIONS, t->pid, NULL, PTRACE_O_TRACEEXEC);
  288. if (ptrace(PTRACE_GETREGS, t->pid, NULL, &regs) < 0)
  289. {
  290. perror("PTRACE_GETREGS (exec)\n");
  291. return -1;
  292. }
  293. debug("PTRACE_GETREGS done");
  294. env = malloc(envsize);
  295. if (!env)
  296. return -1;
  297. snprintf(envpath, PATH_MAX, "/proc/%d/environ", t->pid);
  298. fd = open(envpath, O_RDONLY);
  299. if (fd == -1)
  300. return -1;
  301. r = read(fd, env, envsize);
  302. close(fd);
  303. if (r == -1)
  304. return -1;
  305. while (r == envsize)
  306. {
  307. free(env);
  308. env = malloc(envsize);
  309. if (!env)
  310. return -1;
  311. fd = open(envpath, O_RDONLY);
  312. r = read(fd, env, envsize);
  313. close(fd);
  314. if (r == -1)
  315. return -1;
  316. }
  317. envsize = r;
  318. l2 = sizeof(char *); /* Size of a pointer */
  319. p2 = regs.RSP;
  320. /* First argument is the command string */
  321. l = strlen(command) + 1;
  322. memcpy_into_target(t, p2, command, l);
  323. p2 += l;
  324. /* Second argument is argv */
  325. argvaddr = p2;
  326. /* argv[0] is a pointer to the command string */
  327. memcpy_into_target(t, p2, (char *)&regs.RSP, l2);
  328. p2 += l2;
  329. /* Then follows a NULL pointer */
  330. memcpy_into_target(t, p2, (char *)&nullp, l2);
  331. p2 += l2;
  332. /* Third argument is the environment */
  333. /* First, copy all the strings */
  334. memcpy_into_target(t, p2, env, envsize);
  335. envaddr = p2;
  336. p2 += envsize;
  337. /* Then write an array of pointers to the strings */
  338. envptraddr = p2;
  339. p = env;
  340. while (p < env + envsize)
  341. {
  342. long diffp = p - env + envaddr;
  343. memcpy_into_target(t, p2, (char *)&diffp, l2);
  344. p2 += l2;
  345. p += strlen(p) + 1;
  346. }
  347. /* And have a NULL pointer at the end of the array */
  348. memcpy_into_target(t, p2, (char *)&nullp, l2);
  349. free(env);
  350. ret = remote_syscall(t, MYCALL_EXECVE, regs.RSP, argvaddr, envptraddr);
  351. return ret;
  352. #else
  353. errno = ENOSYS;
  354. return -1;
  355. #endif
  356. }
  357. int mytrace_tcgets(struct mytrace *t, int fd, struct termios *tos)
  358. {
  359. #if defined USE_GRAB
  360. char backup_data[4096];
  361. struct user_regs_struct regs;
  362. size_t size = sizeof(struct termios);
  363. int ret, err;
  364. if (ptrace(PTRACE_GETREGS, t->pid, NULL, &regs) < 0)
  365. {
  366. perror("PTRACE_GETREGS (tcgets)\n");
  367. return -1;
  368. }
  369. /* Backup the data that we will use */
  370. if (memcpy_from_target(t, backup_data, regs.RSP, size) < 0)
  371. return -1;
  372. ret = remote_syscall(t, MYCALL_IOCTL, fd, TCGETS, regs.RSP);
  373. err = errno;
  374. memcpy_from_target(t, (char *)tos, regs.RSP, size);
  375. /* Restore the data */
  376. memcpy_into_target(t, regs.RSP, backup_data, size);
  377. errno = err;
  378. return ret;
  379. #else
  380. errno = ENOSYS;
  381. return -1;
  382. #endif
  383. }
  384. int mytrace_tcsets(struct mytrace *t, int fd, struct termios *tos)
  385. {
  386. #if defined USE_GRAB
  387. char backup_data[4096];
  388. struct user_regs_struct regs;
  389. size_t size = sizeof(struct termios);
  390. int ret, err;
  391. if (ptrace(PTRACE_GETREGS, t->pid, NULL, &regs) < 0)
  392. {
  393. perror("PTRACE_GETREGS (tcsets)\n");
  394. return -1;
  395. }
  396. /* Backup the data that we will use */
  397. if (memcpy_from_target(t, backup_data, regs.RSP, size) < 0)
  398. return -1;
  399. memcpy_into_target(t, regs.RSP, (char *)tos, size);
  400. ret = remote_syscall(t, MYCALL_IOCTL, fd, TCSETS, regs.RSP);
  401. err = errno;
  402. /* Restore the data */
  403. memcpy_into_target(t, regs.RSP, backup_data, size);
  404. errno = err;
  405. return ret;
  406. #else
  407. errno = ENOSYS;
  408. return -1;
  409. #endif
  410. }
  411. int mytrace_sctty(struct mytrace *t, int fd)
  412. {
  413. #if defined USE_GRAB
  414. ptrace(PTRACE_SETOPTIONS, t->pid, NULL, PTRACE_O_TRACEEXIT);
  415. return remote_syscall(t, MYCALL_IOCTL, fd, TIOCSCTTY, 0);
  416. #else
  417. errno = ENOSYS;
  418. return -1;
  419. #endif
  420. }
  421. /*
  422. * XXX: the following functions are local
  423. */
  424. #if defined USE_GRAB
  425. static int memcpy_from_target(struct mytrace *t,
  426. char *dest, long src, size_t n)
  427. {
  428. static int const align = sizeof(long) - 1;
  429. while (n)
  430. {
  431. long data;
  432. size_t todo = sizeof(long) - (src & align);
  433. if (n < todo)
  434. todo = n;
  435. data = ptrace(PTRACE_PEEKTEXT, t->pid, src - (src & align), 0);
  436. if (errno)
  437. {
  438. perror("ptrace_peektext (memcpy_from_target)");
  439. return -1;
  440. }
  441. memcpy(dest, (char *)&data + (src & align), todo);
  442. dest += todo;
  443. src += todo;
  444. n -= todo;
  445. }
  446. return 0;
  447. }
  448. static int memcpy_into_target(struct mytrace *t,
  449. long dest, char const *src, size_t n)
  450. {
  451. static int const align = sizeof(long) - 1;
  452. while (n)
  453. {
  454. long data;
  455. size_t todo = sizeof(long) - (dest & align);
  456. if (n < todo)
  457. todo = n;
  458. if (todo != sizeof(long))
  459. {
  460. data = ptrace(PTRACE_PEEKTEXT, t->pid, dest - (dest & align), 0);
  461. if (errno)
  462. {
  463. perror("ptrace_peektext (memcpy_into_target)");
  464. return -1;
  465. }
  466. }
  467. memcpy((char *)&data + (dest & align), src, todo);
  468. if (ptrace(PTRACE_POKETEXT, t->pid, dest - (dest & align), data) < 0)
  469. {
  470. perror("ptrace_poketext (memcpy_into_target)");
  471. return -1;
  472. }
  473. src += todo;
  474. dest += todo;
  475. n -= todo;
  476. }
  477. return 0;
  478. }
  479. static long remote_syscall(struct mytrace *t, long call,
  480. long arg1, long arg2, long arg3)
  481. {
  482. /* Method for remote syscall: - wait until the traced application exits
  483. from a syscall - save registers - rewind eip/rip to point on the
  484. syscall instruction - single step: execute syscall instruction -
  485. retrieve resulting registers - restore registers */
  486. struct user_regs_struct regs, oldregs;
  487. long oinst;
  488. int bits;
  489. int offset = 2;
  490. if (call < 0
  491. || call >= (long)(sizeof(syscallnames) / sizeof(*syscallnames)))
  492. {
  493. fprintf(stderr, "unknown remote syscall %li\n", call);
  494. return -1;
  495. }
  496. debug("remote syscall %s(0x%lx, 0x%lx, 0x%lx)",
  497. syscallnames[call], arg1, arg2, arg3);
  498. #if defined __x86_64__
  499. bits = 64;
  500. #else
  501. bits = 32;
  502. #endif
  503. for (;;)
  504. {
  505. if (ptrace(PTRACE_GETREGS, t->pid, NULL, &oldregs) < 0)
  506. {
  507. perror("PTRACE_GETREGS (syscall 1)\n");
  508. return -1;
  509. }
  510. oinst = ptrace(PTRACE_PEEKTEXT, t->pid, oldregs.RIP - 2, 0) & 0xffff;
  511. #if defined __x86_64__
  512. if (oinst == SYSCALL_AMD64)
  513. break;
  514. #endif
  515. if (oinst == SYSCALL_X86 || oinst == SYSCALL_X86_NEW)
  516. {
  517. bits = 32;
  518. break;
  519. }
  520. if (ptrace(PTRACE_SYSCALL, t->pid, NULL, 0) < 0)
  521. {
  522. perror("ptrace_syscall (1)");
  523. return -1;
  524. }
  525. waitpid(t->pid, NULL, 0);
  526. if (ptrace(PTRACE_SYSCALL, t->pid, NULL, 0) < 0)
  527. {
  528. perror("ptrace_syscall (2)");
  529. return -1;
  530. }
  531. waitpid(t->pid, NULL, 0);
  532. }
  533. print_registers(t->pid);
  534. if (oinst == SYSCALL_X86_NEW)
  535. {
  536. /* Get back to sysenter */
  537. while ((ptrace(PTRACE_PEEKTEXT, t->pid, oldregs.RIP - offset, 0) &
  538. 0xffff) != 0x340f)
  539. offset++;
  540. oldregs.RBP = oldregs.RSP;
  541. }
  542. regs = oldregs;
  543. regs.RIP = regs.RIP - offset;
  544. #if defined __x86_64__
  545. if (bits == 64)
  546. {
  547. regs.RAX = syscalls64[call];
  548. regs.RDI = arg1;
  549. regs.RSI = arg2;
  550. regs.RDX = arg3;
  551. }
  552. else
  553. #endif
  554. {
  555. regs.RAX = syscalls32[call];
  556. regs.RBX = arg1;
  557. regs.RCX = arg2;
  558. regs.RDX = arg3;
  559. }
  560. if (ptrace(PTRACE_SETREGS, t->pid, NULL, &regs) < 0)
  561. {
  562. perror("PTRACE_SETREGS (syscall 1)\n");
  563. return -1;
  564. }
  565. for (;;)
  566. {
  567. int status;
  568. print_registers(t->pid);
  569. if (ptrace(PTRACE_SINGLESTEP, t->pid, NULL, NULL) < 0)
  570. {
  571. perror("PTRACE_SINGLESTEP (syscall)\n");
  572. return -1;
  573. }
  574. waitpid(t->pid, &status, 0);
  575. if (WIFEXITED(status))
  576. return 0;
  577. if (!WIFSTOPPED(status) || WSTOPSIG(status) != SIGTRAP)
  578. continue;
  579. /* Fuck Linux: there is no macro for this */
  580. switch ((status >> 16) & 0xffff)
  581. {
  582. case PTRACE_EVENT_FORK:
  583. if (ptrace(PTRACE_GETEVENTMSG, t->pid, 0, &t->child) < 0)
  584. {
  585. perror("PTRACE_GETEVENTMSG (syscall)\n");
  586. return -1;
  587. }
  588. debug("PTRACE_GETEVENTMSG %d", t->child);
  589. continue;
  590. case PTRACE_EVENT_EXIT:
  591. debug("PTRACE_EVENT_EXIT");
  592. /* The process is about to exit, don't do anything else */
  593. return 0;
  594. case PTRACE_EVENT_EXEC:
  595. debug("PTRACE_EVENT_EXEC");
  596. return 0;
  597. }
  598. break;
  599. }
  600. print_registers(t->pid);
  601. if (ptrace(PTRACE_GETREGS, t->pid, NULL, &regs) < 0)
  602. {
  603. perror("PTRACE_GETREGS (syscall 2)\n");
  604. return -1;
  605. }
  606. if (ptrace(PTRACE_SETREGS, t->pid, NULL, &oldregs) < 0)
  607. {
  608. perror("PTRACE_SETREGS (syscall 2)\n");
  609. return -1;
  610. }
  611. print_registers(t->pid);
  612. debug("syscall %s returned %ld", syscallnames[call], regs.RAX);
  613. if ((long)regs.RAX < 0)
  614. {
  615. errno = -(long)regs.RAX;
  616. perror("syscall");
  617. return -1;
  618. }
  619. return regs.RAX;
  620. }
  621. /* For debugging purposes only. Prints register and stack information. */
  622. #if defined DEBUG
  623. static void print_registers(pid_t pid)
  624. {
  625. union
  626. {
  627. long int l;
  628. unsigned char data[sizeof(long int)];
  629. } inst;
  630. struct user_regs_struct regs;
  631. int i;
  632. if (ptrace(PTRACE_GETREGS, pid, NULL, &regs) < 0)
  633. {
  634. perror("PTRACE_GETREGS (syscall 2)");
  635. exit(errno);
  636. }
  637. fprintf(stderr, " / %s: " FMT " ", STRINGIFY(RAX), regs.RAX);
  638. fprintf(stderr, "%s: " FMT "\n", STRINGIFY(RBX), regs.RBX);
  639. fprintf(stderr, " | %s: " FMT " ", STRINGIFY(RCX), regs.RCX);
  640. fprintf(stderr, "%s: " FMT "\n", STRINGIFY(RDX), regs.RDX);
  641. fprintf(stderr, " | %s: " FMT " ", STRINGIFY(RDI), regs.RDI);
  642. fprintf(stderr, "%s: " FMT "\n", STRINGIFY(RSI), regs.RSI);
  643. fprintf(stderr, " | %s: " FMT " ", STRINGIFY(RSP), regs.RSP);
  644. fprintf(stderr, "%s: " FMT "\n", STRINGIFY(RIP), regs.RIP);
  645. inst.l = ptrace(PTRACE_PEEKTEXT, pid, regs.RIP - 4, 0);
  646. fprintf(stderr, " | code: ... %02x %02x %02x %02x <---> ",
  647. inst.data[0], inst.data[1], inst.data[2], inst.data[3]);
  648. inst.l = ptrace(PTRACE_PEEKTEXT, pid, regs.RIP, 0);
  649. fprintf(stderr, "%02x %02x %02x %02x ...\n",
  650. inst.data[0], inst.data[1], inst.data[2], inst.data[3]);
  651. fprintf(stderr, " \\ stack: ... ");
  652. for (i = -16; i < 24; i += sizeof(long))
  653. {
  654. inst.l = ptrace(PTRACE_PEEKDATA, pid, regs.RSP + i, 0);
  655. #if defined __x86_64__
  656. fprintf(stderr, "%02x %02x %02x %02x %02x %02x %02x %02x ",
  657. inst.data[0], inst.data[1], inst.data[2], inst.data[3],
  658. inst.data[4], inst.data[5], inst.data[6], inst.data[7]);
  659. #else
  660. fprintf(stderr, "%02x %02x %02x %02x ",
  661. inst.data[0], inst.data[1], inst.data[2], inst.data[3]);
  662. #endif
  663. if (i == 0)
  664. fprintf(stderr, "[%s] ", STRINGIFY(RSP));
  665. }
  666. fprintf(stderr, "...\n");
  667. }
  668. #endif /* DEBUG */
  669. #endif /* USE_GRAB */