You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

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