mdbg.c 28 KB

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