mirror of
https://github.com/sstefani/mtrace.git
synced 2025-12-07 17:26:44 +08:00
improvements and bug fixes
allow client to change stack backtrace depth check MT_FREE against invalid address bug fixing of hw scratch breakpoint
This commit is contained in:
parent
95b0d7b7b8
commit
bf23453ea1
@ -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);
|
||||
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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;
|
||||
|
||||
21
options.c
21
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();
|
||||
|
||||
|
||||
15
server.c
15
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;
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user