enum mix_cmd_result mix_cmd_break_insert (char *command, char **argv, int argc) { char *address = NULL; enum bp_type type = REG_BP; int temp_p = 0; int thread = -1; int ignore_count = 0; char *condition = NULL; char *requested_shlib = NULL; char realpath_buf[PATH_MAX]; enum gdb_rc rc; int *indices = NULL; int pending = 0; struct gdb_exception e; struct gdb_events *old_hooks; enum opt { HARDWARE_OPT, TEMP_OPT /*, REGEXP_OPT */ , CONDITION_OPT, IGNORE_COUNT_OPT, THREAD_OPT, PENDING_OPT, SHLIB_OPT, LIST_OPT }; static struct mix_opt opts[] = { {"h", HARDWARE_OPT, 0}, {"t", TEMP_OPT, 0}, {"c", CONDITION_OPT, 1}, {"i", IGNORE_COUNT_OPT, 1}, {"p", THREAD_OPT, 1}, {"f", PENDING_OPT, 0}, {"s", SHLIB_OPT, 1}, {"l", LIST_OPT, 1}, { 0, 0, 0 } }; /* Parse arguments. It could be -r or -h or -t, <location> or ``--'' to denote the end of the option list. */ int optind = 0; char *optarg; struct cleanup *indices_cleanup = NULL; while (1) { int opt = mix_getopt ("mix_cmd_break_insert", argc, argv, opts, &optind, &optarg); if (opt < 0) break; switch ((enum opt) opt) { case TEMP_OPT: temp_p = 1; break; case HARDWARE_OPT: type = HW_BP; break; #if 0 case REGEXP_OPT: type = REGEXP_BP; break; #endif case CONDITION_OPT: condition = optarg; break; case IGNORE_COUNT_OPT: ignore_count = atol (optarg); /* APPLE LOCAL: Same behavior as set_ignore_count(). */ if (ignore_count < 0) ignore_count = 0; break; case THREAD_OPT: thread = atol (optarg); break; case PENDING_OPT: pending = 1; break; case SHLIB_OPT: requested_shlib = optarg; break; case LIST_OPT: { char *numptr; int nelem = 0, i; /* First count the number of elements, which is the number of spaces plus one. */ numptr = optarg; while (*numptr) { if (*numptr != ' ') { nelem++; while (*numptr != ' ' && *numptr != '\0') numptr++; } else numptr++; } if (nelem == 0) error ("mix_cmd_break_insert: Got index with no elements"); indices = (int *) xmalloc ((nelem + 1) * sizeof (int *)); indices_cleanup = make_cleanup (xfree, indices); /* Now extract the elements. */ numptr = optarg; i = 0; errno = 0; while (*numptr != '\0') { indices[i++] = strtol (numptr, &numptr, 10); if (errno == EINVAL) error ("mix_cmd_break_insert: bad index at \"%s\"", numptr); } /* Since we aren't passing a number of elements, we terminate the indices by putting in a -1 element. */ indices[i] = -1; break; } } } if (optind >= argc) error (_("mix_cmd_break_insert: Missing <location>")); if (optind < argc - 1) error (_("mix_cmd_break_insert: Garbage following <location>")); address = argv[optind]; /* APPLE LOCAL: realpath() the incoming shlib name, as we do with all objfile/dylib/executable names. NB this condition is incorrect if we're passed something like "./foo.dylib", "../foo.dylib", or "~/bin/foo.dylib", but that shouldn't happen.... */ if (requested_shlib && IS_ABSOLUTE_PATH (requested_shlib)) { realpath (requested_shlib, realpath_buf); /* It'll be xstrdup()'ed down in the breakpoint command, so just point to the stack array until then. */ requested_shlib = realpath_buf; } /* Now we have what we need, let's insert the breakpoint! */ if (! mi_breakpoint_observers_installed) { observer_attach_breakpoint_created (breakpoint_notify); observer_attach_breakpoint_modified (breakpoint_notify); observer_attach_breakpoint_deleted (breakpoint_notify); mi_breakpoint_observers_installed = 1; } mi_can_breakpoint_notify = 1; /* Make sure we restore hooks even if exception is thrown. */ TRY_CATCH (e, RETURN_MASK_ALL) { switch (type) { case REG_BP: set_breakpoint (address, condition, 0 /*hardwareflag */, temp_p, thread, ignore_count, pending); break; case HW_BP: set_breakpoint (address, condition, 1 /*hardwareflag */, temp_p, thread, ignore_count, pending); break; #if 0 case REGEXP_BP: if (temp_p) error (_("mix_cmd_break_insert: Unsupported tempoary regexp breakpoint")); else rbreak_command_wrapper (address, FROM_TTY); return MIX_CMD_DONE; break; #endif default: internal_error (__FILE__, __LINE__, _("mix_cmd_break_insert: Bad switch.")); } } mi_can_breakpoint_notify = 0; if (e.reason < 0) throw_exception (e); return MIX_CMD_DONE; }
static void process_events(PluginData* data, PDReader* reader, PDWriter* writer) { uint32_t event; while ((event = PDRead_get_event(reader))) { switch (event) { //case PDEventType_getExceptionLocation : setExceptionLocation(plugin, writer); break; //case PDEventType_getCallstack : set_callstack(plugin, writer); break; case PDEventType_GetRegisters: { get_registers(data); break; } case PDEventType_GetCallstack: { if (should_send_command(data)) set_callstack(data, reader, writer); break; } case PDEventType_GetDisassembly: { if (should_send_command(data)) get_disassembly(data, reader, writer); break; } case PDEventType_GetMemory: { if (should_send_command(data)) get_memory(data, reader, writer); break; } case PDEventType_MenuEvent: { on_menu(data, reader); break; } case PDEventType_SetBreakpoint: { set_breakpoint(data, reader, writer); // if we add a breakpoint to VICE it will always stop but if we are already running when // adding the breakpoint we just force VICE to run again if (data->state == PDDebugState_Running) send_command(data, "ret\n"); break; } case PDEventType_DeleteBreakpoint: { del_breakpoint(data, reader, writer); break; } case PDEventType_SetExecutable: { //if (should_send_command(data)) set_executable(data, reader); break; } } } }
void debugger_proc(pid_t child_proc, struct execute_context *ctx) { /* about child process */ int child_stat; kern_return_t kret; mach_port_t task; int wait_cnt = 0; char **args = ctx->passing_args; /* related analysys of target process binary. */ int i; int nsym; int text_section; uint64_t text_section_offset; uint64_t text_section_size; uint64_t text_section_vmaddr; struct symbol_info *psymbol_table; int init = 0; struct breakpoint_entry top; int stack_depth = 0; /* error check */ if (child_proc == 0 || child_proc == -1) return; /* initialize */ memset(&top, 0x00, sizeof(top)); /* open the port (do as an administrator) */ kret = task_for_pid(mach_task_self(), child_proc, &task); if (kret != KERN_SUCCESS) { fprintf(stderr, "task_for_pid() failed\n"); fprintf(stderr, "%s\n", mach_error_string(kret)); exit(0); } fprintf(stderr, "[Tracer] child_proc: %d\n", child_proc); /* main loop */ while(waitpid(child_proc, &child_stat, WUNTRACED)) { /* {{{ */ char buffer[128]; char w_buf[128]; w_buf[0] = 0x90; /* nop */ if (WIFEXITED(child_stat)) { /* Child Process Terminated */ fprintf(stderr, "[Tracer] Process :%d Terminated\n", child_proc); return; } memset(buffer, 0x00, 128); if(wait_cnt == 0) { /* The First time trapped {{{ */ /* -- The debugee program has not been expanded.-- */ /* -- lookup named symbol -- */ struct file_info bininfo; ud_t ud_obj; uint64_t previous_eip; uint64_t func_start_addr; uint64_t func_end_addr; nsym = get_func_table(args[0], &psymbol_table, &text_section, &text_section_offset, &text_section_size, &text_section_vmaddr); debug_printf("nsym: %d\n", nsym); debug_printf("text section = %d\n", text_section); debug_printf("text section offset: 0x%llx\n", text_section_offset); debug_printf("text section size: 0x%llx\n", text_section_size); debug_printf("text section vmaddr: 0x%llx\n", text_section_vmaddr); qsort(psymbol_table, nsym, sizeof(struct symbol_info), symbolinfo_comp); /* XXX for debugging */ /*display_symbol_table(psymbol_table, nsym); */ /* code analysys */ map_binary(args[0], &bininfo); ud_init(&ud_obj); ud_set_input_buffer(&ud_obj, bininfo.top + text_section_offset, text_section_size); ud_set_mode(&ud_obj, 64); previous_eip = text_section_vmaddr; /* set breakpoint at the entry and exit points of functions */ for(i = 0; i < nsym; i++) { /* Set breakpoints {{{ */ if (is_exclude_func(psymbol_table + i) == 1) { continue; } /* 1, specifying the region of the function */ func_start_addr = psymbol_table[i].nlist64.n_value; if (i != nsym - 1) { /* next section's entry point - 1 */ func_end_addr = psymbol_table[i + 1].nlist64.n_value; } else { func_end_addr = text_section_vmaddr + text_section_size + 1; } printf("%s: 0x%llx --> 0x%llx\n", psymbol_table[i].name, func_start_addr, func_end_addr); /* if (strstr(psymbol_table[i].name, "main") != NULL) { __asm__("int3"); } */ psymbol_table[i].ret_address_num = 0; previous_eip = ud_obj.pc + text_section_vmaddr; while(ud_disassemble(&ud_obj) && previous_eip < func_start_addr) { previous_eip = ud_obj.pc + text_section_vmaddr; } while(ud_disassemble(&ud_obj) && previous_eip < func_end_addr) { if (func_start_addr <= previous_eip && ud_obj.mnemonic == UD_Iret) { set_breakpoint(task, previous_eip, &top); psymbol_table[i].ret_inst_address[ psymbol_table[i].ret_address_num ] = previous_eip; psymbol_table[i].ret_address_num++; } previous_eip = ud_obj.pc + text_section_vmaddr; } /* if (0 < psymbol_table[i].ret_address_num) { set_breakpoint(task, psymbol_table[i].nlist64.n_value, &top); } */ set_breakpoint(task, psymbol_table[i].nlist64.n_value, &top); /* }}} */ } debug_printf("break point insert\n"); unmap_binary(&bininfo); /* }}} */ } else { /* {{{ */ /* break point */ /* 1, Get current address from RIP value. * 2, Find current function name by EIP, and Logging. * 3, Substitute original instruction code for current break point code(0x90). * 4, Decrement EIP value. * 5, Execute only one op-code. * 6, Substitute 0x90 for oroginal code (located in entrance of function). * */ uint64_t rip; read_process_register_64(task, RIP, &rip); if (is_breakpoint(rip - 1, &top) == 1) { stack_depth = breakpoint_handler(task, rip - 1, psymbol_table, nsym, stack_depth); write_process_register_64(task, RIP, RELATIVE_VAL, -1); disable_breakpoint(task, rip - 1, &top); ptrace(PT_STEP, child_proc, (caddr_t)1, 0); set_breakpoint(task, rip - 1, &top); } /* }}} */ } wait_cnt++; ptrace(PT_CONTINUE, child_proc, (caddr_t)1, 0); } /* }}} */ }
static struct breakpoint * set_gdb_breakpoint_1 (char z_type, CORE_ADDR addr, int size, int *err) { struct breakpoint *bp; enum bkpt_type type; enum raw_bkpt_type raw_type; /* If we see GDB inserting a second code breakpoint at the same address, then either: GDB is updating the breakpoint's conditions or commands; or, the first breakpoint must have disappeared due to a shared library unload. On targets where the shared libraries are handled by userspace, like SVR4, for example, GDBserver can't tell if a library was loaded or unloaded. Since we refcount raw breakpoints, we must be careful to make sure GDB breakpoints never contribute more than one reference. if we didn't do this, in case the previous breakpoint is gone due to a shared library unload, we'd just increase the refcount of the previous breakpoint at this address, but the trap was not planted in the inferior anymore, thus the breakpoint would never be hit. Note this must be careful to not create a window where breakpoints are removed from the target, for non-stop, in case the target can poke at memory while the program is running. */ if (z_type == Z_PACKET_SW_BP || z_type == Z_PACKET_HW_BP) { bp = find_gdb_breakpoint (z_type, addr, -1); if (bp != NULL) { if (bp->raw->size != size) { /* A different size than previously seen. The previous breakpoint must be gone then. */ bp->raw->inserted = -1; delete_breakpoint (bp); bp = NULL; } else if (z_type == Z_PACKET_SW_BP) { /* Check if the breakpoint is actually gone from the target, due to an solib unload, for example. Might as well validate _all_ breakpoints. */ validate_breakpoints (); /* Breakpoints that don't pass validation are deleted. */ bp = find_gdb_breakpoint (z_type, addr, -1); } } } else { /* Data breakpoints for the same address but different size are expected. GDB doesn't merge these. The backend gets to do that if it wants/can. */ bp = find_gdb_breakpoint (z_type, addr, size); } if (bp != NULL) { /* We already know about this breakpoint, there's nothing else to do - GDB's reference is already accounted for. Note that whether the breakpoint inserted is left as is - we may be stepping over it, for example, in which case we don't want to force-reinsert it. */ return bp; } raw_type = Z_packet_to_raw_bkpt_type (z_type); type = Z_packet_to_bkpt_type (z_type); return set_breakpoint (type, raw_type, addr, size, NULL, err); }