sgx_gdb.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701
  1. #define _GNU_SOURCE
  2. #include "sgx_gdb.h"
  3. #include <assert.h>
  4. #include <errno.h>
  5. #include <fcntl.h>
  6. #include <signal.h>
  7. #include <stdarg.h>
  8. #include <stdbool.h>
  9. #include <stddef.h>
  10. #include <stdio.h>
  11. #include <string.h>
  12. #include <sys/ptrace.h>
  13. #include <sys/syscall.h>
  14. #include <sys/user.h>
  15. #include <unistd.h>
  16. #include <wait.h>
  17. #include "../sgx_arch.h"
  18. //#define DEBUG_GDB_PTRACE 1
  19. #if DEBUG_GDB_PTRACE == 1
  20. #define DEBUG(fmt, ...) \
  21. do { \
  22. fprintf(stderr, fmt, ##__VA_ARGS__); \
  23. } while (0)
  24. #else
  25. #define DEBUG(fmt, ...) \
  26. do { \
  27. } while (0)
  28. #endif
  29. static int memdevs_cnt = 0;
  30. static struct {
  31. struct enclave_dbginfo ei;
  32. pid_t pid;
  33. int memdev;
  34. } memdevs[32];
  35. #if DEBUG_GDB_PTRACE == 1
  36. static char* str_ptrace_request(enum __ptrace_request request) {
  37. static char buf[50];
  38. int prev_errno;
  39. switch (request) {
  40. case PTRACE_TRACEME:
  41. return "TRACEME";
  42. case PTRACE_PEEKTEXT:
  43. return "PEEKTEXT";
  44. case PTRACE_PEEKDATA:
  45. return "PEEKDATA";
  46. case PTRACE_POKETEXT:
  47. return "POKETEXT";
  48. case PTRACE_POKEDATA:
  49. return "POKEDATA";
  50. case PTRACE_PEEKUSER:
  51. return "PEEKUSER";
  52. case PTRACE_POKEUSER:
  53. return "POKEUSER";
  54. case PTRACE_GETREGS:
  55. return "GETREGS";
  56. case PTRACE_SETREGS:
  57. return "SETREGS";
  58. case PTRACE_SINGLESTEP:
  59. return "SINGLESTEP";
  60. case PTRACE_CONT:
  61. return "CONT";
  62. case PTRACE_KILL:
  63. return "KILL";
  64. case PTRACE_ATTACH:
  65. return "ATTACH";
  66. case PTRACE_DETACH:
  67. return "DETACH";
  68. default: /* fallthrough */;
  69. }
  70. prev_errno = errno; /* snprintf can contaminate errno */
  71. snprintf(buf, sizeof(buf), "0x%x", request);
  72. errno = prev_errno;
  73. return buf;
  74. }
  75. #endif
  76. static void fill_regs(struct user_regs_struct* regs, const sgx_pal_gpr_t* gpr) {
  77. regs->orig_rax = gpr->rax;
  78. regs->rax = gpr->rax;
  79. regs->rcx = gpr->rcx;
  80. regs->rdx = gpr->rdx;
  81. regs->rbx = gpr->rbx;
  82. regs->rsp = gpr->rsp;
  83. regs->rbp = gpr->rbp;
  84. regs->rsi = gpr->rsi;
  85. regs->rdi = gpr->rdi;
  86. regs->r8 = gpr->r8;
  87. regs->r9 = gpr->r9;
  88. regs->r10 = gpr->r10;
  89. regs->r11 = gpr->r11;
  90. regs->r12 = gpr->r12;
  91. regs->r13 = gpr->r13;
  92. regs->r14 = gpr->r14;
  93. regs->r15 = gpr->r15;
  94. regs->rip = gpr->rip;
  95. regs->eflags = gpr->rflags;
  96. regs->fs_base = gpr->fsbase;
  97. regs->gs_base = gpr->gsbase;
  98. /* dummy values for non-SGX-saved regs */
  99. regs->cs = 0;
  100. regs->ss = 0;
  101. regs->ds = 0;
  102. regs->es = 0;
  103. regs->fs = 0;
  104. regs->gs = 0;
  105. }
  106. static void fill_gpr(sgx_pal_gpr_t* gpr, const struct user_regs_struct* regs) {
  107. gpr->rax = regs->rax;
  108. gpr->rcx = regs->rcx;
  109. gpr->rdx = regs->rdx;
  110. gpr->rbx = regs->rbx;
  111. gpr->rsp = regs->rsp;
  112. gpr->rbp = regs->rbp;
  113. gpr->rsi = regs->rsi;
  114. gpr->rdi = regs->rdi;
  115. gpr->r8 = regs->r8;
  116. gpr->r9 = regs->r9;
  117. gpr->r10 = regs->r10;
  118. gpr->r11 = regs->r11;
  119. gpr->r12 = regs->r12;
  120. gpr->r13 = regs->r13;
  121. gpr->r14 = regs->r14;
  122. gpr->r15 = regs->r15;
  123. gpr->rip = regs->rip;
  124. gpr->rflags = regs->eflags;
  125. gpr->fsbase = regs->fs_base;
  126. gpr->gsbase = regs->gs_base;
  127. }
  128. /* This function emulates Glibc ptrace() by issuing ptrace syscall and
  129. * setting errno on error. It is used to access non-enclave memory. */
  130. static long int host_ptrace(enum __ptrace_request request, pid_t tid, void* addr, void* data) {
  131. long int res, ret, is_dbginfo_addr;
  132. int ptrace_errno;
  133. /* If request is PTRACE_PEEKTEXT, PTRACE_PEEKDATA, or PTRACE_PEEKUSER
  134. * then ptrace syscall stores result at address specified by data;
  135. * our wrapper however conforms to Glibc and returns the result as
  136. * return value (with data being ignored). See ptrace(2) NOTES. */
  137. if (request == PTRACE_PEEKTEXT || request == PTRACE_PEEKDATA || request == PTRACE_PEEKUSER) {
  138. data = &res;
  139. }
  140. errno = 0;
  141. ret = syscall((long int)SYS_ptrace, (long int)request, (long int)tid, (long int)addr,
  142. (long int)data);
  143. ptrace_errno = errno;
  144. /* check on dbginfo address to filter ei peeks for less noisy debug */
  145. is_dbginfo_addr = (addr >= (void*)DBGINFO_ADDR &&
  146. addr < (void*)(DBGINFO_ADDR + sizeof(struct enclave_dbginfo)));
  147. if (!is_dbginfo_addr)
  148. DEBUG("[GDB %d] Executed host_ptrace(%s, %d, %p, %p) = %ld\n", getpid(),
  149. str_ptrace_request(request), tid, addr, data, ret);
  150. if (ret < 0 && ptrace_errno != 0) {
  151. errno = ptrace_errno; /* DEBUG/getpid could contaminate errno */
  152. return -1;
  153. }
  154. ret = 0;
  155. if (request == PTRACE_PEEKTEXT || request == PTRACE_PEEKDATA || request == PTRACE_PEEKUSER) {
  156. ret = res;
  157. }
  158. return ret;
  159. }
  160. /* Update GDB's copy of ei.thread_tids with current enclave's ei.thread_tids */
  161. static int update_thread_tids(struct enclave_dbginfo* ei) {
  162. long int res;
  163. void* src = (void*)DBGINFO_ADDR + offsetof(struct enclave_dbginfo, thread_tids);
  164. void* dst = (void*)ei + offsetof(struct enclave_dbginfo, thread_tids);
  165. static_assert((sizeof(ei->thread_tids) % sizeof(long)) == 0,
  166. "Unsupported ei->thread_tids size");
  167. for (int off = 0; off < sizeof(ei->thread_tids); off += sizeof(long)) {
  168. errno = 0;
  169. res = host_ptrace(PTRACE_PEEKDATA, ei->pid, src + off, NULL);
  170. if (res < 0 && errno != 0) {
  171. /* benign failure: enclave is not yet initialized */
  172. return -1;
  173. }
  174. *(long int*)(dst + off) = res;
  175. }
  176. return 0;
  177. }
  178. static void* get_gpr_addr(int memdev, pid_t tid, struct enclave_dbginfo* ei) {
  179. void* tcs_addr = NULL;
  180. struct {
  181. uint64_t ossa;
  182. uint32_t cssa, nssa;
  183. } tcs_part;
  184. int ret;
  185. for (int i = 0; i < MAX_DBG_THREADS; i++)
  186. if (ei->thread_tids[i] == tid) {
  187. tcs_addr = ei->tcs_addrs[i];
  188. break;
  189. }
  190. if (!tcs_addr) {
  191. DEBUG("Cannot find enclave thread %d to peek/poke its GPR\n", tid);
  192. return NULL;
  193. }
  194. ret = pread(memdev, &tcs_part, sizeof(tcs_part),
  195. (off_t)tcs_addr + offsetof(sgx_arch_tcs_t, ossa));
  196. if (ret < sizeof(tcs_part)) {
  197. DEBUG("Cannot read TCS data (%p) of enclave thread %d\n", tcs_addr, tid);
  198. return NULL;
  199. }
  200. DEBUG("[enclave thread %d] TCS at 0x%lx: TCS.ossa = 0x%lx TCS.cssa = %d\n", tid, (long)tcs_addr,
  201. tcs_part.ossa, tcs_part.cssa);
  202. assert(tcs_part.cssa > 0);
  203. return (void*)ei->base + tcs_part.ossa + ei->ssaframesize * tcs_part.cssa -
  204. sizeof(sgx_pal_gpr_t);
  205. }
  206. static int peek_gpr(int memdev, pid_t tid, struct enclave_dbginfo* ei, sgx_pal_gpr_t* gpr) {
  207. int ret;
  208. void* gpr_addr = get_gpr_addr(memdev, tid, ei);
  209. if (!gpr_addr)
  210. return -1;
  211. ret = pread(memdev, gpr, sizeof(sgx_pal_gpr_t), (off_t)gpr_addr);
  212. if (ret < sizeof(sgx_pal_gpr_t)) {
  213. DEBUG("Cannot read GPR data (%p) of enclave thread %d\n", gpr_addr, tid);
  214. return -1;
  215. }
  216. DEBUG("[enclave thread %d] Peek GPR: RIP 0x%08lx RBP 0x%08lx\n", tid, gpr->rip, gpr->rbp);
  217. return 0;
  218. }
  219. static int poke_gpr(int memdev, pid_t tid, struct enclave_dbginfo* ei, const sgx_pal_gpr_t* gpr) {
  220. int ret;
  221. void* gpr_addr = get_gpr_addr(memdev, tid, ei);
  222. if (!gpr_addr)
  223. return -1;
  224. ret = pwrite(memdev, gpr, sizeof(sgx_pal_gpr_t), (off_t)gpr_addr);
  225. if (ret < sizeof(sgx_pal_gpr_t)) {
  226. DEBUG("Cannot write GPR data (%p) of enclave thread %d\n", (void*)gpr_addr, tid);
  227. return -1;
  228. }
  229. DEBUG("[enclave thread %d] Poke GPR: RIP 0x%08lx RBP 0x%08lx\n", tid, gpr->rip, gpr->rbp);
  230. return 0;
  231. }
  232. static int peek_user(int memdev, pid_t tid, struct enclave_dbginfo* ei, struct user* ud) {
  233. int ret;
  234. sgx_pal_gpr_t gpr;
  235. ret = peek_gpr(memdev, tid, ei, &gpr);
  236. if (ret < 0)
  237. return ret;
  238. fill_regs(&ud->regs, &gpr);
  239. return 0;
  240. }
  241. static int poke_user(int memdev, pid_t tid, struct enclave_dbginfo* ei, const struct user* ud) {
  242. int ret;
  243. sgx_pal_gpr_t gpr;
  244. ret = peek_gpr(memdev, tid, ei, &gpr);
  245. if (ret < 0)
  246. return ret;
  247. fill_gpr(&gpr, &ud->regs);
  248. return poke_gpr(memdev, tid, ei, &gpr);
  249. }
  250. static int peek_regs(int memdev, pid_t tid, struct enclave_dbginfo* ei,
  251. struct user_regs_struct* regdata) {
  252. int ret;
  253. sgx_pal_gpr_t gpr;
  254. ret = peek_gpr(memdev, tid, ei, &gpr);
  255. if (ret < 0)
  256. return ret;
  257. fill_regs(regdata, &gpr);
  258. return 0;
  259. }
  260. static int poke_regs(int memdev, pid_t tid, struct enclave_dbginfo* ei,
  261. const struct user_regs_struct* regdata) {
  262. int ret;
  263. sgx_pal_gpr_t gpr;
  264. ret = peek_gpr(memdev, tid, ei, &gpr);
  265. if (ret < 0)
  266. return ret;
  267. fill_gpr(&gpr, regdata);
  268. return poke_gpr(memdev, tid, ei, &gpr);
  269. }
  270. /* Find corresponding memdevice of thread tid (open and populate on first
  271. * access). Return 0 on success, -1 on benign failure (enclave in not yet
  272. * initialized), -2 on other, severe failures.
  273. * */
  274. static int open_memdevice(pid_t tid, int* memdev, struct enclave_dbginfo** ei) {
  275. struct enclave_dbginfo eib = {.pid = -1};
  276. char memdev_path[40];
  277. uint64_t flags;
  278. long int ret;
  279. int fd;
  280. /* Check if corresponding memdevice of this thread was already opened;
  281. * this works when tid = pid (single-threaded apps) but does not work
  282. * for other threads of multi-threaded apps, this case covered below */
  283. for (int i = 0; i < memdevs_cnt; i++) {
  284. if (memdevs[i].pid == tid) {
  285. *memdev = memdevs[i].memdev;
  286. *ei = &memdevs[i].ei;
  287. return update_thread_tids(*ei);
  288. }
  289. }
  290. static_assert(sizeof(eib) % sizeof(long) == 0, "Unsupported eib size");
  291. for (int off = 0; off < sizeof(eib); off += sizeof(long)) {
  292. errno = 0;
  293. ret = host_ptrace(PTRACE_PEEKDATA, tid, (void*)DBGINFO_ADDR + off, NULL);
  294. if (ret < 0 && errno != 0) {
  295. /* benign failure: enclave is not yet initialized */
  296. return -1;
  297. }
  298. memcpy((void*)&eib + off, &ret, sizeof(ret));
  299. }
  300. /* Check again if corresponding memdevice was already opened but now
  301. * using actual pid of app (eib.pid), case for multi-threaded apps */
  302. for (int i = 0; i < memdevs_cnt; i++) {
  303. if (memdevs[i].pid == eib.pid) {
  304. *memdev = memdevs[i].memdev;
  305. *ei = &memdevs[i].ei;
  306. return update_thread_tids(*ei);
  307. }
  308. }
  309. DEBUG("Retrieved debug information (enclave reports PID %d)\n", eib.pid);
  310. if (memdevs_cnt == sizeof(memdevs) / sizeof(memdevs[0])) {
  311. DEBUG("Too many debugged processes (max = %d)\n", memdevs_cnt);
  312. return -2;
  313. }
  314. snprintf(memdev_path, sizeof(memdev_path), "/proc/%d/mem", tid);
  315. fd = open(memdev_path, O_RDWR);
  316. if (fd < 0) {
  317. DEBUG("Cannot open %s\n", memdev_path);
  318. return -2;
  319. }
  320. /* setting debug bit in TCS flags */
  321. for (int i = 0; i < MAX_DBG_THREADS; i++) {
  322. if (!eib.tcs_addrs[i])
  323. continue;
  324. void* flags_addr = eib.tcs_addrs[i] + offsetof(sgx_arch_tcs_t, flags);
  325. ret = pread(fd, &flags, sizeof(flags), (off_t)flags_addr);
  326. if (ret < sizeof(flags)) {
  327. DEBUG("Cannot read TCS flags (address = %p)\n", flags_addr);
  328. return -2;
  329. }
  330. if (flags & TCS_FLAGS_DBGOPTIN)
  331. continue;
  332. flags |= TCS_FLAGS_DBGOPTIN;
  333. DEBUG("Setting TCS debug flag at %p (%lx)\n", flags_addr, flags);
  334. ret = pwrite(fd, &flags, sizeof(flags), (off_t)flags_addr);
  335. if (ret < sizeof(flags)) {
  336. DEBUG("Cannot write TCS flags (address = %p)\n", flags_addr);
  337. return -2;
  338. }
  339. }
  340. memdevs[memdevs_cnt].pid = eib.pid;
  341. memdevs[memdevs_cnt].memdev = fd;
  342. memdevs[memdevs_cnt].ei = eib;
  343. memdevs[memdevs_cnt].ei.thread_stepping = 0;
  344. *memdev = fd;
  345. *ei = &memdevs[memdevs_cnt].ei;
  346. memdevs_cnt++;
  347. return 0;
  348. }
  349. static int is_in_enclave(pid_t tid, struct enclave_dbginfo* ei) {
  350. struct user_regs_struct regs;
  351. int ret = host_ptrace(PTRACE_GETREGS, tid, NULL, &regs);
  352. if (ret < 0) {
  353. DEBUG("Failed getting registers: TID %d\n", tid);
  354. return -1;
  355. }
  356. DEBUG("%d: User RIP 0x%08llx%s\n", tid, regs.rip,
  357. ((void*)regs.rip == ei->aep) ? " (in enclave)" : "");
  358. return ((void*)regs.rip == ei->aep) ? 1 : 0;
  359. }
  360. long int ptrace(enum __ptrace_request request, ...) {
  361. long int ret = 0, res;
  362. va_list ap;
  363. pid_t tid;
  364. void* addr;
  365. void* data;
  366. int memdev;
  367. bool in_enclave;
  368. struct enclave_dbginfo* ei;
  369. struct user userdata;
  370. va_start(ap, request);
  371. tid = va_arg(ap, pid_t);
  372. addr = va_arg(ap, void*);
  373. data = va_arg(ap, void*);
  374. va_end(ap);
  375. DEBUG("[GDB %d] Intercepted ptrace(%s, %d, %p, %p)\n", getpid(), str_ptrace_request(request),
  376. tid, addr, data);
  377. ret = open_memdevice(tid, &memdev, &ei);
  378. if (ret < 0) {
  379. if (ret == -1) {
  380. /* benign failure: enclave is not yet initialized */
  381. return host_ptrace(request, tid, addr, data);
  382. }
  383. errno = EFAULT;
  384. return -1;
  385. }
  386. ret = is_in_enclave(tid, ei);
  387. if (ret < 0) {
  388. errno = EFAULT;
  389. return -1;
  390. }
  391. in_enclave = (ret != 0);
  392. switch (request) {
  393. case PTRACE_PEEKTEXT:
  394. case PTRACE_PEEKDATA: {
  395. if ((addr + sizeof(long)) <= (void*)ei->base || addr >= (void*)(ei->base + ei->size)) {
  396. /* peek into strictly non-enclave memory */
  397. return host_ptrace(PTRACE_PEEKDATA, tid, addr, NULL);
  398. }
  399. ret = pread(memdev, &res, sizeof(long), (unsigned long)addr);
  400. if (ret < 0) {
  401. /* In some cases, GDB wants to read td_thrinfo_t object from
  402. * in-LibOS Glibc. If host OS's Glibc and in-LibOS Glibc
  403. * versions do not match, GDB's supplied addr is incorrect
  404. * and leads to EIO failure of pread(). Circumvent this
  405. * issue by returning a dummy 0. NOTE: this doesn't lead to
  406. * noticeable debugging issues, at least on Ubuntu 16.04. */
  407. if (errno == EIO) {
  408. errno = 0;
  409. return 0;
  410. }
  411. errno = EFAULT;
  412. return -1;
  413. }
  414. return res;
  415. }
  416. case PTRACE_POKETEXT:
  417. case PTRACE_POKEDATA: {
  418. if ((addr + sizeof(long)) <= (void*)ei->base || addr >= (void*)(ei->base + ei->size)) {
  419. /* poke strictly non-enclave memory */
  420. return host_ptrace(PTRACE_POKEDATA, tid, addr, data);
  421. }
  422. ret = pwrite(memdev, &data, sizeof(long), (off_t)addr);
  423. if (ret < 0) {
  424. errno = EFAULT;
  425. return -1;
  426. }
  427. return 0;
  428. }
  429. case PTRACE_PEEKUSER: {
  430. if ((off_t)addr >= sizeof(struct user)) {
  431. errno = EINVAL;
  432. return -1;
  433. }
  434. if (!in_enclave)
  435. return host_ptrace(PTRACE_PEEKUSER, tid, addr, data);
  436. if ((off_t)addr >= sizeof(struct user_regs_struct))
  437. return host_ptrace(PTRACE_PEEKUSER, tid, addr, NULL);
  438. ret = peek_user(memdev, tid, ei, &userdata);
  439. if (ret < 0) {
  440. errno = EFAULT;
  441. return -1;
  442. }
  443. return *(long int*)((void*)&userdata + (off_t)addr);
  444. }
  445. case PTRACE_POKEUSER: {
  446. if ((off_t)addr >= sizeof(struct user)) {
  447. errno = EINVAL;
  448. return -1;
  449. }
  450. if (!in_enclave || (off_t)addr >= sizeof(struct user_regs_struct))
  451. return host_ptrace(PTRACE_POKEUSER, tid, addr, data);
  452. ret = peek_user(memdev, tid, ei, &userdata);
  453. if (ret < 0) {
  454. errno = EFAULT;
  455. return -1;
  456. }
  457. *(long int*)((void*)&userdata + (off_t)addr) = (long int)data;
  458. ret = poke_user(memdev, tid, ei, &userdata);
  459. if (ret < 0) {
  460. errno = EFAULT;
  461. return -1;
  462. }
  463. return 0;
  464. }
  465. case PTRACE_GETREGS: {
  466. if (!in_enclave)
  467. return host_ptrace(PTRACE_GETREGS, tid, addr, data);
  468. ret = peek_regs(memdev, tid, ei, (struct user_regs_struct*)data);
  469. if (ret < 0) {
  470. errno = EFAULT;
  471. return -1;
  472. }
  473. return 0;
  474. }
  475. case PTRACE_SETREGS: {
  476. if (!in_enclave)
  477. return host_ptrace(PTRACE_SETREGS, tid, addr, data);
  478. ret = poke_regs(memdev, tid, ei, (struct user_regs_struct*)data);
  479. if (ret < 0) {
  480. errno = EFAULT;
  481. return -1;
  482. }
  483. return 0;
  484. }
  485. case PTRACE_SINGLESTEP: {
  486. if (!in_enclave)
  487. return host_ptrace(PTRACE_SINGLESTEP, tid, addr, data);
  488. for (int i = 0; i < MAX_DBG_THREADS; i++) {
  489. if (ei->thread_tids[i] == tid) {
  490. ei->thread_stepping |= 1ULL << i;
  491. return host_ptrace(PTRACE_SINGLESTEP, tid, addr, data);
  492. }
  493. }
  494. DEBUG("Cannot find enclave thread %d to single-step\n", tid);
  495. errno = EFAULT;
  496. return -1;
  497. }
  498. default:
  499. return host_ptrace(request, tid, addr, data);
  500. }
  501. /* should not reach here */
  502. return 0;
  503. }
  504. pid_t waitpid(pid_t tid, int* status, int options) {
  505. int ret;
  506. int memdev;
  507. pid_t wait_res;
  508. struct enclave_dbginfo* ei;
  509. sgx_pal_gpr_t gpr;
  510. uint8_t code;
  511. int wait_errno;
  512. DEBUG("[GDB %d] Intercepted waitpid(%d)\n", getpid(), tid);
  513. errno = 0;
  514. wait_res = syscall((long int)SYS_wait4, (long int)tid, (long int)status, (long int)options,
  515. (long int)NULL);
  516. wait_errno = errno;
  517. DEBUG("[GDB %d] Executed host waitpid(%d, <status>, %d) = %d\n", getpid(), tid, options,
  518. wait_res);
  519. if (wait_res < 0) {
  520. errno = wait_errno;
  521. return -1;
  522. }
  523. if (!status) {
  524. return wait_res;
  525. }
  526. if (WIFSTOPPED(*status) && WSTOPSIG(*status) == SIGTRAP) {
  527. tid = wait_res;
  528. ret = open_memdevice(tid, &memdev, &ei);
  529. if (ret < 0) {
  530. if (ret == -1) {
  531. errno = 0; /* benign failure: enclave is not yet initialized */
  532. return wait_res;
  533. }
  534. errno = ECHILD;
  535. return -1;
  536. }
  537. /* for singlestepping case, unset enclave thread's stepping bit */
  538. for (int i = 0; i < MAX_DBG_THREADS; i++) {
  539. if (ei->thread_tids[i] == tid) {
  540. if (ei->thread_stepping & (1ULL << i)) {
  541. ei->thread_stepping &= ~(1ULL << i);
  542. return wait_res;
  543. }
  544. break;
  545. }
  546. }
  547. ret = is_in_enclave(tid, ei);
  548. if (ret < 0) {
  549. errno = ECHILD;
  550. return -1;
  551. }
  552. if (!ret)
  553. return wait_res;
  554. /* target thread is inside the enclave */
  555. ret = peek_gpr(memdev, tid, ei, &gpr);
  556. if (ret < 0) {
  557. errno = ECHILD;
  558. return -1;
  559. }
  560. ret = pread(memdev, &code, sizeof(code), (off_t)gpr.rip);
  561. if (ret < sizeof(code)) {
  562. DEBUG("Cannot read RIP of enclave thread %d\n", tid);
  563. errno = ECHILD;
  564. return -1;
  565. }
  566. if (code != 0xcc)
  567. return wait_res;
  568. DEBUG("RIP 0x%lx points to a breakpoint\n", gpr.rip);
  569. /* This is a quirk of SGX hardware implementation. GDB expects that
  570. * RIP points to one byte *after* INT3 (which GDB put in place of
  571. * original instruction to induce breakpoint trap). But under SGX,
  572. * breakpoint is trapped such that RIP points *to* INT3. Thus, we
  573. * need to adjust RIP according to GDB's expectation.*/
  574. gpr.rip++;
  575. ret = poke_gpr(memdev, tid, ei, &gpr);
  576. if (ret < 0) {
  577. errno = ECHILD;
  578. return -1;
  579. }
  580. }
  581. return wait_res;
  582. }