diff --git a/breakpoint.c b/breakpoint.c index e4a451d..83559b1 100644 --- a/breakpoint.c +++ b/breakpoint.c @@ -302,7 +302,9 @@ void enable_scratch_hw_bp(struct task *task, struct breakpoint *bp) if (unlikely(bp->deleted)) return; - assert(bp->type == BP_HW_SCRATCH); + if (bp->type != BP_HW_SCRATCH) + return; + assert(bp->hw); assert(bp->hw_bp_slot == HW_BP_SCRATCH_SLOT); @@ -315,7 +317,9 @@ void disable_scratch_hw_bp(struct task *task, struct breakpoint *bp) if (unlikely(bp->deleted)) return; - assert(bp->type == BP_HW_SCRATCH); + if (bp->type != BP_HW_SCRATCH) + return; + assert(bp->hw); assert(bp->hw_bp_slot == HW_BP_SCRATCH_SLOT); diff --git a/client/client.c b/client/client.c index 750337f..23f867d 100644 --- a/client/client.c +++ b/client/client.c @@ -580,6 +580,28 @@ void client_request_info(void) return; } +int client_set_depth(int depth) +{ + struct memtrace_depth payload; + + if (depth < 0) + return 1; + + if (depth > 255) + depth = 255; + + if (mt_info.stack_depth == depth) + return 1; + + payload.stack_depth = depth; + + if (sock_send_msg(client_fd, MT_DEPTH, 0, &payload, sizeof(payload)) < 0) { + client_broken(); + return -1; + } + return 0; +} + static int client_iterate_process(struct rb_node *node, void *user) { struct rb_process *data = (struct rb_process *)node; @@ -690,6 +712,11 @@ int client_start(void) return -1; } + if (options.bt_depth) { + if (!client_set_depth(options.bt_depth)) + client_request_info(); + } + client_show_info(); if (options.interactive) { diff --git a/client/client.h b/client/client.h index 4da27bb..c116eb6 100644 --- a/client/client.h +++ b/client/client.h @@ -31,6 +31,7 @@ struct process *client_first_process(void); struct process *client_find_process(unsigned int pid); void client_iterate_processes(int (*func)(struct process *process)); void client_show_info(void); +int client_set_depth(int depth); void client_request_info(void); int client_wait_op(enum mt_operation op); void client_close(void); diff --git a/client/process.c b/client/process.c index 251af11..a643abe 100644 --- a/client/process.c +++ b/client/process.c @@ -615,6 +615,24 @@ static struct rb_block *process_rb_search(struct rb_root *root, unsigned long ad { struct rb_node *node = root->rb_node; + while (node) { + struct rb_block *this = container_of(node, struct rb_block, node); + + if (addr >= this->addr && addr < this->addr + (this->size ? this->size : 1)) + return this; + + if (addr < this->addr) + node = node->rb_left; + else + node = node->rb_right; + } + return NULL; +} + +static struct rb_block *process_rb_block(struct rb_root *root, unsigned long addr) +{ + struct rb_node *node = root->rb_node; + while (node) { struct rb_block *this = container_of(node, struct rb_block, node); @@ -1176,7 +1194,7 @@ void *process_scan(struct process *process, void *leaks, uint32_t payload_len) void *new_leaks = leaks; for(i = 0; i < n; ++i) { - struct rb_block *block = process_rb_search(&process->block_table, process->get_ulong(leaks)); + struct rb_block *block = process_rb_block(&process->block_table, process->get_ulong(leaks)); if (block && !(block->flags & BLOCK_LEAKED)) { block->flags |= BLOCK_LEAKED; @@ -1200,7 +1218,7 @@ void *process_scan(struct process *process, void *leaks, uint32_t payload_len) dump_printf(" leaked bytes: %llu\n", process->leaked_bytes); for(i = 0; i < new; ++i) { - struct rb_block *block = process_rb_search(&process->block_table, process->get_ulong(new_leaks)); + struct rb_block *block = process_rb_block(&process->block_table, process->get_ulong(new_leaks)); if (dump_printf(" leaked at 0x%08lx (%lu bytes)\n", (unsigned long)block->addr, (unsigned long)block->size) == -1) break; @@ -1379,6 +1397,13 @@ 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); @@ -1495,8 +1520,11 @@ void process_alloc(struct process *process, struct mt_msg *mt_msg, void *payload debug(DEBUG_FUNCTION, "ptr=%#lx size=%lu stack_size=%lu", ptr, size, stack_size); - block = process_rb_search_range(&process->block_table, ptr, size); - if (block) { + for(;;) { + block = process_rb_search_range(&process->block_table, ptr, size); + if (!block) + break; + process_dump_collision(process, block, ptr, size, mt_msg->operation); if (options.kill) diff --git a/client/readline.c b/client/readline.c index 8e18afb..12188f6 100644 --- a/client/readline.c +++ b/client/readline.c @@ -70,6 +70,7 @@ static int do_status(struct cmd_opt *cmd, int argc, const char *argv[]); static int do_start(struct cmd_opt *cmd, int argc, const char *argv[]); static int do_stop(struct cmd_opt *cmd, int argc, const char *argv[]); static int do_set_searchpath(struct cmd_opt *cmd, struct cmd_opt *opt, int argc, const char *argv[]); +static int do_set_depth(struct cmd_opt *cmd, struct cmd_opt *opt, int argc, const char *argv[]); static int do_show_info(struct cmd_opt *cmd, struct cmd_opt *opt, int argc, const char *argv[]); static int do_show_searchpath(struct cmd_opt *cmd, struct cmd_opt *opt, int argc, const char *argv[]); @@ -103,6 +104,7 @@ static struct cmd_opt dump_opts[] = { static struct cmd_opt set_opts[] = { { "searchpath", 1, do_set_searchpath, "set searchpath for binaries and libraries" }, + { "depth", 1, do_set_depth, "set backtrace depth" }, { }, }; @@ -496,6 +498,18 @@ static int do_set_searchpath(struct cmd_opt *cmd, struct cmd_opt *opt, int argc, return 0; } +static int do_set_depth(struct cmd_opt *cmd, struct cmd_opt *opt, int argc, const char *argv[]) +{ + if (argc != 3) { + fprintf(stderr, "%s: invalid option argument for '%s'\n", cmd->name, opt->name); + return -1; + } + + client_set_depth(atoi(argv[2])); + + return 0; +} + static int do_show_info(struct cmd_opt *cmd, struct cmd_opt *opt, int argc, const char *argv[]) { if (argc > 2) { diff --git a/memtrace.h b/memtrace.h index b5cbf9c..b215640 100644 --- a/memtrace.h +++ b/memtrace.h @@ -31,7 +31,7 @@ #define IS64BIT 0 #endif -#define MEMTRACE_SI_VERSION 6 +#define MEMTRACE_SI_VERSION 7 #define MEMTRACE_SI_FORK 1 #define MEMTRACE_SI_EXEC 2 @@ -69,6 +69,7 @@ enum mt_operation { MT_NEW_ARRAY, MT_DELETE, MT_DELETE_ARRAY, + MT_DEPTH, }; struct __attribute__((packed)) mt_msg { @@ -126,6 +127,10 @@ struct __attribute__((packed)) memtrace_info { struct memtrace_timer_info skip_bp_time; }; +struct __attribute__((packed)) memtrace_depth { + uint8_t stack_depth; +}; + struct __attribute__((packed)) mt_map_payload { uint64_t addr; uint64_t offset; diff --git a/options.c b/options.c index fc6a3dd..d97fa0a 100644 --- a/options.c +++ b/options.c @@ -45,10 +45,7 @@ #define SYSCONFDIR "/etc" #endif -#define MIN_STACK 4 -#define MAX_STACK 64 - -#define DEFAULT_STACK 16 +#define DEFAULT_STACK 12 #define DEFAULT_PORT 4576 static char *sockdef; @@ -269,7 +266,7 @@ char **process_options(int argc, char **argv) options.auto_scan = 0; options.output = stderr; - options.bt_depth = DEFAULT_STACK; + options.bt_depth = 0; options.port = NULL; options.follow = 0; options.follow_exec = 0; @@ -567,6 +564,11 @@ char **process_options(int argc, char **argv) if (argc > 0) options.command = search_for_command(argv[0]); + if (options.bt_depth < 0) + options.bt_depth = 0; + else + if (options.bt_depth > 255) + options.bt_depth = 255; if (options.address && options.logfile) { fprintf(stderr, "%s: either logfile or remote address is valid\n", progname); @@ -600,6 +602,9 @@ char **process_options(int argc, char **argv) err_usage(); } } + + if (!options.bt_depth) + options.bt_depth = DEFAULT_STACK; } else { if (options.opt_p || options.command) { @@ -694,12 +699,6 @@ char **process_options(int argc, char **argv) if (options.sort_by == OPT_SORT_LEAKS || options.sort_by == OPT_SORT_BYTES_LEAKED) options.auto_scan = 1; - if (options.bt_depth < MIN_STACK) - options.bt_depth = MIN_STACK; - else - if (options.bt_depth > MAX_STACK) - options.bt_depth = MAX_STACK; - if (!options.opt_F) def_config(); diff --git a/server.c b/server.c index 66003f7..f03b031 100644 --- a/server.c +++ b/server.c @@ -177,10 +177,21 @@ int server_handle_command(void) } if (!cmd.pid) { - if (cmd.operation == MT_INFO) + switch(cmd.operation) { + case MT_INFO: report_info(1); - else + break; + case MT_DEPTH: + { + struct memtrace_depth *depth = payload; + + if (depth->stack_depth) + options.bt_depth = depth->stack_depth; + break; + } + default: server_close(); + } goto finish; }