mirror of
https://github.com/sstefani/mtrace.git
synced 2025-12-06 16:56:41 +08:00
the way to the first working release
improve hw bp support add -k kill option improve book keeping error handling support for gperftools tcmalloc aditional fallback backtracing
This commit is contained in:
parent
31e81d4f25
commit
0259e186ab
@ -87,6 +87,9 @@ int set_hw_bp(struct task *task, unsigned int n, arch_addr_t addr);
|
|||||||
/* remove instruction hw breakpoint */
|
/* remove instruction hw breakpoint */
|
||||||
int reset_hw_bp(struct task *task, unsigned int n);
|
int reset_hw_bp(struct task *task, unsigned int n);
|
||||||
|
|
||||||
|
/* remove all instruction hw breakpoints */
|
||||||
|
int reset_all_hw_bp(struct task *task);
|
||||||
|
|
||||||
/* save the process context (state, registers, stack pointer) */
|
/* save the process context (state, registers, stack pointer) */
|
||||||
int fetch_context(struct task *task);
|
int fetch_context(struct task *task);
|
||||||
|
|
||||||
|
|||||||
24
breakpoint.c
24
breakpoint.c
@ -114,7 +114,7 @@ static int find_hw_bp_slot(struct task *leader)
|
|||||||
|
|
||||||
static void enable_hw_bp(struct task *task, struct breakpoint *bp)
|
static void enable_hw_bp(struct task *task, struct breakpoint *bp)
|
||||||
{
|
{
|
||||||
int slot = bp->hw_bp_slot;
|
unsigned int slot = bp->hw_bp_slot;
|
||||||
|
|
||||||
if (bp->hw_bp_slot != HW_BP_SCRATCH_SLOT)
|
if (bp->hw_bp_slot != HW_BP_SCRATCH_SLOT)
|
||||||
assert(task->hw_bp[slot] == NULL);
|
assert(task->hw_bp[slot] == NULL);
|
||||||
@ -127,7 +127,7 @@ static void enable_hw_bp(struct task *task, struct breakpoint *bp)
|
|||||||
|
|
||||||
void breakpoint_hw_clone(struct task *task)
|
void breakpoint_hw_clone(struct task *task)
|
||||||
{
|
{
|
||||||
int i;
|
unsigned int i;
|
||||||
struct task *leader = task->leader;
|
struct task *leader = task->leader;
|
||||||
|
|
||||||
if (leader == task)
|
if (leader == task)
|
||||||
@ -139,15 +139,21 @@ void breakpoint_hw_clone(struct task *task)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(leader->hw_bp[i]->hw_bp_slot == i);
|
if (leader->hw_bp[i]) {
|
||||||
|
assert(leader->hw_bp[i]->enabled);
|
||||||
|
assert(leader->hw_bp[i]->hw_bp_slot == i);
|
||||||
|
|
||||||
enable_hw_bp(task, leader->hw_bp[i]);
|
enable_hw_bp(task, leader->hw_bp[i]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void disable_hw_bp(struct task *task, struct breakpoint *bp)
|
static void disable_hw_bp(struct task *task, struct breakpoint *bp)
|
||||||
{
|
{
|
||||||
int slot = bp->hw_bp_slot;
|
unsigned int slot = bp->hw_bp_slot;
|
||||||
|
|
||||||
|
if (!task->hw_bp[slot])
|
||||||
|
return;
|
||||||
|
|
||||||
assert(task->hw_bp[slot] == bp);
|
assert(task->hw_bp[slot] == bp);
|
||||||
|
|
||||||
@ -159,15 +165,17 @@ static void disable_hw_bp(struct task *task, struct breakpoint *bp)
|
|||||||
|
|
||||||
void breakpoint_hw_destroy(struct task *task)
|
void breakpoint_hw_destroy(struct task *task)
|
||||||
{
|
{
|
||||||
int i;
|
unsigned int i;
|
||||||
|
|
||||||
for(i = 0; i < HW_BREAKPOINTS; ++i) {
|
for(i = 0; i < HW_BREAKPOINTS; ++i) {
|
||||||
if (task->hw_bp[i]) {
|
if (task->hw_bp[i]) {
|
||||||
assert(task->hw_bp[i]->hw_bp_slot == i);
|
assert(task->hw_bp[i]->hw_bp_slot == i);
|
||||||
|
|
||||||
disable_hw_bp(task, task->hw_bp[i]);
|
task->hw_bp[i] = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
reset_all_hw_bp(task);
|
||||||
}
|
}
|
||||||
|
|
||||||
void enable_scratch_hw_bp(struct task *task, struct breakpoint *bp)
|
void enable_scratch_hw_bp(struct task *task, struct breakpoint *bp)
|
||||||
@ -338,7 +346,7 @@ void breakpoint_delete(struct task *task, struct breakpoint *bp)
|
|||||||
|
|
||||||
#if HW_BREAKPOINTS > 0
|
#if HW_BREAKPOINTS > 0
|
||||||
if (bp->type != SW_BP) {
|
if (bp->type != SW_BP) {
|
||||||
int slot = bp->hw_bp_slot;
|
unsigned int slot = bp->hw_bp_slot;
|
||||||
|
|
||||||
if (bp->type == HW_BP) {
|
if (bp->type == HW_BP) {
|
||||||
assert(slot != HW_BP_SCRATCH_SLOT);
|
assert(slot != HW_BP_SCRATCH_SLOT);
|
||||||
|
|||||||
@ -42,7 +42,7 @@ struct breakpoint {
|
|||||||
union {
|
union {
|
||||||
unsigned char orig_value[BREAKPOINT_LENGTH];
|
unsigned char orig_value[BREAKPOINT_LENGTH];
|
||||||
#if HW_BREAKPOINTS > 0
|
#if HW_BREAKPOINTS > 0
|
||||||
int hw_bp_slot;
|
unsigned int hw_bp_slot;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
104
client/process.c
104
client/process.c
@ -522,6 +522,15 @@ static void process_dump_stack(struct process *process, struct rb_stack *this)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void process_dump_collision(struct process *process, struct rb_block *this, unsigned long addr, unsigned long size, enum mt_operation operation)
|
||||||
|
{
|
||||||
|
fprintf(stderr, ">>> block collision pid:%d\n new: %s=%#lx(%lu)\n old: %s=%#lx(%lu)\n",
|
||||||
|
process->pid,
|
||||||
|
str_operation(operation), addr, size,
|
||||||
|
str_operation(this->stack_node->stack->operation), this->addr, this->size
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
static struct rb_block *process_rb_search_range(struct rb_root *root, unsigned long addr, unsigned long size)
|
static struct rb_block *process_rb_search_range(struct rb_root *root, unsigned long addr, unsigned long size)
|
||||||
{
|
{
|
||||||
struct rb_node *node = root->rb_node;
|
struct rb_node *node = root->rb_node;
|
||||||
@ -589,7 +598,7 @@ static void process_rb_delete_block(struct process *process, struct rb_block *bl
|
|||||||
free(block);
|
free(block);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int process_rb_insert_block(struct process *process, unsigned long addr, unsigned long size, struct rb_stack *stack, unsigned long flags)
|
static int process_rb_insert_block(struct process *process, unsigned long addr, unsigned long size, struct rb_stack *stack, unsigned long flags, enum mt_operation operation)
|
||||||
{
|
{
|
||||||
struct rb_node **new = &process->block_table.rb_node, *parent = NULL;
|
struct rb_node **new = &process->block_table.rb_node, *parent = NULL;
|
||||||
struct rb_block *block;
|
struct rb_block *block;
|
||||||
@ -605,8 +614,15 @@ static int process_rb_insert_block(struct process *process, unsigned long addr,
|
|||||||
|
|
||||||
parent = *new;
|
parent = *new;
|
||||||
|
|
||||||
if (addr <= this->addr && addr + n > this->addr)
|
if (addr <= this->addr && addr + n > this->addr) {
|
||||||
|
if (options.kill || options.verbose > 1) {
|
||||||
|
process_dump_collision(process, this, addr, size, operation);
|
||||||
|
|
||||||
|
if (options.kill)
|
||||||
|
abort();
|
||||||
|
}
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (addr < this->addr)
|
if (addr < this->addr)
|
||||||
new = &((*new)->rb_left);
|
new = &((*new)->rb_left);
|
||||||
@ -776,8 +792,8 @@ static int process_rb_duplicate_block(struct rb_node *node, void *user)
|
|||||||
struct process *process = user;
|
struct process *process = user;
|
||||||
struct rb_stack *stack = stack_clone(process, block->stack_node);
|
struct rb_stack *stack = stack_clone(process, block->stack_node);
|
||||||
|
|
||||||
if (process_rb_insert_block(process, block->addr, block->size, stack, block->flags))
|
if (process_rb_insert_block(process, block->addr, block->size, stack, block->flags, block->stack_node->stack->operation))
|
||||||
abort();
|
return -1;
|
||||||
|
|
||||||
process->bytes_used += block->size;
|
process->bytes_used += block->size;
|
||||||
|
|
||||||
@ -887,24 +903,41 @@ static void _process_dump(struct process *process, int (*sortby)(const struct rb
|
|||||||
unsigned long i;
|
unsigned long i;
|
||||||
void *data;
|
void *data;
|
||||||
|
|
||||||
arr = malloc(sizeof(struct rb_stack *) * process->stack_trees);
|
|
||||||
if (!arr)
|
|
||||||
return;
|
|
||||||
|
|
||||||
for(i = 0, data = rb_first(&process->stack_table); data; data = rb_next(data))
|
|
||||||
arr[i++] = container_of(data, struct rb_stack, node);
|
|
||||||
|
|
||||||
if (dump_init(file) == -1)
|
if (dump_init(file) == -1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
dump_printf("Process dump %d %s\n", process->pid, process->filename ? process->filename : "<unknown>");
|
dump_printf("Process dump %d %s\n", process->pid, process->filename ? process->filename : "<unknown>");
|
||||||
|
|
||||||
|
if (!process->stack_trees)
|
||||||
|
goto skip;
|
||||||
|
|
||||||
|
arr = malloc(sizeof(struct rb_stack *) * process->stack_trees);
|
||||||
|
if (!arr)
|
||||||
|
goto skip;
|
||||||
|
|
||||||
|
for(i = 0, data = rb_first(&process->stack_table); data; data = rb_next(data))
|
||||||
|
arr[i++] = container_of(data, struct rb_stack, node);
|
||||||
|
|
||||||
|
assert(i == process->stack_trees);
|
||||||
|
|
||||||
qsort(arr, process->stack_trees, sizeof(struct stack *), (void *)sortby);
|
qsort(arr, process->stack_trees, sizeof(struct stack *), (void *)sortby);
|
||||||
|
|
||||||
|
if (file == stderr) {
|
||||||
|
unsigned long n = process->stack_trees / 2;
|
||||||
|
unsigned long l = process->stack_trees - 1;
|
||||||
|
|
||||||
|
for(i = 0; i < n; ++i) {
|
||||||
|
struct rb_stack *tmp = arr[i];
|
||||||
|
|
||||||
|
arr[i] = arr[l - i];
|
||||||
|
arr[l - i] = tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for(i = 0; i < process->stack_trees; ++i) {
|
for(i = 0; i < process->stack_trees; ++i) {
|
||||||
struct rb_stack *stack = arr[i];
|
struct rb_stack *stack = arr[i];
|
||||||
|
|
||||||
if (!skipfunc(stack) && !stack->stack->ignore) {
|
if (!stack->stack->ignore && !skipfunc(stack)) {
|
||||||
if (dump_printf(
|
if (dump_printf(
|
||||||
"Stack (%s):\n"
|
"Stack (%s):\n"
|
||||||
" bytes used: %llu\n"
|
" bytes used: %llu\n"
|
||||||
@ -926,6 +959,7 @@ static void _process_dump(struct process *process, int (*sortby)(const struct rb
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
free(arr);
|
free(arr);
|
||||||
|
skip:
|
||||||
dump_flush();
|
dump_flush();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1101,8 +1135,13 @@ void process_munmap(struct process *process, struct mt_msg *mt_msg, void *payloa
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
if (!is_mmap(block->stack_node->stack->operation)) {
|
if (!is_mmap(block->stack_node->stack->operation)) {
|
||||||
fprintf(stderr, ">>> block missmatch MAP<>MALLOC %#lx found\n", ptr);
|
if (options.kill || options.verbose > 1) {
|
||||||
abort();
|
fprintf(stderr, ">>> block missmatch pid:%d MAP<>MALLOC %#lx\n", process->pid, ptr);
|
||||||
|
|
||||||
|
if (options.kill)
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (block->addr >= ptr) {
|
if (block->addr >= ptr) {
|
||||||
@ -1136,8 +1175,8 @@ void process_munmap(struct process *process, struct mt_msg *mt_msg, void *payloa
|
|||||||
|
|
||||||
block->size = off;
|
block->size = off;
|
||||||
|
|
||||||
if (process_rb_insert_block(process, new_addr, new_size, block->stack_node, 0))
|
if (process_rb_insert_block(process, new_addr, new_size, block->stack_node, 0, mt_msg->operation))
|
||||||
abort();
|
break;
|
||||||
|
|
||||||
process->n_allocations++;
|
process->n_allocations++;
|
||||||
process->total_allocations++;
|
process->total_allocations++;
|
||||||
@ -1181,14 +1220,24 @@ 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 (is_mmap(block->stack_node->stack->operation)) {
|
if (is_mmap(block->stack_node->stack->operation)) {
|
||||||
fprintf(stderr, ">>> block missmatch MAP<>MALLOC %#lx found\n", ptr);
|
if (options.kill || options.verbose > 1) {
|
||||||
abort();
|
fprintf(stderr, ">>> block missmatch pid:%d MAP<>MALLOC %#lx\n", process->pid, ptr);
|
||||||
|
|
||||||
|
if (options.kill)
|
||||||
|
abort();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
process_rb_delete_block(process, block);
|
process_rb_delete_block(process, block);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (!process->attached)
|
if (!process->attached) {
|
||||||
fprintf(stderr, ">>> block %#lx not found (pid=%d, tid=%d)\n", ptr, process->pid, mt_msg->tid);
|
if (options.kill || options.verbose > 1) {
|
||||||
|
fprintf(stderr, ">>> block %#lx not found pid:%d tid:%d\n", ptr, process->pid, mt_msg->tid);
|
||||||
|
|
||||||
|
if (options.kill)
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1227,16 +1276,21 @@ 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);
|
debug(DEBUG_FUNCTION, "ptr=%#lx size=%lu stack_size=%lu", ptr, size, stack_size);
|
||||||
|
|
||||||
block = process_rb_search(&process->block_table, ptr);
|
block = process_rb_search_range(&process->block_table, ptr, size);
|
||||||
if (block) {
|
if (block) {
|
||||||
fprintf(stderr, ">>> block collison %s ptr %#lx size %lu pid %d tid %d\n", str_operation(mt_msg->operation), ptr, size, process->pid, mt_msg->tid);
|
if (options.kill || options.verbose > 1) {
|
||||||
abort();
|
process_dump_collision(process, block, ptr, size, mt_msg->operation);
|
||||||
|
|
||||||
|
if (options.kill)
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
process_rb_delete_block(process, block);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct rb_stack *stack = stack_add(process, process->pid, stack_data, stack_size, mt_msg->operation);
|
struct rb_stack *stack = stack_add(process, process->pid, stack_data, stack_size, mt_msg->operation);
|
||||||
|
|
||||||
if (process_rb_insert_block(process, ptr, size, stack, 0))
|
if (process_rb_insert_block(process, ptr, size, stack, 0, mt_msg->operation))
|
||||||
abort();
|
return;
|
||||||
|
|
||||||
process->total_allocations++;
|
process->total_allocations++;
|
||||||
process->bytes_used += size;
|
process->bytes_used += size;
|
||||||
|
|||||||
35
dwarf.c
35
dwarf.c
@ -873,11 +873,8 @@ static int dwarf_extract_cfi_from_fde(struct dwarf_addr_space *as, void *addrp)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int lib_addr_match(struct library *lib, arch_addr_t ip)
|
static inline int lib_addr_match(struct library *lib, arch_addr_t ip)
|
||||||
{
|
{
|
||||||
if (!lib)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return ip >= lib->load_addr && ip < lib->load_addr + lib->load_size;
|
return ip >= lib->load_addr && ip < lib->load_addr + lib->load_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -886,8 +883,10 @@ int dwarf_locate_map(struct dwarf_addr_space *as, arch_addr_t ip)
|
|||||||
struct task *leader;
|
struct task *leader;
|
||||||
struct list_head *it;
|
struct list_head *it;
|
||||||
|
|
||||||
if (lib_addr_match(as->cursor.lib, ip))
|
if (as->cursor.lib) {
|
||||||
return 0;
|
if (lib_addr_match(as->cursor.lib, ip))
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
leader = as->task->leader;
|
leader = as->task->leader;
|
||||||
|
|
||||||
@ -1885,12 +1884,13 @@ int dwarf_step(struct dwarf_addr_space *as)
|
|||||||
int ret;
|
int ret;
|
||||||
struct dwarf_cursor *c = &as->cursor;
|
struct dwarf_cursor *c = &as->cursor;
|
||||||
struct dwarf_reg_state *rs_current;
|
struct dwarf_reg_state *rs_current;
|
||||||
arch_addr_t ip;
|
arch_addr_t ip, cfa;
|
||||||
|
|
||||||
if (!c->valid)
|
if (!c->valid)
|
||||||
return -DWARF_EINVAL;
|
return -DWARF_EINVAL;
|
||||||
|
|
||||||
ip = c->ip;
|
ip = c->ip;
|
||||||
|
cfa = c->cfa;
|
||||||
|
|
||||||
/* The 'ip' can point either to the previous or next instruction
|
/* The 'ip' can point either to the previous or next instruction
|
||||||
depending on what type of frame we have: normal call or a place
|
depending on what type of frame we have: normal call or a place
|
||||||
@ -1935,10 +1935,27 @@ fail:
|
|||||||
debug(DEBUG_DWARF, "try arch specific step");
|
debug(DEBUG_DWARF, "try arch specific step");
|
||||||
|
|
||||||
ret = dwarf_arch_step(as);
|
ret = dwarf_arch_step(as);
|
||||||
if (!ret)
|
if (!ret) {
|
||||||
ret = dwarf_locate_map(as, c->use_prev_instr ? c->ip - 1 : c->ip);
|
if (dwarf_locate_map(as, c->use_prev_instr ? c->ip - 1 : c->ip))
|
||||||
|
ret = -DWARF_ENOINFO;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
for(i = 0; i < 16; ++i) {
|
||||||
|
if (dwarf_readw(as, &cfa, &ip, as->task->is_64bit))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (!dwarf_locate_map(as, ip)) {
|
||||||
|
c->cfa = cfa;
|
||||||
|
c->ip = ip;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
debug(DEBUG_DWARF, "error %d", ret);
|
debug(DEBUG_DWARF, "error %d", ret);
|
||||||
|
|
||||||
c->valid = 0;
|
c->valid = 0;
|
||||||
|
|||||||
@ -90,6 +90,7 @@ static void usage(void)
|
|||||||
" -f, --follow-child trace forked children\n"
|
" -f, --follow-child trace forked children\n"
|
||||||
" -h, --help display this help and exit\n"
|
" -h, --help display this help and exit\n"
|
||||||
" -i, --interactive interactive client mode\n"
|
" -i, --interactive interactive client mode\n"
|
||||||
|
" -k, --kill abort mtrace on unexpected error conditon\n"
|
||||||
" -l, --listen listen on socket path or address in server mode\n"
|
" -l, --listen listen on socket path or address in server mode\n"
|
||||||
" -o, --output=FILE write the trace output to file with given name\n"
|
" -o, --output=FILE write the trace output to file with given name\n"
|
||||||
" -p, --pid=PID attach to the process with the process ID pid (may be repeated)\n"
|
" -p, --pid=PID attach to the process with the process ID pid (may be repeated)\n"
|
||||||
@ -257,6 +258,7 @@ char **process_options(int argc, char **argv)
|
|||||||
options.opt_b = NULL;
|
options.opt_b = NULL;
|
||||||
options.sort_by = -1;
|
options.sort_by = -1;
|
||||||
options.debug = 0;
|
options.debug = 0;
|
||||||
|
options.kill = 0;
|
||||||
|
|
||||||
for(;;) {
|
for(;;) {
|
||||||
int c;
|
int c;
|
||||||
@ -273,6 +275,7 @@ char **process_options(int argc, char **argv)
|
|||||||
{ "follow-child", 0, 0, 'f'},
|
{ "follow-child", 0, 0, 'f'},
|
||||||
{ "follow-exec", 0, 0, 'e' },
|
{ "follow-exec", 0, 0, 'e' },
|
||||||
{ "interactive", 0, 0, 'i' },
|
{ "interactive", 0, 0, 'i' },
|
||||||
|
{ "kill", 0, 0, 'k' },
|
||||||
{ "listen", 1, 0, 'l' },
|
{ "listen", 1, 0, 'l' },
|
||||||
{ "output", 1, 0, 'o' },
|
{ "output", 1, 0, 'o' },
|
||||||
{ "pid", 1, 0, 'p' },
|
{ "pid", 1, 0, 'p' },
|
||||||
@ -286,7 +289,7 @@ char **process_options(int argc, char **argv)
|
|||||||
{ 0, 0, 0, 0 }
|
{ 0, 0, 0, 0 }
|
||||||
};
|
};
|
||||||
c = getopt_long(argc, argv,
|
c = getopt_long(argc, argv,
|
||||||
"+aefhisVvw"
|
"+aefhiksVvw"
|
||||||
"b:c:C:D:F:l:o:p:P:u:d:S:",
|
"b:c:C:D:F:l:o:p:P:u:d:S:",
|
||||||
long_options,
|
long_options,
|
||||||
&option_index);
|
&option_index);
|
||||||
@ -412,6 +415,9 @@ char **process_options(int argc, char **argv)
|
|||||||
case 'e':
|
case 'e':
|
||||||
options.follow_exec = 1;
|
options.follow_exec = 1;
|
||||||
break;
|
break;
|
||||||
|
case 'k':
|
||||||
|
options.kill = 1;
|
||||||
|
break;
|
||||||
case 'v':
|
case 'v':
|
||||||
options.verbose++;
|
options.verbose++;
|
||||||
break;
|
break;
|
||||||
|
|||||||
@ -65,6 +65,7 @@ struct options_t {
|
|||||||
int interactive; /* interactive mode */
|
int interactive; /* interactive mode */
|
||||||
FILE *output; /* output to a specific file */
|
FILE *output; /* output to a specific file */
|
||||||
int server; /* server mode flag */
|
int server; /* server mode flag */
|
||||||
|
int kill; /* kill on errors */
|
||||||
char *listen; /* server listen on socket path or address */
|
char *listen; /* server listen on socket path or address */
|
||||||
char *client; /* connect to socket path or address */
|
char *client; /* connect to socket path or address */
|
||||||
char *user; /* -u: username to run command as */
|
char *user; /* -u: username to run command as */
|
||||||
|
|||||||
23
report.c
23
report.c
@ -307,6 +307,13 @@ static int _report_pvalloc(struct task *task, struct library_symbol *libsym)
|
|||||||
return report_alloc(task, MT_PVALLOC, ret, len, options.bt_depth);
|
return report_alloc(task, MT_PVALLOC, ret, len, options.bt_depth);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int report_ni(struct task *task, struct library_symbol *libsym)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "%s not implemented!!!\n", libsym->func->name);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static const struct function flist[] = {
|
static const struct function flist[] = {
|
||||||
{ "malloc", 2, NULL, _report_malloc },
|
{ "malloc", 2, NULL, _report_malloc },
|
||||||
{ "free", 3, report_free, NULL },
|
{ "free", 3, report_free, NULL },
|
||||||
@ -320,8 +327,24 @@ static const struct function flist[] = {
|
|||||||
{ "aligned_alloc", 11, NULL, _report_aligned_alloc },
|
{ "aligned_alloc", 11, NULL, _report_aligned_alloc },
|
||||||
{ "valloc", 12, NULL, _report_valloc },
|
{ "valloc", 12, NULL, _report_valloc },
|
||||||
{ "pvalloc", 13, NULL, _report_pvalloc },
|
{ "pvalloc", 13, NULL, _report_pvalloc },
|
||||||
|
{ "mremap", 14, report_ni, NULL },
|
||||||
#if 0
|
#if 0
|
||||||
{ "cfree", 14, report_free, NULL },
|
{ "cfree", 14, report_free, NULL },
|
||||||
|
{ "vfree", 14, report_free, NULL },
|
||||||
|
#endif
|
||||||
|
#if 1
|
||||||
|
/*
|
||||||
|
* support for Google gperftools
|
||||||
|
* the c++ operators new and delete do not call malloc() and free()
|
||||||
|
*/
|
||||||
|
{ "tc_delete", 14, report_free, NULL },
|
||||||
|
{ "tc_deletearray", 14, report_free, NULL },
|
||||||
|
{ "tc_deletearray_nothrow", 14, report_free, NULL },
|
||||||
|
{ "tc_delete_nothrow", 14, report_free, NULL },
|
||||||
|
{ "tc_new", 14, NULL, _report_malloc },
|
||||||
|
{ "tc_newarray", 14, NULL, _report_malloc },
|
||||||
|
{ "tc_newarray_nothrow", 14, NULL, _report_malloc },
|
||||||
|
{ "tc_new_nothrow", 14, NULL, _report_malloc },
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -219,7 +219,7 @@ static void process_event(struct task *task, int status)
|
|||||||
int stop_signal;
|
int stop_signal;
|
||||||
struct task *leader = task->leader;
|
struct task *leader = task->leader;
|
||||||
struct breakpoint *bp = NULL;
|
struct breakpoint *bp = NULL;
|
||||||
int i;
|
unsigned int i;
|
||||||
arch_addr_t ip;
|
arch_addr_t ip;
|
||||||
|
|
||||||
assert(leader != NULL);
|
assert(leader != NULL);
|
||||||
|
|||||||
@ -31,15 +31,37 @@
|
|||||||
#include "task.h"
|
#include "task.h"
|
||||||
|
|
||||||
/* Breakpoint access modes */
|
/* Breakpoint access modes */
|
||||||
enum {
|
#define BP_X 1
|
||||||
BP_X = 1,
|
#define BP_RW 2
|
||||||
BP_RW = 2,
|
#define BP_W 4
|
||||||
BP_W = 4,
|
|
||||||
};
|
|
||||||
|
|
||||||
static int set_breakpoint_addr(struct task *task, arch_addr_t addr, int n)
|
static int _apply_hw_bp(struct task *task, uint32_t dr7)
|
||||||
{
|
{
|
||||||
int ret;
|
long ret;
|
||||||
|
|
||||||
|
task->arch.dr7 = dr7;
|
||||||
|
|
||||||
|
ret = ptrace(PTRACE_POKEUSER, task->pid, offsetof(struct user, u_debugreg[7]), task->arch.dr7);
|
||||||
|
if (ret) {
|
||||||
|
if (errno != ESRCH) {
|
||||||
|
fprintf(stderr, "PTRACE_POKEUSER u_debugreg[7] pid=%d %s\n", task->pid, strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int apply_hw_bp(struct task *task, uint32_t dr7)
|
||||||
|
{
|
||||||
|
if (dr7 == task->arch.dr7)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return _apply_hw_bp(task, dr7);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int set_breakpoint_addr(struct task *task, arch_addr_t addr, unsigned int n)
|
||||||
|
{
|
||||||
|
long ret;
|
||||||
|
|
||||||
#ifdef __x86_64__
|
#ifdef __x86_64__
|
||||||
if (!task->is_64bit)
|
if (!task->is_64bit)
|
||||||
@ -56,9 +78,8 @@ static int set_breakpoint_addr(struct task *task, arch_addr_t addr, int n)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int set_breakpoint_mode(struct task *task, int n, int type, int len, int local, int global)
|
static int set_breakpoint_mode(struct task *task, unsigned int n, int type, int len, int local, int global)
|
||||||
{
|
{
|
||||||
long ret;
|
|
||||||
uint32_t mode;
|
uint32_t mode;
|
||||||
uint32_t dr7, mask;
|
uint32_t dr7, mask;
|
||||||
|
|
||||||
@ -114,25 +135,15 @@ static int set_breakpoint_mode(struct task *task, int n, int type, int len, int
|
|||||||
if (!(dr7 & 0b10101010))
|
if (!(dr7 & 0b10101010))
|
||||||
dr7 &= ~(1 << 9);
|
dr7 &= ~(1 << 9);
|
||||||
|
|
||||||
if (dr7 != task->arch.dr7) {
|
return apply_hw_bp(task, dr7);
|
||||||
task->arch.dr7 = dr7;
|
|
||||||
|
|
||||||
ret = ptrace(PTRACE_POKEUSER, task->pid, offsetof(struct user, u_debugreg[7]), task->arch.dr7);
|
|
||||||
if (ret) {
|
|
||||||
if (errno != ESRCH) {
|
|
||||||
fprintf(stderr, "PTRACE_POKEUSER u_debugreg[7] pid=%d %s\n", task->pid, strerror(errno));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int set_hw_bp(struct task *task, unsigned int n, arch_addr_t addr)
|
int set_hw_bp(struct task *task, unsigned int n, arch_addr_t addr)
|
||||||
{
|
{
|
||||||
|
#if 0
|
||||||
if (reset_hw_bp(task, n) == -1)
|
if (reset_hw_bp(task, n) == -1)
|
||||||
return -1;
|
return -1;
|
||||||
|
#endif
|
||||||
if (set_breakpoint_addr(task, addr, n) == -1)
|
if (set_breakpoint_addr(task, addr, n) == -1)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
@ -147,7 +158,6 @@ int set_hw_bp(struct task *task, unsigned int n, arch_addr_t addr)
|
|||||||
|
|
||||||
int reset_hw_bp(struct task *task, unsigned int n)
|
int reset_hw_bp(struct task *task, unsigned int n)
|
||||||
{
|
{
|
||||||
long ret;
|
|
||||||
uint32_t dr7, mask;
|
uint32_t dr7, mask;
|
||||||
|
|
||||||
mask = (0b1111 << (16 + 4 * n)) | (0b11 << (2 * n));
|
mask = (0b1111 << (16 + 4 * n)) | (0b11 << (2 * n));
|
||||||
@ -160,18 +170,12 @@ int reset_hw_bp(struct task *task, unsigned int n)
|
|||||||
if (!(dr7 & 0b10101010))
|
if (!(dr7 & 0b10101010))
|
||||||
dr7 &= ~(1 << 9);
|
dr7 &= ~(1 << 9);
|
||||||
|
|
||||||
if (dr7 != task->arch.dr7) {
|
return apply_hw_bp(task, dr7);
|
||||||
task->arch.dr7 = dr7;
|
}
|
||||||
|
|
||||||
ret = ptrace(PTRACE_POKEUSER, task->pid, offsetof(struct user, u_debugreg[7]), task->arch.dr7);
|
int reset_all_hw_bp(struct task *task)
|
||||||
if (ret) {
|
{
|
||||||
if (errno != ESRCH) {
|
return apply_hw_bp(task, 0);
|
||||||
fprintf(stderr, "PTRACE_POKEUSER u_debugreg[7] pid=%d %s\n", task->pid, strerror(errno));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int is_64bit(struct mt_elf *mte)
|
int is_64bit(struct mt_elf *mte)
|
||||||
@ -181,28 +185,12 @@ int is_64bit(struct mt_elf *mte)
|
|||||||
|
|
||||||
int arch_task_init(struct task *task)
|
int arch_task_init(struct task *task)
|
||||||
{
|
{
|
||||||
long ret;
|
return _apply_hw_bp(task, 0);
|
||||||
int i;
|
|
||||||
|
|
||||||
ret = ptrace(PTRACE_PEEKUSER, task->pid, offsetof(struct user, u_debugreg[7]), 0);
|
|
||||||
if (ret == -1 && errno) {
|
|
||||||
if (errno != ESRCH) {
|
|
||||||
fatal("PTRACE_PEEKUSER u_debugreg[7] pid=%d %s\n", task->pid, strerror(errno));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
task->arch.dr7 = ret;
|
|
||||||
|
|
||||||
for(i = 0; i < HW_BREAKPOINTS; ++i)
|
|
||||||
reset_hw_bp(task, i);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void arch_task_destroy(struct task *task)
|
void arch_task_destroy(struct task *task)
|
||||||
{
|
{
|
||||||
|
apply_hw_bp(task, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
int arch_task_clone(struct task *retp, struct task *task)
|
int arch_task_clone(struct task *retp, struct task *task)
|
||||||
|
|||||||
5
task.c
5
task.c
@ -43,7 +43,6 @@
|
|||||||
#include "library.h"
|
#include "library.h"
|
||||||
#include "mtelf.h"
|
#include "mtelf.h"
|
||||||
#include "report.h"
|
#include "report.h"
|
||||||
#include "server.h"
|
|
||||||
#include "task.h"
|
#include "task.h"
|
||||||
#include "trace.h"
|
#include "trace.h"
|
||||||
|
|
||||||
@ -199,7 +198,6 @@ static void leader_cleanup(struct task *task)
|
|||||||
|
|
||||||
static void task_destroy(struct task *task)
|
static void task_destroy(struct task *task)
|
||||||
{
|
{
|
||||||
breakpoint_hw_destroy(task);
|
|
||||||
backtrace_destroy(task);
|
backtrace_destroy(task);
|
||||||
arch_task_destroy(task);
|
arch_task_destroy(task);
|
||||||
os_task_destroy(task);
|
os_task_destroy(task);
|
||||||
@ -323,8 +321,7 @@ int task_clone(struct task *task, struct task *newtask)
|
|||||||
if (backtrace_init(newtask) < 0)
|
if (backtrace_init(newtask) < 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
if (server_connected())
|
breakpoint_hw_clone(newtask);
|
||||||
breakpoint_hw_clone(newtask);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
fail:
|
fail:
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user