sgx_gdb.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481
  1. /* -*- mode:c; c-file-style:"k&r"; c-basic-offset: 4; tab-width:4; indent-tabs-mode:nil; mode:auto-fill; fill-column:78; -*- */
  2. /* vim: set ts=4 sw=4 et tw=78 fo=cqt wm=0: */
  3. #include <stddef.h>
  4. #include <unistd.h>
  5. #include <stdio.h>
  6. #include <fcntl.h>
  7. #include <errno.h>
  8. #include <stdarg.h>
  9. #include <sys/syscall.h>
  10. #include <sys/ptrace.h>
  11. #include <sys/user.h>
  12. #include "sgx_gdb.h"
  13. #include "../sgx_arch.h"
  14. //#define DEBUG_GDB_PTRACE 1
  15. #if DEBUG_GDB_PTRACE == 1
  16. #define DEBUG(fmt, ...) do { fprintf(stderr, fmt, ##__VA_ARGS__); } while (0)
  17. #else
  18. #define DEBUG(fmt, ...) do {} while (0)
  19. #endif
  20. static
  21. long int __host_ptrace (enum __ptrace_request request, va_list * ap)
  22. {
  23. pid_t pid = va_arg(*ap, pid_t);
  24. void * addr = va_arg(*ap, void *);
  25. void * data = va_arg(*ap, void *);
  26. long int res, ret;
  27. if (request > 0 && request < 4)
  28. data = &ret;
  29. res = syscall((long int) SYS_ptrace,
  30. (long int) request,
  31. (long int) pid,
  32. (long int) addr,
  33. (long int) data);
  34. if (res >= 0 && request > 0 && request < 4) {
  35. errno = 0;
  36. res = ret;
  37. }
  38. if (request > 0 && request < 4)
  39. data = NULL;
  40. if (res < 0) {
  41. if (request >= 0x4000)
  42. DEBUG("ptrace(0x%x, %d, %p, %p) = -1 (err=%d)\n", request, pid, addr,
  43. data, errno);
  44. else
  45. DEBUG("ptrace(%d, %d, %p, %p) = -1 (err=%d)\n", request, pid, addr,
  46. data, errno);
  47. } else {
  48. if (request >= 0x4000)
  49. DEBUG("ptrace(0x%x, %d, %p, %p) = 0x%lx\n", request, pid, addr, data, res);
  50. else
  51. DEBUG("ptrace(%d, %d, %p, %p) = 0x%lx\n", request, pid, addr, data, res);
  52. }
  53. return res;
  54. }
  55. static
  56. long int host_ptrace (enum __ptrace_request request, ...)
  57. {
  58. va_list ap;
  59. va_start(ap, request);
  60. long int ret = __host_ptrace(request, &ap);
  61. va_end(ap);
  62. return ret;
  63. }
  64. static
  65. int host_peekdata (pid_t pid, void * addr, void * data, int size)
  66. {
  67. for (int off = 0 ; off < size ; off += sizeof(long int)) {
  68. long int ret = host_ptrace(PTRACE_PEEKDATA, pid, addr + off);
  69. if (ret < 0)
  70. return ret;
  71. *(long int *) (data + off) = ret;
  72. }
  73. return 0;
  74. }
  75. // DEP 11/6/16: Can't figure out where this is used, but reluctant to delete
  76. // just yet
  77. #if 0
  78. static
  79. int host_pokedata (pid_t pid, void * addr, void * data, int size)
  80. {
  81. for (int off = 0 ; off < size ; off += sizeof(long int)) {
  82. long int ret = host_ptrace(PTRACE_POKEDATA, pid, addr + off,
  83. *(long int *) (data + off));
  84. if (ret < 0)
  85. return ret;
  86. }
  87. return 0;
  88. }
  89. #endif
  90. static inline
  91. int host_peektids (int memdev, struct enclave_dbginfo * ei)
  92. {
  93. long int ret;
  94. ret = host_peekdata(ei->pid,
  95. (void *) DBGINFO_ADDR +
  96. offsetof(struct enclave_dbginfo, thread_tids),
  97. ei->thread_tids,
  98. sizeof(ei->thread_tids));
  99. if (ret < 0) {
  100. DEBUG("Failed getting thread information\n");
  101. return ret;
  102. }
  103. for (int i = 0 ; i < MAX_DBG_THREADS ; i++)
  104. if (ei->thread_tids[i]) {
  105. DEBUG("thread %d: GPR at %p\n", ei->thread_tids[i],
  106. (void *) ei->thread_gprs[i]);
  107. }
  108. return ret;
  109. }
  110. static inline
  111. int host_peekonetid (pid_t pid, int memdev, struct enclave_dbginfo * ei)
  112. {
  113. int ret = host_peektids(memdev, ei);
  114. if (ret < 0)
  115. return ret;
  116. for (int i = 0 ;
  117. i < sizeof(ei->thread_tids) / sizeof(ei->thread_tids[0]) ;
  118. i++)
  119. if (ei->thread_tids[i] == pid)
  120. return 0;
  121. DEBUG("No such thread: %d\n", pid);
  122. return -ESRCH;
  123. }
  124. static
  125. int host_peekgpr (int memdev, pid_t pid, struct enclave_dbginfo * ei,
  126. sgx_arch_gpr_t * gpr)
  127. {
  128. int ret;
  129. unsigned long gpr_addr = 0;
  130. for (int i = 0 ;
  131. i < sizeof(ei->thread_tids) / sizeof(ei->thread_tids[0]) ;
  132. i++)
  133. if (ei->thread_tids[i] == pid) {
  134. gpr_addr = ei->thread_gprs[i];
  135. break;
  136. }
  137. if (!gpr_addr) {
  138. DEBUG("No such thread: %d\n", pid);
  139. errno = -ESRCH;
  140. return -1;
  141. }
  142. ret = pread(memdev, gpr, sizeof(sgx_arch_gpr_t), gpr_addr);
  143. if (ret < sizeof(sgx_arch_gpr_t)) {
  144. DEBUG("Can't read GPR data (%p)\n", (void *) gpr_addr);
  145. if (ret >= 0) {
  146. errno = -EFAULT;
  147. ret = -1;
  148. }
  149. return ret;
  150. }
  151. DEBUG("[%d] RIP 0x%08lx RBP 0x%08lx\n", pid, gpr->rip, gpr->rbp);
  152. return 0;
  153. }
  154. static inline
  155. void fill_regs (struct user_regs_struct * regs, sgx_arch_gpr_t * gpr)
  156. {
  157. regs->r15 = gpr->r15;
  158. regs->r14 = gpr->r14;
  159. regs->r13 = gpr->r13;
  160. regs->r12 = gpr->r12;
  161. regs->rbp = gpr->rbp;
  162. regs->rbx = gpr->rbx;
  163. regs->r11 = gpr->r11;
  164. regs->r10 = gpr->r10;
  165. regs->r9 = gpr->r9;
  166. regs->r8 = gpr->r8;
  167. regs->rax = gpr->rax;
  168. regs->rcx = gpr->rcx;
  169. regs->rdx = gpr->rdx;
  170. regs->rsi = gpr->rsi;
  171. regs->rdi = gpr->rdi;
  172. regs->orig_rax = gpr->rax;
  173. regs->rip = gpr->rip;
  174. regs->eflags = gpr->rflags;
  175. regs->rsp = gpr->rsp;
  176. }
  177. static
  178. int host_peekuser (int memdev, pid_t pid, struct enclave_dbginfo * ei,
  179. struct user * ud)
  180. {
  181. sgx_arch_gpr_t gpr;
  182. int ret;
  183. ret = host_peekgpr(memdev, pid, ei, &gpr);
  184. if (ret < 0)
  185. return ret;
  186. fill_regs(&ud->regs, &gpr);
  187. return 0;
  188. }
  189. static
  190. int host_peekregs (int memdev, pid_t pid, struct enclave_dbginfo * ei,
  191. struct user_regs_struct * regdata)
  192. {
  193. sgx_arch_gpr_t gpr;
  194. int ret;
  195. ret = host_peekgpr(memdev, pid, ei, &gpr);
  196. if (ret < 0)
  197. return ret;
  198. fill_regs(regdata, &gpr);
  199. return 0;
  200. }
  201. // DEP 11/6/16: Can't figure out where this is used, but reluctant to delete
  202. // just yet
  203. #if 0
  204. static
  205. int host_peekfpregs (int memdev,pid_t pid, struct enclave_dbginfo * ei,
  206. struct user_fpregs_struct * fpregdata)
  207. {
  208. sgx_arch_gpr_t gpr;
  209. int ret;
  210. ret = host_peekgpr(memdev, pid, ei, &gpr);
  211. if (ret < 0)
  212. return ret;
  213. return 0;
  214. }
  215. #endif
  216. static struct { pid_t pid; int memdev; struct enclave_dbginfo ei; } memdevs[32];
  217. static int nmemdevs = 0;
  218. int open_memdevice (pid_t pid, int * memdev, struct enclave_dbginfo ** ei)
  219. {
  220. int ret;
  221. for (int i = 0 ; i < nmemdevs ; i++)
  222. if (memdevs[i].pid == pid) {
  223. *memdev = memdevs[i].memdev;
  224. *ei = &memdevs[i].ei;
  225. return 0;
  226. }
  227. if (nmemdevs == sizeof(memdevs) / sizeof(memdevs[0]))
  228. return -ENOMEM;
  229. struct enclave_dbginfo eib;
  230. ret = host_peekdata(pid, (void *) DBGINFO_ADDR, &eib,
  231. sizeof(struct enclave_dbginfo));
  232. if (ret < 0) {
  233. return ret;
  234. }
  235. for (int i = 0 ; i < nmemdevs ; i++)
  236. if (memdevs[i].pid == eib.pid) {
  237. *memdev = memdevs[i].memdev;
  238. *ei = &memdevs[i].ei;
  239. return 0;
  240. }
  241. DEBUG("Retrieved enclave information (PID %d)\n", eib.pid);
  242. char memdev_path[40];
  243. int fd;
  244. snprintf(memdev_path, 40, "/proc/%d/mem", pid);
  245. fd = open(memdev_path, O_RDWR);
  246. if (fd < 0)
  247. return fd;
  248. memdevs[nmemdevs].pid = pid;
  249. memdevs[nmemdevs].memdev = fd;
  250. memdevs[nmemdevs].ei = eib;
  251. *memdev = fd;
  252. *ei = &memdevs[nmemdevs].ei;
  253. nmemdevs++;
  254. return 0;
  255. }
  256. static inline
  257. int host_peekisinenclave (pid_t pid, struct enclave_dbginfo * ei)
  258. {
  259. long int ret = host_ptrace(PTRACE_PEEKUSER, pid,
  260. offsetof(struct user, regs.rip));
  261. if (ret < 0) {
  262. DEBUG("Failed peeking user: PID %d\n", pid);
  263. return ret;
  264. }
  265. DEBUG("[%d] User RIP 0x%08lx\n", pid, ret);
  266. return (ret == ei->aep) ? 1 : 0;
  267. }
  268. long int ptrace (enum __ptrace_request request, ...)
  269. {
  270. long int ret = 0, res;
  271. va_list ap;
  272. pid_t pid;
  273. void * addr, * data;
  274. int memdev;
  275. struct enclave_dbginfo * ei;
  276. #if 0
  277. if (request >= 0x4000)
  278. fprintf(stderr, "ptrace(0x%x)\n", request);
  279. else
  280. fprintf(stderr, "ptrace(%d)\n", request);
  281. #endif
  282. va_start(ap, request);
  283. switch (request) {
  284. case PTRACE_PEEKTEXT:
  285. case PTRACE_PEEKDATA: {
  286. pid = va_arg(ap, pid_t);
  287. addr = va_arg(ap, void *);
  288. DEBUG("%d: PEEKTEXT/PEEKDATA(%d, %p)\n", getpid(), pid, addr);
  289. ret = open_memdevice(pid, &memdev, &ei);
  290. if (ret < 0) {
  291. do_host_peekdata:
  292. ret = host_ptrace(PTRACE_PEEKDATA, pid, addr);
  293. break;
  294. }
  295. if (addr < (void *) ei->base ||
  296. addr >= (void *) (ei->base + ei->size))
  297. goto do_host_peekdata;
  298. ret = pread(memdev, &res, sizeof(long int), (unsigned long) addr);
  299. if (ret >= 0)
  300. ret = res;
  301. break;
  302. }
  303. case PTRACE_POKETEXT:
  304. case PTRACE_POKEDATA: {
  305. pid = va_arg(ap, pid_t);
  306. addr = va_arg(ap, void *);
  307. data = va_arg(ap, void *);
  308. DEBUG("%d: POKETEXT/POKEDATA(%d, %p, 0x%016lx)\n", getpid(), pid,
  309. addr, (unsigned long) data);
  310. ret = open_memdevice(pid, &memdev, &ei);
  311. if (ret < 0) {
  312. do_host_pokedata:
  313. errno = 0;
  314. ret = host_ptrace(PTRACE_POKEDATA, pid, addr, data);
  315. break;
  316. }
  317. if (addr < (void *) ei->base ||
  318. addr >= (void *) (ei->base + ei->size))
  319. goto do_host_pokedata;
  320. ret = pwrite(memdev, &data, sizeof(long int), (unsigned long) addr);
  321. break;
  322. }
  323. case PTRACE_PEEKUSER: {
  324. struct user userdata;
  325. pid = va_arg(ap, pid_t);
  326. addr = va_arg(ap, void *);
  327. DEBUG("%d: PEEKUSER(%d, %p)\n", getpid(), pid, addr);
  328. if ((unsigned long) addr >= sizeof(struct user)) {
  329. ret = -EINVAL;
  330. break;
  331. }
  332. ret = open_memdevice(pid, &memdev, &ei);
  333. if (ret < 0) {
  334. do_host_peekuser:
  335. errno = 0;
  336. ret = host_ptrace(PTRACE_PEEKUSER, pid, addr);
  337. break;
  338. }
  339. if (host_peekonetid(pid, memdev, ei) < 0)
  340. goto do_host_peekuser;
  341. if ((unsigned long) addr == offsetof(struct user, regs.fs_base) ||
  342. (unsigned long) addr == offsetof(struct user, regs.gs_base))
  343. goto do_host_peekuser;
  344. if ((unsigned long) addr >= sizeof(struct user_regs_struct))
  345. goto do_host_peekuser;
  346. ret = host_peekisinenclave(pid, ei);
  347. if (ret < 0)
  348. break;
  349. if (!ret)
  350. goto do_host_peekuser;
  351. ret = host_peekuser(memdev, pid, ei, &userdata);
  352. if (ret < 0)
  353. break;
  354. data = (void *) &userdata + (unsigned long) addr;
  355. ret = *(long int *) data;
  356. break;
  357. }
  358. case PTRACE_GETREGS: {
  359. pid = va_arg(ap, pid_t);
  360. addr = va_arg(ap, void *);
  361. data = va_arg(ap, void *);
  362. DEBUG("%d: GETREGS(%d, %p)\n", getpid(), pid, data);
  363. ret = open_memdevice(pid, &memdev, &ei);
  364. if (ret < 0) {
  365. do_host_getregs:
  366. errno = 0;
  367. ret = host_ptrace(PTRACE_GETREGS, pid, addr, data);
  368. break;
  369. }
  370. if (host_peekonetid(pid, memdev, ei) < 0)
  371. goto do_host_getregs;
  372. ret = host_peekisinenclave(pid, ei);
  373. if (ret < 0)
  374. break;
  375. if (!ret)
  376. goto do_host_getregs;
  377. ret = host_peekregs(memdev, pid, ei,
  378. (struct user_regs_struct *) data);
  379. break;
  380. }
  381. default:
  382. ret = __host_ptrace(request, &ap);
  383. break;
  384. }
  385. #if 0
  386. if (ret < 0 && errno) {
  387. if (request >= 0x4000)
  388. fprintf(stderr, "ptrace(0x%x) = -1 (err=%d)\n", request, errno);
  389. else
  390. fprintf(stderr, "ptrace(%d) = -1 (err=%d)\n", request, errno);
  391. }
  392. #endif
  393. va_end(ap);
  394. return ret;
  395. }