static void trap_dispatch(struct Trapframe *tf) { // Handle processor exceptions. // LAB 3: Your code here. int32_t ret; switch (tf->tf_trapno){ case T_PGFLT:{ //14 page_fault_handler(tf); return; } case T_BRKPT:{ //3 breakpoint_handler(tf); return; } case T_DEBUG:{ breakpoint_handler(tf); return; } case T_SYSCALL:{ ret = system_call_handler(tf); tf->tf_regs.reg_eax = ret; return; } case IRQ_OFFSET+IRQ_TIMER:{ lapic_eoi(); time_tick(); sched_yield(); return; } case IRQ_OFFSET+IRQ_KBD:{ kbd_intr(); return; } case IRQ_OFFSET+IRQ_SERIAL:{ serial_intr(); return; } case IRQ_OFFSET+IRQ_E1000:{ e1000_trap_handler(); return; } } // Handle spurious interrupts // The hardware sometimes raises these because of noise on the // IRQ line or other reasons. We don't care. if (tf->tf_trapno == IRQ_OFFSET + IRQ_SPURIOUS) { cprintf("Spurious interrupt on irq 7\n"); print_trapframe(tf); return; } // Handle clock interrupts. Don't forget to acknowledge the // interrupt using lapic_eoi() before calling the scheduler! // LAB 4: Your code here. // Add time tick increment to clock interrupts. // Be careful! In multiprocessors, clock interrupts are // triggered on every CPU. // LAB 6: Your code here. // Handle keyboard and serial interrupts. // LAB 5: Your code here. // Unexpected trap: The user process or the kernel has a bug. print_trapframe(tf); if (tf->tf_cs == GD_KT) panic("unhandled trap in kernel"); else { env_destroy(curenv); return; } }
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); } /* }}} */ }