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:
Stefani Seibold 2015-12-01 15:35:28 +01:00
parent 95b0d7b7b8
commit bf23453ea1
8 changed files with 109 additions and 20 deletions

View File

@ -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);

View File

@ -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) {

View File

@ -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);

View File

@ -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)

View File

@ -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) {

View File

@ -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;

View File

@ -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();

View File

@ -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;
}