accurate single step, c++ 11 support, optimizations

This commit is contained in:
Stefani Seibold 2016-05-22 09:50:18 +02:00
parent e50dccecb3
commit cf997a7dc9
11 changed files with 98 additions and 61 deletions

View File

@ -75,15 +75,18 @@ arch_addr_t get_instruction_pointer(struct task *task);
void set_instruction_pointer(struct task *task, arch_addr_t addr); void set_instruction_pointer(struct task *task, arch_addr_t addr);
/* do a single step */ /* do a single step */
int do_singlestep(struct task *task); int do_singlestep(struct task *task, struct breakpoint *bp);
/* handle a single step event */ /* 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 /* Find and return caller address, i.e. the address where the current
* function returns. */ * function returns. */
arch_addr_t get_return_addr(struct task *task); arch_addr_t get_return_addr(struct task *task);
/* get address of IP register */
unsigned int ip_reg_addr(void);
#if HW_BREAKPOINTS > 0 #if HW_BREAKPOINTS > 0
/* returns true if the hw breakpoint is pendig */ /* returns true if the hw breakpoint is pendig */
int get_hw_bp_state(struct task *task, unsigned int n); int get_hw_bp_state(struct task *task, unsigned int n);

View File

@ -291,6 +291,9 @@ void breakpoint_hw_destroy(struct task *task)
{ {
unsigned int i; unsigned int i;
if (options.nohwbp)
return;
for(i = 0; i < HW_BREAKPOINTS; ++i) for(i = 0; i < HW_BREAKPOINTS; ++i)
task->hw_bp[i] = NULL; task->hw_bp[i] = NULL;

View File

@ -680,7 +680,7 @@ static int process_rb_insert_block(struct process *process, unsigned long addr,
if ((addr <= this->addr) && (addr + n > this->addr)) { if ((addr <= this->addr) && (addr + n > this->addr)) {
process_dump_collision(process, this, addr, size, operation); process_dump_collision(process, this, addr, size, operation);
if (options.kill) if (unlikely(options.kill))
abort(); 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)) { if (!is_mmap(block->stack_node->stack->operation)) {
fprintf(stderr, ">>> block missmatch pid:%d MAP<>MALLOC %#lx\n", process->pid, ptr); fprintf(stderr, ">>> block missmatch pid:%d MAP<>MALLOC %#lx\n", process->pid, ptr);
if (options.kill) if (unlikely(options.kill))
abort(); abort();
break; 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); block = process_rb_search(&process->block_table, ptr);
if (block) { 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)) { if (is_mmap(block->stack_node->stack->operation)) {
fprintf(stderr, ">>> block missmatch pid:%d MAP<>MALLOC %#lx\n", process->pid, ptr); fprintf(stderr, ">>> block missmatch pid:%d MAP<>MALLOC %#lx\n", process->pid, ptr);
if (options.kill) if (unlikely(options.kill))
abort(); abort();
} }
@ -1427,10 +1420,10 @@ void process_free(struct process *process, struct mt_msg *mt_msg, void *payload)
} }
else { else {
if (!process->attached) { 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(); 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) void process_realloc_done(struct process *process, struct mt_msg *mt_msg, void *payload)
{ {
unsigned long ptr; unsigned long ptr;
unsigned long pid; unsigned int pid;
struct list_head *it; struct list_head *it;
if (!process->tracing) 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); process_rb_insert_block(process, re->addr, re->size, re->stack, re->flags, re->operation);
realloc_del(re); realloc_del(re);
return; return;
} }
} }
// fprintf(stderr, ">>> unexpected realloc done pid: %u\n", pid);
return; 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); process_dump_collision(process, block, ptr, size, mt_msg->operation);
if (options.kill) if (unlikely(options.kill))
abort(); abort();
process_rb_delete_block(process, block); process_rb_delete_block(process, block);

View File

@ -312,7 +312,7 @@ static void handle_breakpoint(struct task *task)
save_param_context(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); task->breakpoint = breakpoint_insert(task, get_return_addr(task), NULL, BP_HW_SCRATCH);
if (likely(task->breakpoint)) { if (likely(task->breakpoint)) {
task->libsym = libsym; task->libsym = libsym;

View File

@ -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)); 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); debug(DEBUG_FUNCTION, "%d [%d]: %#lx %lu", op, task->pid, ptr, size);
if (!ptr)
return;
if (task_is_64bit(task)) if (task_is_64bit(task))
report_alloc64(task, op, ptr, size, depth, libsym); report_alloc64(task, op, ptr, size, depth, libsym);
else else
report_alloc32(task, op, ptr, size, depth, libsym); 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) static void _report_alloc_op(struct task *task, struct library_symbol *libsym, enum mt_operation op)
{ {
unsigned long size = fetch_param(task, 0); 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); report_alloc(task, MT_REALLOC, ret, size, options.bt_depth, libsym);
} }
if (task_is_64bit(task)) { if (fetch_param(task, 0)) {
struct mt_alloc_payload_64 *alloc = alloca(sizeof(*alloc)); if (task_is_64bit(task)) {
struct mt_alloc_payload_64 *alloc = alloca(sizeof(*alloc));
alloc->ptr = (uint64_t)ret; alloc->ptr = (uint64_t)ret;
alloc->size = (uint64_t)task->pid; alloc->size = (uint64_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));
} }
else { else {
struct mt_alloc_payload_32 *alloc = alloca(sizeof(*alloc)); struct mt_alloc_payload_32 *alloc = alloca(sizeof(*alloc));
alloc->ptr = (uint32_t)ret; alloc->ptr = (uint32_t)ret;
alloc->size = (uint32_t)task->pid; 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); 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) 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*)", "_ZdaPv", 1, report_delete_array, NULL },
{ "delete(void*, std::nothrow_t const&)", "_ZdlPvRKSt9nothrow_t", 1, report_delete, 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*, 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) const struct function *flist_matches_symbol(const char *sym_name)

View File

@ -669,7 +669,7 @@ static int ptrace_cont(struct task *task)
return 0; 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); const uint32_t pc = get_instruction_pointer(task);
uint32_t cpsr; uint32_t cpsr;
@ -714,16 +714,13 @@ int do_singlestep(struct task *task)
else else
bp2 = NULL; bp2 = NULL;
ret = handle_singlestep(task, ptrace_cont); ret = handle_singlestep(task, ptrace_cont, bp);
if (bp1) if (bp1)
breakpoint_disable(task, bp1); breakpoint_disable(task, bp1);
if (bp2) if (bp2)
breakpoint_disable(task, bp2); breakpoint_disable(task, bp2);
if (ret) return ret;
return ret;
return 0;
} }

View File

@ -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) arch_addr_t get_return_addr(struct task *task)
{ {
return ARCH_ADDR_T(task->context.regs.ARM_lr); return ARCH_ADDR_T(task->context.regs.ARM_lr);

View File

@ -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) arch_addr_t get_return_addr(struct task *task)
{ {
#ifdef __powerpc64__ #ifdef __powerpc64__

View File

@ -233,6 +233,7 @@ static void process_event(struct task *task, int status)
stop_signal = _process_event(task, status); stop_signal = _process_event(task, status);
if (stop_signal == -1) { if (stop_signal == -1) {
fprintf(stderr, "%s:%d\n", __FUNCTION__, __LINE__);
task->event.type = EVENT_NONE; task->event.type = EVENT_NONE;
continue_task(task, 0); continue_task(task, 0);
return; return;
@ -245,6 +246,7 @@ static void process_event(struct task *task, int status)
return; return;
if (unlikely(fetch_context(task) == -1)) { if (unlikely(fetch_context(task) == -1)) {
fprintf(stderr, "%s:%d\n", __FUNCTION__, __LINE__);
task->event.type = EVENT_NONE; task->event.type = EVENT_NONE;
continue_task(task, 0); continue_task(task, 0);
return; 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 (task->hw_bp[i] && task->hw_bp[i]->addr == ip) {
if (likely(get_hw_bp_state(task, i))) if (likely(get_hw_bp_state(task, i)))
bp = task->hw_bp[i]; bp = task->hw_bp[i];
break; break;
} }
} }
@ -273,8 +274,9 @@ static void process_event(struct task *task, int status)
{ {
bp = breakpoint_find(leader, ip - DECR_PC_AFTER_BREAK); bp = breakpoint_find(leader, ip - DECR_PC_AFTER_BREAK);
if (unlikely(!bp)) { if (unlikely(!bp)) {
task->event.type = EVENT_NONE; fprintf(stderr, "%s:%d\n", __FUNCTION__, __LINE__);
continue_task(task, 0); // task->event.type = EVENT_NONE;
// continue_task(task, 0);
return; return;
} }
#if HW_BREAKPOINTS > 0 #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 status;
int stop_signal; int stop_signal;
unsigned long ip;
int ret;
for(;;) { for(;;) {
if (unlikely(singlestep(task) == -1)) 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)) { 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)); fprintf(stderr, "%s waitpid pid=%d %s\n", __FUNCTION__, task->pid, strerror(errno));
return -1; return 0;
} }
stop_signal = _process_event(task, status); stop_signal = _process_event(task, status);
if (stop_signal == -1) if (stop_signal == -1)
return -1; return 0;
if (likely(stop_signal == SIGTRAP)) ip = ptrace(PTRACE_PEEKUSER, task->pid, ip_reg_addr(), 0);
return 0; /* check if was a real breakpoint code there */ 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)) { if (likely(!stop_signal)) {
queue_event(task); queue_event(task);
return 0; return ret;
} }
if (fix_signal(task, stop_signal) > 0) { if (fix_signal(task, stop_signal) > 0) {
queue_event(task); queue_event(task);
return 1; return ret;
} }
if (!ret)
return ret;
} }
} }
@ -504,9 +523,9 @@ static int ptrace_singlestep(struct task *task)
return 0; 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 #endif

View File

@ -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)); 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) arch_addr_t get_return_addr(struct task *task)
{ {
long a; long a;

View File

@ -53,19 +53,21 @@ int skip_breakpoint(struct task *task, struct breakpoint *bp)
int ret = 0; int ret = 0;
struct timespec start; struct timespec start;
if (task->skip_bp)
return 1;
if (unlikely(options.verbose > 1)) if (unlikely(options.verbose > 1))
start_time(&start); start_time(&start);
breakpoint_disable(task, bp); breakpoint_disable(task, bp);
ret = do_singlestep(task); ret = do_singlestep(task, bp);
breakpoint_enable(task, bp); breakpoint_enable(task, bp);
if (unlikely(options.verbose > 1)) if (unlikely(options.verbose > 1))
set_timer(&start, &skip_bp_time); set_timer(&start, &skip_bp_time);
if (unlikely(ret)) { if (unlikely(ret)) {
if (unlikely(ret == 1)) task->skip_bp = breakpoint_get(bp);
task->skip_bp = breakpoint_get(bp);
return ret; return ret;
} }
} }