mirror of
https://github.com/sstefani/mtrace.git
synced 2025-12-06 16:56:41 +08:00
accurate single step, c++ 11 support, optimizations
This commit is contained in:
parent
e50dccecb3
commit
cf997a7dc9
@ -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);
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
2
event.c
2
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;
|
||||
|
||||
43
report.c
43
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)
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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__
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
8
trace.c
8
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;
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user