mdbg.c 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884
  1. /*
  2. * Copyright (C)2005-2020 Haxe Foundation
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a
  5. * copy of this software and associated documentation files (the "Software"),
  6. * to deal in the Software without restriction, including without limitation
  7. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8. * and/or sell copies of the Software, and to permit persons to whom the
  9. * Software is furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice shall be included in
  12. * all copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  20. * DEALINGS IN THE SOFTWARE.
  21. */
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <stdbool.h>
  25. #include <unistd.h>
  26. #include <time.h>
  27. #include <signal.h>
  28. #include <semaphore.h>
  29. #include <errno.h>
  30. #include <assert.h>
  31. #include <sys/types.h>
  32. #include <sys/user.h>
  33. #include <sys/ptrace.h>
  34. #include <sys/event.h>
  35. #include <sys/sysctl.h>
  36. #include <mach/mach.h>
  37. #include <mach/mach_types.h>
  38. #include <mach/mach_vm.h>
  39. #include <mach/vm_prot.h>
  40. #include <mach/exception_types.h>
  41. #include <mdbg/mach_exc.h>
  42. #include "mdbg.h"
  43. #pragma mark Defines
  44. #define STATUS_TIMEOUT -1
  45. #define STATUS_EXIT 0
  46. #define STATUS_BREAKPOINT 1
  47. #define STATUS_SINGLESTEP 2
  48. #define STATUS_ERROR 3
  49. #define STATUS_HANDLED 4
  50. #define STATUS_STACKOVERFLOW 5
  51. #define STATUS_WATCHBREAK 0x100
  52. #define SINGLESTEP_TRAP 0x00000100
  53. #define MAX_EXCEPTION_PORTS 16
  54. /* Forward declarations */
  55. boolean_t mach_exc_server(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP);
  56. static struct debug_session *find_session(mach_port_t task);
  57. static mach_port_t get_task(pid_t pid);
  58. static mach_port_t get_thread(mach_port_t mach_task, uint thread_num);
  59. static uint64_t get_thread_id(thread_t thread);
  60. static x86_thread_state64_t* get_thread_state(mach_port_t mach_thread);
  61. static kern_return_t set_thread_state(thread_t mach_thread, x86_thread_state64_t *break_state);
  62. static x86_debug_state64_t* get_debug_state(thread_t mach_thread);
  63. static kern_return_t set_debug_state(thread_t mach_thread, x86_debug_state64_t *break_state);
  64. static void* task_exception_server (mach_port_t exception_port);
  65. #pragma mark Structs
  66. typedef struct {
  67. debug_session **list;
  68. unsigned int count;
  69. } pointer_list;
  70. pointer_list sessions;
  71. typedef struct {
  72. mach_msg_type_number_t count;
  73. exception_mask_t masks[MAX_EXCEPTION_PORTS];
  74. exception_handler_t ports[MAX_EXCEPTION_PORTS];
  75. exception_behavior_t behaviors[MAX_EXCEPTION_PORTS];
  76. thread_state_flavor_t flavors[MAX_EXCEPTION_PORTS];
  77. } exception_ports_info;
  78. #pragma mark Helpers
  79. static void* safe_malloc(size_t x) {
  80. void *mal = malloc(x);
  81. if(mal == NULL) {
  82. fprintf(stderr, "[-safe_malloc] Error Exiting\n");
  83. exit(-1);
  84. }
  85. memset(mal, 0, x);
  86. return mal;
  87. }
  88. #pragma mark Debug
  89. #if MDBG_DEBUG
  90. # define DEBUG_PRINT(fmt,...) \
  91. do { fprintf(stdout, "%s[%d] %s(): " fmt "\n",__FILE__, __LINE__, __func__, ##__VA_ARGS__); } while (0);
  92. # if MDBG_LOG_LEVEL > 0
  93. # define DEBUG_PRINT_VERBOSE(fmt,...) \
  94. do { fprintf(stdout, "%s[%d] %s(): " fmt "\n",__FILE__, __LINE__, __func__, ##__VA_ARGS__); } while (0);
  95. # else
  96. # define DEBUG_PRINT_VERBOSE(fmt,...)
  97. #endif
  98. #else
  99. # define DEBUG_PRINT(fmt,...)
  100. # define DEBUG_PRINT_VERBOSE(fmt,...)
  101. #endif
  102. #define RETURN_ON_MACH_ERROR(code,msg,...) \
  103. if (code != KERN_SUCCESS) {\
  104. DEBUG_PRINT(msg,##__VA_ARGS__);\
  105. return code;\
  106. }
  107. #define EXIT_ON_MACH_ERROR(code,msg,...) \
  108. if (code != KERN_SUCCESS) {\
  109. DEBUG_PRINT(msg,##__VA_ARGS__);\
  110. exit(0);\
  111. }
  112. #if MDBG_DEBUG
  113. static void log_buffer(unsigned char *buf, int size) {
  114. for (int i=0; i<size; i++) {
  115. printf("%02lx\t", (unsigned long)buf[i]);
  116. if ((i+1)%16 == 0) printf("\n");
  117. }
  118. }
  119. static char* get_signal_name(int sig) {
  120. switch(sig) {
  121. case 1: return "SIGHUP";
  122. case 2: return "SIGINT";
  123. case 3: return "SIGQUIT";
  124. case 4: return "SIGILL";
  125. case 5: return "SIGTRAP";
  126. case 6: return "SIGABRT";
  127. case 7: return "SIGEMT";
  128. case 8: return "SIGFPE";
  129. case 9: return "SIGKILL";
  130. case 10: return "SIGBUS";
  131. case 11: return "SIGSEGV";
  132. case 12: return "SIGSYS";
  133. case 13: return "SIGPIPE";
  134. case 14: return "SIGALRM";
  135. case 15: return "SIGTERM";
  136. case 16: return "SIGURG";
  137. case 17: return "SIGSTOP";
  138. case 18: return "SIGTSTP";
  139. case 19: return "SIGCONT";
  140. case 20: return "SIGCHLD";
  141. case 21: return "SIGTTIN";
  142. case 22: return "SIGTTOU";
  143. case 23: return "SIGIO";
  144. case 24: return "SIGXCPU";
  145. case 25: return "SIGXFSZ";
  146. case 26: return "SIGVTALRM";
  147. case 27: return "SIGPROF";
  148. case 28: return "SIGWINCH";
  149. case 29: return "SIGINFO";
  150. case 30: return "SIGUSR1";
  151. case 31: return "SIGUSR2";
  152. default: return "UNKNOWN";
  153. }
  154. }
  155. static char* exception_to_string(exception_type_t exc) {
  156. switch(exc) {
  157. case EXC_BREAKPOINT : return "EXC_BREAKPOINT";
  158. case EXC_BAD_ACCESS : return "EXC_BAD_ACCESS";
  159. case EXC_BAD_INSTRUCTION: return "EXC_BAD_INSTRUCTION";
  160. case EXC_ARITHMETIC : return "EXC_ARITHMETIC";
  161. case EXC_EMULATION : return "EXC_EMULATION";
  162. case EXC_SOFTWARE : return "EXC_SOFTWARE";
  163. case EXC_SYSCALL : return "EXC_SYSCALL";
  164. case EXC_MACH_SYSCALL : return "EXC_MACH_SYSCALL";
  165. case EXC_RPC_ALERT : return "EXC_RPC_ALERT";
  166. case EXC_CRASH : return "EXC_CRASH";
  167. case EXC_RESOURCE : return "EXC_RESOURCE";
  168. case EXC_GUARD : return "EXC_GUARD";
  169. case NOTE_EXEC : return "EXEC";
  170. case NOTE_FORK : return "FORK";
  171. case NOTE_SIGNAL : return "SIGNAL";
  172. case NOTE_EXIT : return "EXIT";
  173. default:
  174. return "[-exception_to_string] unknown exception type!";
  175. }
  176. }
  177. static char* get_register_name(int reg) {
  178. switch(reg) {
  179. case REG_RAX: return "Rax";
  180. case REG_RBX: return "Rbx";
  181. case REG_RCX: return "Rcx";
  182. case REG_RDX: return "Rdx";
  183. case REG_RDI: return "Rdi";
  184. case REG_RSI: return "Rsi";
  185. case REG_RBP: return "Rbp";
  186. case REG_RSP: return "Rsp";
  187. case REG_R8: return "R8";
  188. case REG_R9: return "R9";
  189. case REG_R10: return "R10";
  190. case REG_R11: return "R11";
  191. case REG_R12: return "R12";
  192. case REG_R13: return "R13";
  193. case REG_R14: return "R14";
  194. case REG_R15: return "R15";
  195. case REG_RIP: return "Rip";
  196. case REG_RFLAGS: return "Rflags";
  197. case REG_DR0: return "Dr0";
  198. case REG_DR1: return "Dr1";
  199. case REG_DR2: return "Dr2";
  200. case REG_DR3: return "Dr3";
  201. case REG_DR4: return "Dr4";
  202. case REG_DR5: return "Dr5";
  203. case REG_DR6: return "Dr6";
  204. case REG_DR7: return "Dr7";
  205. default: return "invalid register";
  206. }
  207. }
  208. #endif
  209. #pragma mark Debug helpers
  210. // From: https://developer.apple.com/library/archive/qa/qa1361/_index.html
  211. // Returns true if the current process is being debugged (either
  212. // running under the debugger or has a debugger attached post facto).
  213. bool is_debugger_attached(void) {
  214. int junk;
  215. int mib[4];
  216. struct kinfo_proc info;
  217. size_t size;
  218. info.kp_proc.p_flag = 0;
  219. mib[0] = CTL_KERN;
  220. mib[1] = KERN_PROC;
  221. mib[2] = KERN_PROC_PID;
  222. mib[3] = getpid();
  223. size = sizeof(info);
  224. junk = sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0);
  225. assert(junk == 0);
  226. // We're being debugged if the P_TRACED flag is set.
  227. return ( (info.kp_proc.p_flag & P_TRACED) != 0 );
  228. }
  229. #pragma mark Debug sessions
  230. static debug_session *create_debug_session(mach_port_t task, pid_t pid) {
  231. debug_session *exists = find_session(task);
  232. if(exists != NULL) {
  233. return exists;
  234. }
  235. debug_session *sess = malloc(sizeof(debug_session));
  236. memset(sess, 0, sizeof(debug_session));
  237. sess->task = task;
  238. sess->pid = pid;
  239. sess->exception_port = 0;
  240. sess->old_exception_ports = (struct exception_ports_info*)malloc(sizeof(exception_ports_info));
  241. sess->process_status = STATUS_HANDLED;
  242. // create a semaphore `wait_sem` to handle signaling between exception port thread and main thread
  243. kern_return_t kret = semaphore_create(task, &sess->wait_sem, 0, 0);
  244. EXIT_ON_MACH_ERROR(kret, "Fatal error: failed to create semaphore!");
  245. // add `debug_session` to `sessions` list for future lookup
  246. sessions.list = realloc(sessions.list, sizeof(debug_session*) * (sessions.count + 1));
  247. sessions.list[sessions.count++] = sess;
  248. DEBUG_PRINT("created session num: %i", sessions.count);
  249. return sess;
  250. }
  251. static bool destroy_debug_session(debug_session *sess) {
  252. semaphore_destroy(sess->task, sess->wait_sem);
  253. free(sess);
  254. if(sessions.count > 1) {
  255. debug_session **new_list = malloc(sizeof(debug_session*) * (sessions.count-1));
  256. int j = 0;
  257. for(int i = 0; i < sessions.count; i++) {
  258. if(sessions.list[i] != sess) {
  259. new_list[j++] = sessions.list[i];
  260. }
  261. }
  262. free(sessions.list);
  263. sessions.list = new_list;
  264. } else {
  265. free(sessions.list);
  266. sessions.list = NULL;
  267. }
  268. sessions.count--;
  269. return true;
  270. }
  271. static debug_session *find_session(mach_port_t task) {
  272. int i = 0;
  273. while(i < sessions.count) {
  274. if(sessions.list[i]->task == task) {
  275. return sessions.list[i];
  276. }
  277. i++;
  278. }
  279. return NULL;
  280. }
  281. static debug_session *find_session_by_pid(pid_t pid) {
  282. int i = 0;
  283. while(i < sessions.count) {
  284. if(sessions.list[i]->pid == pid) {
  285. return sessions.list[i];
  286. }
  287. i++;
  288. }
  289. return NULL;
  290. }
  291. #pragma mark Registers
  292. __uint64_t *get_reg( x86_thread_state64_t *regs, int r ) {
  293. switch( r ) {
  294. case REG_RAX: return &regs->__rax;
  295. case REG_RBX: return &regs->__rbx;
  296. case REG_RCX: return &regs->__rcx;
  297. case REG_RDX: return &regs->__rdx;
  298. case REG_RDI: return &regs->__rdi;
  299. case REG_RSI: return &regs->__rsi;
  300. case REG_RBP: return &regs->__rbp;
  301. case REG_RSP: return &regs->__rsp;
  302. case REG_R8: return &regs->__r8;
  303. case REG_R9: return &regs->__r9;
  304. case REG_R10: return &regs->__r10;
  305. case REG_R11: return &regs->__r11;
  306. case REG_R12: return &regs->__r12;
  307. case REG_R13: return &regs->__r13;
  308. case REG_R14: return &regs->__r14;
  309. case REG_R15: return &regs->__r15;
  310. case REG_RIP: return &regs->__rip;
  311. case REG_RFLAGS: return &regs->__rflags;
  312. }
  313. return NULL;
  314. }
  315. __uint64_t *get_debug_reg( x86_debug_state64_t *regs, int r ) {
  316. switch( r ) {
  317. case REG_DR0: return &regs->__dr0;
  318. case REG_DR1: return &regs->__dr1;
  319. case REG_DR2: return &regs->__dr2;
  320. case REG_DR3: return &regs->__dr3;
  321. case REG_DR4: return &regs->__dr4;
  322. case REG_DR5: return &regs->__dr5;
  323. case REG_DR6: return &regs->__dr6;
  324. case REG_DR7: return &regs->__dr7;
  325. }
  326. return NULL;
  327. }
  328. __uint64_t read_register(mach_port_t task, int thread, int reg, bool is64 ) {
  329. __uint64_t *rdata;
  330. mach_port_t mach_thread = get_thread(task, thread);
  331. if(reg >= REG_DR0) {
  332. x86_debug_state64_t *regs = get_debug_state(mach_thread);
  333. rdata = get_debug_reg(regs, reg - 4);
  334. } else {
  335. x86_thread_state64_t *regs = get_thread_state(mach_thread);
  336. rdata = get_reg(regs, reg);
  337. }
  338. DEBUG_PRINT_VERBOSE("register %s is: 0x%08x\n", get_register_name(reg), *rdata);
  339. return *rdata;
  340. }
  341. static kern_return_t write_register(mach_port_t task, int thread, int reg, void *value, bool is64 ) {
  342. DEBUG_PRINT_VERBOSE("write register %i (%s) on thread %i", reg, get_register_name(reg), thread);
  343. __uint64_t *rdata;
  344. mach_port_t mach_thread = get_thread(task, thread);
  345. if(reg >= REG_DR0) {
  346. x86_debug_state64_t *regs = get_debug_state(mach_thread);
  347. rdata = get_debug_reg(regs, reg - 4);
  348. DEBUG_PRINT_VERBOSE("register flag for %s was: 0x%08x\n",get_register_name(reg), *rdata);
  349. *rdata = (__uint64_t)value;
  350. set_debug_state(mach_thread, regs);
  351. } else {
  352. x86_thread_state64_t *regs = get_thread_state(mach_thread);
  353. rdata = get_reg(regs, reg);
  354. DEBUG_PRINT_VERBOSE("register flag for %s was: 0x%08x\n",get_register_name(reg), *rdata);
  355. *rdata = (__uint64_t)value;
  356. set_thread_state(mach_thread, regs);
  357. }
  358. DEBUG_PRINT_VERBOSE("register flag for %s now is: 0x%08x\n",get_register_name(reg), *rdata);
  359. return KERN_SUCCESS;
  360. }
  361. #pragma mark Memory IO
  362. static kern_return_t read_memory(mach_port_t task, mach_vm_address_t addr, mach_vm_address_t dest, int size) {
  363. mach_vm_size_t nread;
  364. kern_return_t kret = mach_vm_read_overwrite(task, addr, size, dest, &nread);
  365. EXIT_ON_MACH_ERROR(kret,"Error: probably reading from invalid address!");
  366. DEBUG_PRINT_VERBOSE("read %i bytes from %p", nread, addr);
  367. #if MDBG_DEBUG && MDBG_LOG_LEVEL > 1
  368. log_buffer(dest, size);
  369. printf("\n\n");
  370. #endif
  371. return kret;
  372. }
  373. static kern_return_t write_memory(mach_port_t task, mach_vm_address_t addr, mach_vm_address_t src, int size) {
  374. kern_return_t kret = mach_vm_protect(task, addr, size, 0, VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE);
  375. EXIT_ON_MACH_ERROR(kret,"Fatal error: failed to acquire write permission!");
  376. kret = mach_vm_write(task, addr, src, size);
  377. EXIT_ON_MACH_ERROR(kret,"Fatal error: failed to write to traced process memory!");
  378. kret = mach_vm_protect(task, addr, size, 0, VM_PROT_READ | VM_PROT_EXECUTE);
  379. EXIT_ON_MACH_ERROR(kret,"Fatal error: failed to reset write permission!");
  380. DEBUG_PRINT_VERBOSE("wrote %i bytes to %p",size, addr);
  381. #if MDBG_DEBUG && MDBG_LOG_LEVEL
  382. log_buffer(src, size);
  383. printf("\n\n");
  384. #endif
  385. return kret;
  386. }
  387. #pragma mark Threads
  388. static thread_act_port_array_t get_task_threads(mach_port_t mach_task, mach_msg_type_number_t *threadCount) {
  389. thread_act_port_array_t threadList;
  390. task_threads(mach_task, &threadList, threadCount);
  391. return threadList;
  392. }
  393. static mach_port_t get_thread(mach_port_t mach_task, uint thread_id) {
  394. thread_act_port_array_t threadList;
  395. mach_msg_type_number_t threadCount;
  396. kern_return_t kret = task_threads(mach_task, &threadList, &threadCount);
  397. if (kret != KERN_SUCCESS) {
  398. DEBUG_PRINT("get_thread() failed with message %s!\n", mach_error_string(kret));
  399. exit(0);
  400. }
  401. for(int i=0;i<threadCount;i++) {
  402. if(get_thread_id(threadList[i]) == thread_id) {
  403. return threadList[i];
  404. }
  405. }
  406. exit(0); // TODO: catch better
  407. }
  408. static thread_identifier_info_data_t* get_thread_info(thread_t thread) {
  409. thread_identifier_info_data_t *tident = safe_malloc(sizeof(thread_identifier_info_data_t));
  410. mach_msg_type_number_t tident_count = THREAD_IDENTIFIER_INFO_COUNT;
  411. kern_return_t kret = thread_info (thread, THREAD_IDENTIFIER_INFO, (thread_info_t)tident, &tident_count);
  412. EXIT_ON_MACH_ERROR(kret, "failed to get thread info");
  413. return tident;
  414. }
  415. static uint64_t get_thread_id(thread_t thread) {
  416. thread_identifier_info_data_t *tinfo = get_thread_info(thread);
  417. return tinfo->thread_id;
  418. }
  419. static x86_thread_state64_t* get_thread_state(thread_t mach_thread) {
  420. x86_thread_state64_t* state;
  421. mach_msg_type_number_t stateCount = x86_THREAD_STATE64_COUNT;
  422. state = safe_malloc(sizeof(x86_thread_state64_t));
  423. kern_return_t kret = thread_get_state( mach_thread, x86_THREAD_STATE64, (thread_state_t)state, &stateCount);
  424. if (kret != KERN_SUCCESS) {
  425. DEBUG_PRINT("Error failed with message %s!\n", mach_error_string(kret));
  426. exit(0);
  427. }
  428. return state;
  429. }
  430. static kern_return_t set_thread_state(thread_t mach_thread, x86_thread_state64_t *break_state) {
  431. kern_return_t kret = thread_set_state(mach_thread, x86_THREAD_STATE64, (thread_state_t)break_state, x86_THREAD_STATE64_COUNT);
  432. if (kret != KERN_SUCCESS) {
  433. DEBUG_PRINT("Error failed with message %s!\n", mach_error_string(kret));
  434. exit(0);
  435. }
  436. return kret;
  437. }
  438. // Debug register state
  439. static x86_debug_state64_t* get_debug_state(thread_t mach_thread) {
  440. x86_debug_state64_t* state;
  441. mach_msg_type_number_t stateCount = x86_DEBUG_STATE64_COUNT;
  442. state = safe_malloc(sizeof(x86_debug_state64_t));
  443. kern_return_t kret = thread_get_state( mach_thread, x86_DEBUG_STATE64, (thread_state_t)state, &stateCount);
  444. if (kret != KERN_SUCCESS) {
  445. DEBUG_PRINT("Error failed with message %s!\n", mach_error_string(kret));
  446. exit(0);
  447. }
  448. return state;
  449. }
  450. static kern_return_t set_debug_state(thread_t mach_thread, x86_debug_state64_t *break_state) {
  451. kern_return_t kret = thread_set_state(mach_thread, x86_DEBUG_STATE64, (thread_state_t)break_state, x86_DEBUG_STATE64_COUNT);
  452. if (kret != KERN_SUCCESS) {
  453. DEBUG_PRINT("Error failed with message %s!\n", mach_error_string(kret));
  454. exit(0);
  455. }
  456. return kret;
  457. }
  458. #pragma mark Exception ports
  459. static kern_return_t save_exception_ports(task_t task, exception_ports_info *info) {
  460. info->count = (sizeof (info->ports) / sizeof (info->ports[0]));
  461. return task_get_exception_ports(task, EXC_MASK_ALL, info->masks, &info->count, info->ports, info->behaviors, info->flavors);
  462. }
  463. static kern_return_t restore_exception_ports(task_t task, exception_ports_info *info) {
  464. int i;
  465. kern_return_t kret;
  466. for (i = 0; i < info->count; i++) {
  467. kret = task_set_exception_ports(task, info->masks[i], info->ports[i], info->behaviors[i], info->flavors[i]);
  468. if (kret != KERN_SUCCESS)
  469. return kret;
  470. }
  471. return KERN_SUCCESS;
  472. }
  473. #pragma mark Tasks
  474. static mach_port_t get_task(pid_t pid) {
  475. debug_session *sess = find_session_by_pid(pid);
  476. if(sess != NULL) {
  477. return sess->task;
  478. }
  479. mach_port_t task;
  480. kern_return_t kret = task_for_pid(mach_task_self(), pid, &task);
  481. EXIT_ON_MACH_ERROR(kret,"Fatal error: failed to get task for pid %i",pid);
  482. return task;
  483. }
  484. static kern_return_t attach_to_task(mach_port_t task, pid_t pid) {
  485. if(find_session(task) != NULL) {
  486. DEBUG_PRINT("Warning already attached to task (%i). Not attaching again!",task);
  487. return KERN_SUCCESS;
  488. }
  489. debug_session *sess = create_debug_session(task, pid);
  490. kern_return_t kret;
  491. int err;
  492. kret = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &sess->exception_port);
  493. RETURN_ON_MACH_ERROR(kret,"mach_port_allocate failed");
  494. kret = mach_port_insert_right(mach_task_self(), sess->exception_port, sess->exception_port, MACH_MSG_TYPE_MAKE_SEND);
  495. RETURN_ON_MACH_ERROR(kret,"mach_port_insert_right failed");
  496. // store current exception ports
  497. save_exception_ports(task, (exception_ports_info*)sess->old_exception_ports);
  498. kret = task_set_exception_ports(task, EXC_MASK_ALL, sess->exception_port, EXCEPTION_STATE_IDENTITY|MACH_EXCEPTION_CODES, x86_THREAD_STATE64);
  499. RETURN_ON_MACH_ERROR(kret,"task_set_exception_ports failed");
  500. // launch mach exception port thread //
  501. err = pthread_create(&sess->exception_handler_thread, NULL, (void *(*)(void*))task_exception_server, (void *(*)(void*))(unsigned long long)sess->exception_port);
  502. EXIT_ON_MACH_ERROR(err,"can't create *task_exception_server* thread :[%s]",strerror(err));
  503. DEBUG_PRINT("successfully created mach exception port thread %d\n", 0);
  504. return KERN_SUCCESS;
  505. }
  506. static kern_return_t attach_to_pid(pid_t pid) {
  507. attach_to_task(get_task(pid), pid);
  508. return ptrace(PT_ATTACHEXC, pid, 0, 0) == 0 ? KERN_SUCCESS : KERN_FAILURE;
  509. }
  510. static kern_return_t detach_from_pid(pid_t pid) {
  511. debug_session *sess = find_session_by_pid( pid );
  512. if(sess != NULL) {
  513. DEBUG_PRINT("cleaning up debug session...");
  514. restore_exception_ports(sess->task, (exception_ports_info*)sess->old_exception_ports);
  515. ptrace(PT_DETACH, pid, 0, 0);
  516. destroy_debug_session(sess);
  517. DEBUG_PRINT("successfully ended session!");
  518. } else {
  519. DEBUG_PRINT("found no session to cleanup!");
  520. }
  521. return KERN_SUCCESS;
  522. }
  523. #pragma mark Exceptions
  524. extern kern_return_t catch_mach_exception_raise /* stub – will not be called */
  525. (
  526. mach_port_t exception_port,
  527. mach_port_t thread,
  528. mach_port_t task,
  529. exception_type_t exception,
  530. mach_exception_data_t code,
  531. mach_msg_type_number_t codeCnt
  532. ) {
  533. DEBUG_PRINT("this handler should not be called");
  534. return MACH_RCV_INVALID_TYPE;
  535. }
  536. extern kern_return_t catch_mach_exception_raise_state /* stub – will not be called */
  537. (
  538. mach_port_t exception_port,
  539. exception_type_t exception,
  540. const mach_exception_data_t code,
  541. mach_msg_type_number_t codeCnt,
  542. int *flavor,
  543. const thread_state_t old_state,
  544. mach_msg_type_number_t old_stateCnt,
  545. thread_state_t new_state,
  546. mach_msg_type_number_t *new_stateCnt
  547. ) {
  548. DEBUG_PRINT("this handler should not be called");
  549. return MACH_RCV_INVALID_TYPE;
  550. }
  551. extern kern_return_t catch_mach_exception_raise_state_identity(
  552. mach_port_t exception_port,
  553. mach_port_t thread,
  554. mach_port_t task,
  555. exception_type_t exception,
  556. exception_data_t code,
  557. mach_msg_type_number_t codeCnt,
  558. int * flavor,
  559. thread_state_t old_state,
  560. mach_msg_type_number_t old_stateCnt,
  561. thread_state_t new_state,
  562. mach_msg_type_number_t *new_stateCnt
  563. ) {
  564. x86_thread_state64_t *state = (x86_thread_state64_t *) old_state;
  565. x86_thread_state64_t *newState = (x86_thread_state64_t *) new_state;
  566. debug_session *sess = find_session(task);
  567. sess->current_thread = get_thread_id(thread); /* set system-wide thread id */
  568. DEBUG_PRINT("exception occured on thread (%i): %s",sess->current_thread, exception_to_string(exception));
  569. DEBUG_PRINT("stack address: 0x%02lx", state->__rip);
  570. if (exception == EXC_SOFTWARE && code[0] == EXC_SOFT_SIGNAL) { // handling UNIX soft signal
  571. int subcode = code[2];
  572. DEBUG_PRINT("EXC_SOFTWARE signal: %s",get_signal_name(code[2]));
  573. if (subcode == SIGSTOP || subcode == SIGTRAP) {
  574. // clear signal to prevent default OS handling //
  575. ptrace(PT_THUPDATE,
  576. sess->pid,
  577. (caddr_t)(uintptr_t)thread,
  578. 0);
  579. task_suspend(sess->task);
  580. sess->process_status = STATUS_BREAKPOINT;
  581. semaphore_signal(sess->wait_sem);
  582. return KERN_SUCCESS;
  583. }
  584. /*else if(subcode == SIGTERM) { // TODO: Check if we need this
  585. sess->process_status = STATUS_EXIT;
  586. return KERN_SUCCESS;
  587. }*/
  588. }
  589. else if(exception == EXC_BREAKPOINT) {
  590. task_suspend(sess->task);
  591. // check if single step mode
  592. if(state->__rflags & SINGLESTEP_TRAP) {
  593. state->__rflags &= ~SINGLESTEP_TRAP; // clear single-step
  594. sess->process_status = STATUS_SINGLESTEP;
  595. DEBUG_PRINT("SINGLE STEP");
  596. } else {
  597. sess->process_status = STATUS_BREAKPOINT;
  598. }
  599. // move past breakpoint by setting old to new thread state
  600. *newState = *state;
  601. *new_stateCnt = old_stateCnt;
  602. *flavor = x86_THREAD_STATE64;
  603. semaphore_signal(sess->wait_sem);
  604. return KERN_SUCCESS;
  605. }
  606. else if(exception == EXC_BAD_INSTRUCTION) {
  607. task_suspend(sess->task);
  608. sess->process_status = STATUS_BREAKPOINT;
  609. return KERN_SUCCESS;
  610. }
  611. else if(exception == EXC_BAD_ACCESS) {
  612. task_suspend(sess->task);
  613. sess->process_status = STATUS_ERROR;
  614. return KERN_SUCCESS;
  615. }
  616. else {
  617. DEBUG_PRINT("not handling this exception (%s)!", exception_to_string(exception));
  618. }
  619. return KERN_FAILURE;
  620. }
  621. static void* task_exception_server (mach_port_t exception_port) {
  622. mach_msg_return_t rt;
  623. mach_msg_header_t *msg;
  624. mach_msg_header_t *reply;
  625. msg = safe_malloc(sizeof(union __RequestUnion__mach_exc_subsystem));
  626. reply = safe_malloc(sizeof(union __ReplyUnion__mach_exc_subsystem));
  627. DEBUG_PRINT("launching exception server...");
  628. int i = 0;
  629. while (1) {
  630. DEBUG_PRINT("waiting for next exception (%i)...",i);
  631. i++;
  632. rt = mach_msg(msg, MACH_RCV_MSG, 0, sizeof(union __RequestUnion__mach_exc_subsystem), exception_port, 0, MACH_PORT_NULL);
  633. if (rt!= MACH_MSG_SUCCESS) {
  634. DEBUG_PRINT("MACH_RCV_MSG stopped, exit from task_exception_server thread :%d\n", 1);
  635. return "MACH_RCV_MSG_FAILURE";
  636. }
  637. /*
  638. * Call out to the mach_exc_server generated by mig and mach_exc.defs.
  639. * This will in turn invoke one of:
  640. * mach_catch_exception_raise()
  641. * mach_catch_exception_raise_state()
  642. * mach_catch_exception_raise_state_identity()
  643. * .. depending on the behavior specified when registering the Mach exception port.
  644. */
  645. mach_exc_server(msg, reply);
  646. // Send the now-initialized reply
  647. rt = mach_msg(reply, MACH_SEND_MSG, reply->msgh_size, 0, MACH_PORT_NULL, 0, MACH_PORT_NULL);
  648. if (rt!= MACH_MSG_SUCCESS) {
  649. return "MACH_SEND_MSG_FAILURE";
  650. }
  651. }
  652. }
  653. static void wait_for_exception(debug_session *sess, int timeout /*in millis*/) {
  654. DEBUG_PRINT("waiting for next exception...");
  655. kern_return_t kret = semaphore_timedwait(sess->wait_sem, (struct mach_timespec){0,timeout * 1000000});
  656. if(kret == KERN_OPERATION_TIMED_OUT) {
  657. sess->process_status = STATUS_TIMEOUT;
  658. DEBUG_PRINT("wait timed out!");
  659. } else {
  660. DEBUG_PRINT("got notified of an exception!");
  661. }
  662. }
  663. #pragma mark Debug API
  664. status_t MDBG_API(session_attach)( pid_t pid ) {
  665. return attach_to_pid(pid) == KERN_SUCCESS;
  666. }
  667. status_t MDBG_API(session_detach)( pid_t pid ) {
  668. return detach_from_pid(pid) == KERN_SUCCESS;
  669. }
  670. status_t MDBG_API(session_pause)( pid_t pid ) {
  671. return kill(pid, SIGTRAP) == 0;
  672. }
  673. int MDBG_API(session_wait)( pid_t pid, int *thread, int timeout ) {
  674. debug_session *sess = find_session_by_pid( pid );
  675. if(sess != NULL) {
  676. wait_for_exception(sess, timeout);
  677. *thread = sess->current_thread;
  678. return sess->process_status;
  679. }
  680. return 4;
  681. }
  682. status_t MDBG_API(session_resume)( pid_t pid ) {
  683. debug_session *sess = find_session_by_pid( pid );
  684. if(sess != NULL) {
  685. sess->process_status = STATUS_HANDLED;
  686. task_resume(sess->task);
  687. return true;
  688. }
  689. return false;
  690. }
  691. debug_session *MDBG_API(session_get)( pid_t pid ) {
  692. return find_session_by_pid( pid );
  693. }
  694. status_t MDBG_API(read_memory)( pid_t pid, unsigned char* addr, unsigned char* dest, int size ) {
  695. return read_memory( get_task(pid), (mach_vm_address_t)addr, (mach_vm_address_t)dest, size ) == KERN_SUCCESS;
  696. }
  697. status_t MDBG_API(write_memory)( pid_t pid, unsigned char* addr, unsigned char* src, int size ) {
  698. return write_memory( get_task(pid), (mach_vm_address_t)addr, (mach_vm_address_t)src, size ) == KERN_SUCCESS;
  699. }
  700. void* MDBG_API(read_register)( pid_t pid, int thread, int reg, bool is64 ) {
  701. return (void*)read_register( get_task(pid), thread, reg, is64 );
  702. }
  703. status_t MDBG_API(write_register)( pid_t pid, int thread, int reg, void *value, bool is64 ) {
  704. return write_register( get_task(pid), thread, reg, value, is64 ) == KERN_SUCCESS;
  705. }