sgx_gdb.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473
  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. static
  76. int host_pokedata (pid_t pid, void * addr, void * data, int size)
  77. {
  78. for (int off = 0 ; off < size ; off += sizeof(long int)) {
  79. long int ret = host_ptrace(PTRACE_POKEDATA, pid, addr + off,
  80. *(long int *) (data + off));
  81. if (ret < 0)
  82. return ret;
  83. }
  84. return 0;
  85. }
  86. static inline
  87. int host_peektids (int memdev, struct enclave_dbginfo * ei)
  88. {
  89. long int ret;
  90. ret = host_peekdata(ei->pid,
  91. (void *) DBGINFO_ADDR +
  92. offsetof(struct enclave_dbginfo, thread_tids),
  93. ei->thread_tids,
  94. sizeof(ei->thread_tids));
  95. if (ret < 0) {
  96. DEBUG("Failed getting thread information\n");
  97. return ret;
  98. }
  99. for (int i = 0 ; i < MAX_DBG_THREADS ; i++)
  100. if (ei->thread_tids[i]) {
  101. DEBUG("thread %d: GPR at %p\n", ei->thread_tids[i],
  102. (void *) ei->thread_gprs[i]);
  103. }
  104. return ret;
  105. }
  106. static inline
  107. int host_peekonetid (pid_t pid, int memdev, struct enclave_dbginfo * ei)
  108. {
  109. int ret = host_peektids(memdev, ei);
  110. if (ret < 0)
  111. return ret;
  112. for (int i = 0 ;
  113. i < sizeof(ei->thread_tids) / sizeof(ei->thread_tids[0]) ;
  114. i++)
  115. if (ei->thread_tids[i] == pid)
  116. return 0;
  117. DEBUG("No such thread: %d\n", pid);
  118. return -ESRCH;
  119. }
  120. static
  121. int host_peekgpr (int memdev, pid_t pid, struct enclave_dbginfo * ei,
  122. sgx_arch_gpr_t * gpr)
  123. {
  124. int ret;
  125. unsigned long gpr_addr = 0;
  126. for (int i = 0 ;
  127. i < sizeof(ei->thread_tids) / sizeof(ei->thread_tids[0]) ;
  128. i++)
  129. if (ei->thread_tids[i] == pid) {
  130. gpr_addr = ei->thread_gprs[i];
  131. break;
  132. }
  133. if (!gpr_addr) {
  134. DEBUG("No such thread: %d\n", pid);
  135. errno = -ESRCH;
  136. return -1;
  137. }
  138. ret = pread(memdev, gpr, sizeof(sgx_arch_gpr_t), gpr_addr);
  139. if (ret < sizeof(sgx_arch_gpr_t)) {
  140. DEBUG("Can't read GPR data (%p)\n", (void *) gpr_addr);
  141. if (ret >= 0) {
  142. errno = -EFAULT;
  143. ret = -1;
  144. }
  145. return ret;
  146. }
  147. DEBUG("[%d] RIP 0x%08lx RBP 0x%08lx\n", pid, gpr->rip, gpr->rbp);
  148. return 0;
  149. }
  150. static inline
  151. void fill_regs (struct user_regs_struct * regs, sgx_arch_gpr_t * gpr)
  152. {
  153. regs->r15 = gpr->r15;
  154. regs->r14 = gpr->r14;
  155. regs->r13 = gpr->r13;
  156. regs->r12 = gpr->r12;
  157. regs->rbp = gpr->rbp;
  158. regs->rbx = gpr->rbx;
  159. regs->r11 = gpr->r11;
  160. regs->r10 = gpr->r10;
  161. regs->r9 = gpr->r9;
  162. regs->r8 = gpr->r8;
  163. regs->rax = gpr->rax;
  164. regs->rcx = gpr->rcx;
  165. regs->rdx = gpr->rdx;
  166. regs->rsi = gpr->rsi;
  167. regs->rdi = gpr->rdi;
  168. regs->orig_rax = gpr->rax;
  169. regs->rip = gpr->rip;
  170. regs->eflags = gpr->rflags;
  171. regs->rsp = gpr->rsp;
  172. }
  173. static
  174. int host_peekuser (int memdev, pid_t pid, struct enclave_dbginfo * ei,
  175. struct user * ud)
  176. {
  177. sgx_arch_gpr_t gpr;
  178. int ret;
  179. ret = host_peekgpr(memdev, pid, ei, &gpr);
  180. if (ret < 0)
  181. return ret;
  182. fill_regs(&ud->regs, &gpr);
  183. return 0;
  184. }
  185. static
  186. int host_peekregs (int memdev, pid_t pid, struct enclave_dbginfo * ei,
  187. struct user_regs_struct * regdata)
  188. {
  189. sgx_arch_gpr_t gpr;
  190. int ret;
  191. ret = host_peekgpr(memdev, pid, ei, &gpr);
  192. if (ret < 0)
  193. return ret;
  194. fill_regs(regdata, &gpr);
  195. return 0;
  196. }
  197. static
  198. int host_peekfpregs (int memdev,pid_t pid, struct enclave_dbginfo * ei,
  199. struct user_fpregs_struct * fpregdata)
  200. {
  201. sgx_arch_gpr_t gpr;
  202. int ret;
  203. ret = host_peekgpr(memdev, pid, ei, &gpr);
  204. if (ret < 0)
  205. return ret;
  206. return 0;
  207. }
  208. static struct { pid_t pid; int memdev; struct enclave_dbginfo ei; } memdevs[32];
  209. static int nmemdevs = 0;
  210. int open_memdevice (pid_t pid, int * memdev, struct enclave_dbginfo ** ei)
  211. {
  212. int ret;
  213. for (int i = 0 ; i < nmemdevs ; i++)
  214. if (memdevs[i].pid == pid) {
  215. *memdev = memdevs[i].memdev;
  216. *ei = &memdevs[i].ei;
  217. return 0;
  218. }
  219. if (nmemdevs == sizeof(memdevs) / sizeof(memdevs[0]))
  220. return -ENOMEM;
  221. struct enclave_dbginfo eib;
  222. ret = host_peekdata(pid, (void *) DBGINFO_ADDR, &eib,
  223. sizeof(struct enclave_dbginfo));
  224. if (ret < 0) {
  225. return ret;
  226. }
  227. for (int i = 0 ; i < nmemdevs ; i++)
  228. if (memdevs[i].pid == eib.pid) {
  229. *memdev = memdevs[i].memdev;
  230. *ei = &memdevs[i].ei;
  231. return 0;
  232. }
  233. DEBUG("Retrieved enclave information (PID %d)\n", eib.pid);
  234. char memdev_path[40];
  235. int fd;
  236. snprintf(memdev_path, 40, "/proc/%d/mem", pid);
  237. fd = open(memdev_path, O_RDWR);
  238. if (fd < 0)
  239. return fd;
  240. memdevs[nmemdevs].pid = pid;
  241. memdevs[nmemdevs].memdev = fd;
  242. memdevs[nmemdevs].ei = eib;
  243. *memdev = fd;
  244. *ei = &memdevs[nmemdevs].ei;
  245. nmemdevs++;
  246. return 0;
  247. }
  248. static inline
  249. int host_peekisinenclave (pid_t pid, struct enclave_dbginfo * ei)
  250. {
  251. long int ret = host_ptrace(PTRACE_PEEKUSER, pid,
  252. offsetof(struct user, regs.rip));
  253. if (ret < 0) {
  254. DEBUG("Failed peeking user: PID %d\n", pid);
  255. return ret;
  256. }
  257. DEBUG("[%d] User RIP 0x%08lx\n", pid, ret);
  258. return (ret == ei->aep) ? 1 : 0;
  259. }
  260. long int ptrace (enum __ptrace_request request, ...)
  261. {
  262. long int ret = 0, res;
  263. va_list ap;
  264. pid_t pid;
  265. void * addr, * data;
  266. int memdev;
  267. struct enclave_dbginfo * ei;
  268. #if 0
  269. if (request >= 0x4000)
  270. fprintf(stderr, "ptrace(0x%x)\n", request);
  271. else
  272. fprintf(stderr, "ptrace(%d)\n", request);
  273. #endif
  274. va_start(ap, request);
  275. switch (request) {
  276. case PTRACE_PEEKTEXT:
  277. case PTRACE_PEEKDATA: {
  278. pid = va_arg(ap, pid_t);
  279. addr = va_arg(ap, void *);
  280. DEBUG("%d: PEEKTEXT/PEEKDATA(%d, %p)\n", getpid(), pid, addr);
  281. ret = open_memdevice(pid, &memdev, &ei);
  282. if (ret < 0) {
  283. do_host_peekdata:
  284. ret = host_ptrace(PTRACE_PEEKDATA, pid, addr);
  285. break;
  286. }
  287. if (addr < (void *) ei->base ||
  288. addr >= (void *) (ei->base + ei->size))
  289. goto do_host_peekdata;
  290. ret = pread(memdev, &res, sizeof(long int), (unsigned long) addr);
  291. if (ret >= 0)
  292. ret = res;
  293. break;
  294. }
  295. case PTRACE_POKETEXT:
  296. case PTRACE_POKEDATA: {
  297. pid = va_arg(ap, pid_t);
  298. addr = va_arg(ap, void *);
  299. data = va_arg(ap, void *);
  300. DEBUG("%d: POKETEXT/POKEDATA(%d, %p, 0x%016lx)\n", getpid(), pid,
  301. addr, (unsigned long) data);
  302. ret = open_memdevice(pid, &memdev, &ei);
  303. if (ret < 0) {
  304. do_host_pokedata:
  305. errno = 0;
  306. ret = host_ptrace(PTRACE_POKEDATA, pid, addr, data);
  307. break;
  308. }
  309. if (addr < (void *) ei->base ||
  310. addr >= (void *) (ei->base + ei->size))
  311. goto do_host_pokedata;
  312. ret = pwrite(memdev, &data, sizeof(long int), (unsigned long) addr);
  313. break;
  314. }
  315. case PTRACE_PEEKUSER: {
  316. struct user userdata;
  317. pid = va_arg(ap, pid_t);
  318. addr = va_arg(ap, void *);
  319. DEBUG("%d: PEEKUSER(%d, %p)\n", getpid(), pid, addr);
  320. if ((unsigned long) addr >= sizeof(struct user)) {
  321. ret = -EINVAL;
  322. break;
  323. }
  324. ret = open_memdevice(pid, &memdev, &ei);
  325. if (ret < 0) {
  326. do_host_peekuser:
  327. errno = 0;
  328. ret = host_ptrace(PTRACE_PEEKUSER, pid, addr);
  329. break;
  330. }
  331. if (host_peekonetid(pid, memdev, ei) < 0)
  332. goto do_host_peekuser;
  333. if ((unsigned long) addr == offsetof(struct user, regs.fs_base) ||
  334. (unsigned long) addr == offsetof(struct user, regs.gs_base))
  335. goto do_host_peekuser;
  336. if ((unsigned long) addr >= sizeof(struct user_regs_struct))
  337. goto do_host_peekuser;
  338. ret = host_peekisinenclave(pid, ei);
  339. if (ret < 0)
  340. break;
  341. if (!ret)
  342. goto do_host_peekuser;
  343. ret = host_peekuser(memdev, pid, ei, &userdata);
  344. if (ret < 0)
  345. break;
  346. data = (void *) &userdata + (unsigned long) addr;
  347. ret = *(long int *) data;
  348. break;
  349. }
  350. case PTRACE_GETREGS: {
  351. pid = va_arg(ap, pid_t);
  352. addr = va_arg(ap, void *);
  353. data = va_arg(ap, void *);
  354. DEBUG("%d: GETREGS(%d, %p)\n", getpid(), pid, data);
  355. ret = open_memdevice(pid, &memdev, &ei);
  356. if (ret < 0) {
  357. do_host_getregs:
  358. errno = 0;
  359. ret = host_ptrace(PTRACE_GETREGS, pid, addr, data);
  360. break;
  361. }
  362. if (host_peekonetid(pid, memdev, ei) < 0)
  363. goto do_host_getregs;
  364. ret = host_peekisinenclave(pid, ei);
  365. if (ret < 0)
  366. break;
  367. if (!ret)
  368. goto do_host_getregs;
  369. ret = host_peekregs(memdev, pid, ei,
  370. (struct user_regs_struct *) data);
  371. break;
  372. }
  373. default:
  374. ret = __host_ptrace(request, &ap);
  375. break;
  376. }
  377. #if 0
  378. if (ret < 0 && errno) {
  379. if (request >= 0x4000)
  380. fprintf(stderr, "ptrace(0x%x) = -1 (err=%d)\n", request, errno);
  381. else
  382. fprintf(stderr, "ptrace(%d) = -1 (err=%d)\n", request, errno);
  383. }
  384. #endif
  385. va_end(ap);
  386. return ret;
  387. }