diff --git a/backend.h b/backend.h index 6e050f1..71e4b7c 100644 --- a/backend.h +++ b/backend.h @@ -75,15 +75,18 @@ arch_addr_t get_instruction_pointer(struct task *task); void set_instruction_pointer(struct task *task, arch_addr_t addr); /* do a single step */ -int do_singlestep(struct task *task); +int do_singlestep(struct task *task, struct breakpoint *bp); /* handle a single step event */ -int handle_singlestep(struct task *task, int (*singlestep)(struct task *task)); +int handle_singlestep(struct task *task, int (*singlestep)(struct task *task), struct breakpoint *bp); /* Find and return caller address, i.e. the address where the current * function returns. */ arch_addr_t get_return_addr(struct task *task); +/* get address of IP register */ +unsigned int ip_reg_addr(void); + #if HW_BREAKPOINTS > 0 /* returns true if the hw breakpoint is pendig */ int get_hw_bp_state(struct task *task, unsigned int n); diff --git a/breakpoint.c b/breakpoint.c index aae569d..43588e9 100644 --- a/breakpoint.c +++ b/breakpoint.c @@ -291,6 +291,9 @@ void breakpoint_hw_destroy(struct task *task) { unsigned int i; + if (options.nohwbp) + return; + for(i = 0; i < HW_BREAKPOINTS; ++i) task->hw_bp[i] = NULL; diff --git a/client/process.c b/client/process.c index 334e4e6..25dcb8d 100644 --- a/client/process.c +++ b/client/process.c @@ -680,7 +680,7 @@ static int process_rb_insert_block(struct process *process, unsigned long addr, if ((addr <= this->addr) && (addr + n > this->addr)) { process_dump_collision(process, this, addr, size, operation); - if (options.kill) + if (unlikely(options.kill)) abort(); } @@ -1262,7 +1262,7 @@ void process_munmap(struct process *process, struct mt_msg *mt_msg, void *payloa if (!is_mmap(block->stack_node->stack->operation)) { fprintf(stderr, ">>> block missmatch pid:%d MAP<>MALLOC %#lx\n", process->pid, ptr); - if (options.kill) + if (unlikely(options.kill)) abort(); break; @@ -1387,17 +1387,10 @@ void process_free(struct process *process, struct mt_msg *mt_msg, void *payload) block = process_rb_search(&process->block_table, ptr); if (block) { - if (block->addr != ptr) { - fprintf(stderr, ">>> block invalid free %#lx pid:%d\n", ptr, process->pid); - - if (options.kill) - abort(); - } - if (is_mmap(block->stack_node->stack->operation)) { fprintf(stderr, ">>> block missmatch pid:%d MAP<>MALLOC %#lx\n", process->pid, ptr); - if (options.kill) + if (unlikely(options.kill)) abort(); } @@ -1427,10 +1420,10 @@ void process_free(struct process *process, struct mt_msg *mt_msg, void *payload) } else { if (!process->attached) { - if (unlikely(options.kill)) { - fprintf(stderr, ">>> block %#lx not found pid:%d\n", ptr, process->pid); + fprintf(stderr, ">>> block %#lx not found pid:%d\n", ptr, process->pid); + + if (unlikely(options.kill)) abort(); - } } } } @@ -1438,7 +1431,7 @@ void process_free(struct process *process, struct mt_msg *mt_msg, void *payload) void process_realloc_done(struct process *process, struct mt_msg *mt_msg, void *payload) { unsigned long ptr; - unsigned long pid; + unsigned int pid; struct list_head *it; if (!process->tracing) @@ -1467,11 +1460,11 @@ void process_realloc_done(struct process *process, struct mt_msg *mt_msg, void * process_rb_insert_block(process, re->addr, re->size, re->stack, re->flags, re->operation); realloc_del(re); - return; } } +// fprintf(stderr, ">>> unexpected realloc done pid: %u\n", pid); return; } @@ -1517,7 +1510,7 @@ void process_alloc(struct process *process, struct mt_msg *mt_msg, void *payload process_dump_collision(process, block, ptr, size, mt_msg->operation); - if (options.kill) + if (unlikely(options.kill)) abort(); process_rb_delete_block(process, block); diff --git a/event.c b/event.c index 8546d66..28b74ea 100644 --- a/event.c +++ b/event.c @@ -312,7 +312,7 @@ static void handle_breakpoint(struct task *task) save_param_context(task); - if (libsym->func->report_out || options.kill) { + if (libsym->func->report_out || !options.nocpp) { task->breakpoint = breakpoint_insert(task, get_return_addr(task), NULL, BP_HW_SCRATCH); if (likely(task->breakpoint)) { task->libsym = libsym; diff --git a/report.c b/report.c index b8b5c25..1101f8b 100644 --- a/report.c +++ b/report.c @@ -113,24 +113,19 @@ static void report_alloc32(struct task *task, enum mt_operation op, unsigned lon server_send_msg(op, task->leader->pid, alloc, sizeof(*alloc) + i * sizeof(uint32_t)); } -static void _report_alloc(struct task *task, enum mt_operation op, unsigned long ptr, unsigned long size, int depth, struct library_symbol *libsym) +static void report_alloc(struct task *task, enum mt_operation op, unsigned long ptr, unsigned long size, int depth, struct library_symbol *libsym) { debug(DEBUG_FUNCTION, "%d [%d]: %#lx %lu", op, task->pid, ptr, size); + if (!ptr) + return; + if (task_is_64bit(task)) report_alloc64(task, op, ptr, size, depth, libsym); else report_alloc32(task, op, ptr, size, depth, libsym); } -static void report_alloc(struct task *task, enum mt_operation op, unsigned long ptr, unsigned long size, int depth, struct library_symbol *libsym) -{ - if (!ptr) - return; - - _report_alloc(task, op, ptr, size, depth, libsym); -} - static void _report_alloc_op(struct task *task, struct library_symbol *libsym, enum mt_operation op) { unsigned long size = fetch_param(task, 0); @@ -186,21 +181,23 @@ static void _report_realloc(struct task *task, struct library_symbol *libsym) report_alloc(task, MT_REALLOC, ret, size, options.bt_depth, libsym); } - if (task_is_64bit(task)) { - struct mt_alloc_payload_64 *alloc = alloca(sizeof(*alloc)); + if (fetch_param(task, 0)) { + if (task_is_64bit(task)) { + struct mt_alloc_payload_64 *alloc = alloca(sizeof(*alloc)); - alloc->ptr = (uint64_t)ret; - alloc->size = (uint64_t)task->pid; + alloc->ptr = (uint64_t)ret; + alloc->size = (uint64_t)task->pid; - server_send_msg(MT_REALLOC_DONE, task->leader->pid, alloc, sizeof(*alloc)); - } - else { - struct mt_alloc_payload_32 *alloc = alloca(sizeof(*alloc)); + server_send_msg(MT_REALLOC_DONE, task->leader->pid, alloc, sizeof(*alloc)); + } + else { + struct mt_alloc_payload_32 *alloc = alloca(sizeof(*alloc)); - alloc->ptr = (uint32_t)ret; - alloc->size = (uint32_t)task->pid; + alloc->ptr = (uint32_t)ret; + alloc->size = (uint32_t)task->pid; - server_send_msg(MT_REALLOC_DONE, task->leader->pid, alloc, sizeof(*alloc)); + server_send_msg(MT_REALLOC_DONE, task->leader->pid, alloc, sizeof(*alloc)); + } } } @@ -208,7 +205,7 @@ static void report_realloc(struct task *task, struct library_symbol *libsym) { unsigned long addr = fetch_param(task, 0); - _report_alloc(task, MT_REALLOC_ENTER, addr, task->pid, options.sanity ? options.bt_depth : 0, libsym); + report_alloc(task, MT_REALLOC_ENTER, addr, task->pid, options.sanity ? options.bt_depth : 0, libsym); } static void _report_calloc(struct task *task, struct library_symbol *libsym) @@ -368,6 +365,10 @@ static const struct function flist[] = { { "delete[](void*)", "_ZdaPv", 1, report_delete_array, NULL }, { "delete(void*, std::nothrow_t const&)", "_ZdlPvRKSt9nothrow_t", 1, report_delete, NULL }, { "delete[](void*, std::nothrow_t const&)", "_ZdaPvRKSt9nothrow_t", 1, report_delete_array, NULL }, + { "delete(void*, unsigned long)", "_ZdlPvm", 1, report_delete, NULL }, + { "delete[](void*, unsigned long)", "_ZdaPvj", 1, report_delete_array, NULL }, + { "delete(void*, unsigned long)", "_ZdlPvj", 1, report_delete, NULL }, + { "delete[](void*, unsigned long)", "_ZdaPvm", 1, report_delete_array, NULL }, }; const struct function *flist_matches_symbol(const char *sym_name) diff --git a/sysdeps/linux-gnu/arm/arch.c b/sysdeps/linux-gnu/arm/arch.c index 9979fc3..bf18192 100644 --- a/sysdeps/linux-gnu/arm/arch.c +++ b/sysdeps/linux-gnu/arm/arch.c @@ -669,7 +669,7 @@ static int ptrace_cont(struct task *task) return 0; } -int do_singlestep(struct task *task) +int do_singlestep(struct task *task, struct breakpoint *bp) { const uint32_t pc = get_instruction_pointer(task); uint32_t cpsr; @@ -714,16 +714,13 @@ int do_singlestep(struct task *task) else bp2 = NULL; - ret = handle_singlestep(task, ptrace_cont); + ret = handle_singlestep(task, ptrace_cont, bp); if (bp1) breakpoint_disable(task, bp1); if (bp2) breakpoint_disable(task, bp2); - if (ret) - return ret; - - return 0; + return ret; } diff --git a/sysdeps/linux-gnu/arm/regs.c b/sysdeps/linux-gnu/arm/regs.c index c33bb4a..47ad44f 100644 --- a/sysdeps/linux-gnu/arm/regs.c +++ b/sysdeps/linux-gnu/arm/regs.c @@ -59,6 +59,11 @@ void set_instruction_pointer(struct task *task, arch_addr_t addr) } } +unsigned int ip_reg_addr(void) +{ + return offsetof(struct pt_regs, ARM_pc); +} + arch_addr_t get_return_addr(struct task *task) { return ARCH_ADDR_T(task->context.regs.ARM_lr); diff --git a/sysdeps/linux-gnu/ppc/regs.c b/sysdeps/linux-gnu/ppc/regs.c index b40de17..adecbf0 100644 --- a/sysdeps/linux-gnu/ppc/regs.c +++ b/sysdeps/linux-gnu/ppc/regs.c @@ -74,6 +74,11 @@ void set_instruction_pointer(struct task *task, arch_addr_t addr) } } +unsigned int ip_reg_addr(void) +{ + return sizeof(unsigned long) * PT_NIP; +} + arch_addr_t get_return_addr(struct task *task) { #ifdef __powerpc64__ diff --git a/sysdeps/linux-gnu/trace.c b/sysdeps/linux-gnu/trace.c index 92f14a9..97eb2e2 100644 --- a/sysdeps/linux-gnu/trace.c +++ b/sysdeps/linux-gnu/trace.c @@ -233,6 +233,7 @@ static void process_event(struct task *task, int status) stop_signal = _process_event(task, status); if (stop_signal == -1) { +fprintf(stderr, "%s:%d\n", __FUNCTION__, __LINE__); task->event.type = EVENT_NONE; continue_task(task, 0); return; @@ -245,6 +246,7 @@ static void process_event(struct task *task, int status) return; if (unlikely(fetch_context(task) == -1)) { +fprintf(stderr, "%s:%d\n", __FUNCTION__, __LINE__); task->event.type = EVENT_NONE; continue_task(task, 0); return; @@ -259,7 +261,6 @@ static void process_event(struct task *task, int status) if (task->hw_bp[i] && task->hw_bp[i]->addr == ip) { if (likely(get_hw_bp_state(task, i))) bp = task->hw_bp[i]; - break; } } @@ -273,8 +274,9 @@ static void process_event(struct task *task, int status) { bp = breakpoint_find(leader, ip - DECR_PC_AFTER_BREAK); if (unlikely(!bp)) { - task->event.type = EVENT_NONE; - continue_task(task, 0); +fprintf(stderr, "%s:%d\n", __FUNCTION__, __LINE__); +// task->event.type = EVENT_NONE; +// continue_task(task, 0); return; } #if HW_BREAKPOINTS > 0 @@ -459,10 +461,12 @@ void stop_threads(struct task *task) } } -int handle_singlestep(struct task *task, int (*singlestep)(struct task *task)) +int handle_singlestep(struct task *task, int (*singlestep)(struct task *task), struct breakpoint *bp) { int status; int stop_signal; + unsigned long ip; + int ret; for(;;) { if (unlikely(singlestep(task) == -1)) @@ -470,26 +474,41 @@ int handle_singlestep(struct task *task, int (*singlestep)(struct task *task)) if (unlikely(TEMP_FAILURE_RETRY(waitpid(task->pid, &status, __WALL)) != task->pid)) { fprintf(stderr, "%s waitpid pid=%d %s\n", __FUNCTION__, task->pid, strerror(errno)); - return -1; + return 0; } stop_signal = _process_event(task, status); if (stop_signal == -1) - return -1; + return 0; - if (likely(stop_signal == SIGTRAP)) - return 0; /* check if was a real breakpoint code there */ + ip = ptrace(PTRACE_PEEKUSER, task->pid, ip_reg_addr(), 0); + if (ip == (unsigned long)-1) { + fprintf(stderr, "%s ptrace get IP pid=%d %s\n", __FUNCTION__, task->pid, strerror(errno)); + return 0; + } + + if (ip != bp->addr) { + ret = 0; + + if (likely(stop_signal == SIGTRAP)) + return ret; + } + else + ret = 1; if (likely(!stop_signal)) { queue_event(task); - return 0; + return ret; } if (fix_signal(task, stop_signal) > 0) { queue_event(task); - return 1; + return ret; } + + if (!ret) + return ret; } } @@ -504,9 +523,9 @@ static int ptrace_singlestep(struct task *task) return 0; } -int do_singlestep(struct task *task) +int do_singlestep(struct task *task, struct breakpoint *bp) { - return handle_singlestep(task, ptrace_singlestep); + return handle_singlestep(task, ptrace_singlestep, bp); } #endif diff --git a/sysdeps/linux-gnu/x86/regs.c b/sysdeps/linux-gnu/x86/regs.c index 1547be7..f718d27 100644 --- a/sysdeps/linux-gnu/x86/regs.c +++ b/sysdeps/linux-gnu/x86/regs.c @@ -91,6 +91,15 @@ void set_instruction_pointer(struct task *task, arch_addr_t addr) fprintf(stderr, "pid=%d Couldn't set instruction pointer: %s\n", task->pid, strerror(errno)); } +unsigned int ip_reg_addr(void) +{ +#ifdef __x86_64__ + return sizeof(unsigned long) * RIP; +#else + return sizeof(unsigned long) * EIP; +#endif +} + arch_addr_t get_return_addr(struct task *task) { long a; diff --git a/trace.c b/trace.c index 4f0da0e..e244cae 100644 --- a/trace.c +++ b/trace.c @@ -53,19 +53,21 @@ int skip_breakpoint(struct task *task, struct breakpoint *bp) int ret = 0; struct timespec start; + if (task->skip_bp) + return 1; + if (unlikely(options.verbose > 1)) start_time(&start); breakpoint_disable(task, bp); - ret = do_singlestep(task); + ret = do_singlestep(task, bp); breakpoint_enable(task, bp); if (unlikely(options.verbose > 1)) set_timer(&start, &skip_bp_time); if (unlikely(ret)) { - if (unlikely(ret == 1)) - task->skip_bp = breakpoint_get(bp); + task->skip_bp = breakpoint_get(bp); return ret; } }