mirror of
https://github.com/sstefani/mtrace.git
synced 2025-12-06 08:46:41 +08:00
clean up, option for invalid free releases
This commit is contained in:
parent
3e2980613c
commit
3b7a0d0552
@ -383,7 +383,7 @@ struct breakpoint *breakpoint_new_ext(struct task *task, arch_addr_t addr, struc
|
|||||||
case BP_AUTO:
|
case BP_AUTO:
|
||||||
case BP_HW:
|
case BP_HW:
|
||||||
#if HW_BREAKPOINTS > 1
|
#if HW_BREAKPOINTS > 1
|
||||||
list_add_tail(&bp->link_list, &leader->hw_bp_list);
|
list_add_tail(&bp->link_list, &leader->hw_bp_list);
|
||||||
leader->hw_bp_num++;
|
leader->hw_bp_num++;
|
||||||
#endif
|
#endif
|
||||||
case BP_SW:
|
case BP_SW:
|
||||||
|
|||||||
@ -202,7 +202,7 @@ static int parse_config(const char *filename)
|
|||||||
char *p;
|
char *p;
|
||||||
struct stat statbuf;
|
struct stat statbuf;
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
fd = open(filename, O_RDONLY);
|
fd = open(filename, O_RDONLY);
|
||||||
if (fd == -1)
|
if (fd == -1)
|
||||||
fatal("could not open config file: `%s' (%s)", filename, strerror(errno));
|
fatal("could not open config file: `%s' (%s)", filename, strerror(errno));
|
||||||
@ -248,10 +248,10 @@ static struct process *pid_rb_delete(struct rb_root *root, unsigned int pid)
|
|||||||
|
|
||||||
if (data) {
|
if (data) {
|
||||||
process = data->process;
|
process = data->process;
|
||||||
|
|
||||||
rb_erase(&data->node, root);
|
rb_erase(&data->node, root);
|
||||||
free(data);
|
free(data);
|
||||||
|
|
||||||
return process;
|
return process;
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -807,7 +807,7 @@ int client_send_msg(struct process *process, enum mt_operation op, void *payload
|
|||||||
|
|
||||||
ret = sock_send_msg(client_fd, process->val16(op), process->pid, payload, payload_len);
|
ret = sock_send_msg(client_fd, process->val16(op), process->pid, payload, payload_len);
|
||||||
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
client_broken();
|
client_broken();
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -112,7 +112,7 @@ static int dump_pager(void)
|
|||||||
struct termios termios_old;
|
struct termios termios_old;
|
||||||
int len;
|
int len;
|
||||||
ioevent_func oldfunc;
|
ioevent_func oldfunc;
|
||||||
|
|
||||||
len = printf("Press <space> for next line, q for quit and any other for next page\r") - 1;
|
len = printf("Press <space> for next line, q for quit and any other for next page\r") - 1;
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
|
|
||||||
@ -194,7 +194,7 @@ static int dump_line(char *s, int n)
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int dump_printf(const char *fmt, ...)
|
int dump_printf(const char *fmt, ...)
|
||||||
{
|
{
|
||||||
char *str;
|
char *str;
|
||||||
|
|||||||
115
client/process.c
115
client/process.c
@ -72,6 +72,7 @@ struct rb_stack {
|
|||||||
unsigned long long bytes_leaked;
|
unsigned long long bytes_leaked;
|
||||||
unsigned long long tsc;
|
unsigned long long tsc;
|
||||||
unsigned long long n_mismatched;
|
unsigned long long n_mismatched;
|
||||||
|
unsigned long long n_badfree;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct map {
|
struct map {
|
||||||
@ -460,6 +461,7 @@ static struct rb_stack *stack_clone(struct process *process, struct rb_stack *st
|
|||||||
this->leaks = stack_node->leaks;
|
this->leaks = stack_node->leaks;
|
||||||
this->n_allocations = stack_node->n_allocations;
|
this->n_allocations = stack_node->n_allocations;
|
||||||
this->n_mismatched = stack_node->n_mismatched;
|
this->n_mismatched = stack_node->n_mismatched;
|
||||||
|
this->n_badfree = stack_node->n_badfree;
|
||||||
this->total_allocations = stack_node->total_allocations;
|
this->total_allocations = stack_node->total_allocations;
|
||||||
this->bytes_used = stack_node->bytes_used;
|
this->bytes_used = stack_node->bytes_used;
|
||||||
this->bytes_leaked = stack_node->bytes_leaked;
|
this->bytes_leaked = stack_node->bytes_leaked;
|
||||||
@ -527,6 +529,7 @@ static struct rb_stack *stack_add(struct process *process, unsigned int pid, voi
|
|||||||
this->refcnt = 0;
|
this->refcnt = 0;
|
||||||
this->n_allocations = 0;
|
this->n_allocations = 0;
|
||||||
this->n_mismatched = 0;
|
this->n_mismatched = 0;
|
||||||
|
this->n_badfree = 0;
|
||||||
this->total_allocations = 0;
|
this->total_allocations = 0;
|
||||||
this->bytes_used = 0;
|
this->bytes_used = 0;
|
||||||
this->leaks = 0;
|
this->leaks = 0;
|
||||||
@ -924,7 +927,16 @@ static int sort_tsc(const struct rb_stack **p, const struct rb_stack **q)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sort_mismatched(const struct rb_stack **p, const struct rb_stack **q)
|
static int _sort_badfree(const struct rb_stack **p, const struct rb_stack **q)
|
||||||
|
{
|
||||||
|
if ((*p)->n_badfree > (*q)->n_badfree)
|
||||||
|
return -1;
|
||||||
|
if ((*p)->n_badfree < (*q)->n_badfree)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _sort_mismatched(const struct rb_stack **p, const struct rb_stack **q)
|
||||||
{
|
{
|
||||||
if ((*p)->n_mismatched > (*q)->n_mismatched)
|
if ((*p)->n_mismatched > (*q)->n_mismatched)
|
||||||
return -1;
|
return -1;
|
||||||
@ -933,6 +945,26 @@ static int sort_mismatched(const struct rb_stack **p, const struct rb_stack **q)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int sort_badfree(const struct rb_stack **p, const struct rb_stack **q)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = _sort_badfree(p, q);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
return _sort_mismatched(p, q);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sort_mismatched(const struct rb_stack **p, const struct rb_stack **q)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = _sort_mismatched(p, q);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
return _sort_badfree(p, q);
|
||||||
|
}
|
||||||
|
|
||||||
static int sort_usage(const struct rb_stack **p, const struct rb_stack **q)
|
static int sort_usage(const struct rb_stack **p, const struct rb_stack **q)
|
||||||
{
|
{
|
||||||
if ((*p)->bytes_used > (*q)->bytes_used)
|
if ((*p)->bytes_used > (*q)->bytes_used)
|
||||||
@ -1047,7 +1079,18 @@ static void _process_dump(struct process *process, int (*sortby)(const struct rb
|
|||||||
struct rb_stack *stack = arr[i];
|
struct rb_stack *stack = arr[i];
|
||||||
|
|
||||||
if (!skipfunc(stack)) {
|
if (!skipfunc(stack)) {
|
||||||
if (!stack->n_mismatched) {
|
if (stack->n_mismatched || stack->n_badfree) {
|
||||||
|
if (dump_printf(
|
||||||
|
"Stack (%s):\n"
|
||||||
|
" total number of mismatches: %llu\n"
|
||||||
|
" total number of bad free: %llu\n",
|
||||||
|
str_operation(stack->stack->operation),
|
||||||
|
stack->n_mismatched,
|
||||||
|
stack->n_badfree
|
||||||
|
) == -1)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else {
|
||||||
if (dump_printf(
|
if (dump_printf(
|
||||||
"Stack (%s):\n"
|
"Stack (%s):\n"
|
||||||
" bytes used: %llu\n"
|
" bytes used: %llu\n"
|
||||||
@ -1065,15 +1108,6 @@ static void _process_dump(struct process *process, int (*sortby)(const struct rb
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
if (dump_printf(
|
|
||||||
"Stack (%s):\n"
|
|
||||||
" total number of mismatches: %llu\n",
|
|
||||||
str_operation(stack->stack->operation),
|
|
||||||
stack->n_mismatched
|
|
||||||
) == -1)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dump_printf(" tsc: %llu\n", stack->tsc) == -1)
|
if (dump_printf(" tsc: %llu\n", stack->tsc) == -1)
|
||||||
break;
|
break;
|
||||||
@ -1118,11 +1152,6 @@ static int skip_zero_allocations(struct rb_stack *stack)
|
|||||||
return !stack->n_allocations;
|
return !stack->n_allocations;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int skip_non_mismatched(struct rb_stack *stack)
|
|
||||||
{
|
|
||||||
return !stack->n_mismatched;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int skip_zero_leaks(struct rb_stack *stack)
|
static int skip_zero_leaks(struct rb_stack *stack)
|
||||||
{
|
{
|
||||||
return !stack->leaks;
|
return !stack->leaks;
|
||||||
@ -1165,7 +1194,12 @@ void process_dump_sort_tsc(struct process *process, const char *outfile, int lfl
|
|||||||
|
|
||||||
void process_dump_sort_mismatched(struct process *process, const char *outfile, int lflag)
|
void process_dump_sort_mismatched(struct process *process, const char *outfile, int lflag)
|
||||||
{
|
{
|
||||||
process_dump(process, sort_mismatched, skip_non_mismatched, outfile, lflag);
|
process_dump(process, sort_mismatched, skip_none, outfile, lflag);
|
||||||
|
}
|
||||||
|
|
||||||
|
void process_dump_sort_badfree(struct process *process, const char *outfile, int lflag)
|
||||||
|
{
|
||||||
|
process_dump(process, sort_badfree, skip_none, outfile, lflag);
|
||||||
}
|
}
|
||||||
|
|
||||||
void process_dump_stacks(struct process *process, const char *outfile, int lflag)
|
void process_dump_stacks(struct process *process, const char *outfile, int lflag)
|
||||||
@ -1260,10 +1294,10 @@ 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 pid:%d MAP<>MALLOC %#lx\n", process->pid, ptr);
|
if (unlikely(options.kill)) {
|
||||||
|
fprintf(stderr, ">>> block missmatch pid:%d MAP<>MALLOC %#lx\n", process->pid, ptr);
|
||||||
if (unlikely(options.kill))
|
|
||||||
abort();
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1388,17 +1422,19 @@ 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 pid:%d MAP<>MALLOC %#lx\n", process->pid, ptr);
|
if (unlikely(options.kill)) {
|
||||||
|
fprintf(stderr, ">>> block missmatch pid:%d MAP<>MALLOC %#lx\n", process->pid, ptr);
|
||||||
if (unlikely(options.kill))
|
|
||||||
abort();
|
abort();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!is_sane(block, mt_msg->operation)) {
|
if (stack_size) {
|
||||||
struct rb_stack *stack = stack_add(process, process->pid, stack_data, stack_size, mt_msg->operation);
|
if (!is_sane(block, mt_msg->operation)) {
|
||||||
|
struct rb_stack *stack = stack_add(process, process->pid, stack_data, stack_size, mt_msg->operation);
|
||||||
|
|
||||||
stack->n_mismatched++;
|
stack->n_mismatched++;
|
||||||
stack->tsc = process->tsc++;
|
stack->tsc = process->tsc++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mt_msg->operation == MT_REALLOC_ENTER) {
|
if (mt_msg->operation == MT_REALLOC_ENTER) {
|
||||||
@ -1420,10 +1456,17 @@ void process_free(struct process *process, struct mt_msg *mt_msg, void *payload)
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (!process->attached) {
|
if (!process->attached) {
|
||||||
fprintf(stderr, ">>> block %#lx not found pid:%d\n", ptr, process->pid);
|
if (unlikely(options.kill)) {
|
||||||
|
fprintf(stderr, ">>> block %#lx not found pid:%d\n", ptr, process->pid);
|
||||||
if (unlikely(options.kill))
|
|
||||||
abort();
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stack_size) {
|
||||||
|
struct rb_stack *stack = stack_add(process, process->pid, stack_data, stack_size, mt_msg->operation);
|
||||||
|
|
||||||
|
stack->n_badfree++;
|
||||||
|
stack->tsc = process->tsc++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1464,7 +1507,10 @@ void process_realloc_done(struct process *process, struct mt_msg *mt_msg, void *
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// fprintf(stderr, ">>> unexpected realloc done pid: %u\n", pid);
|
if (unlikely(options.kill)) {
|
||||||
|
fprintf(stderr, ">>> unexpected realloc done pid: %u\n", pid);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1579,7 +1625,10 @@ void process_dump_sortby(struct process *process)
|
|||||||
_process_dump(process, sort_usage, skip_zero_allocations, options.output, options.lflag);
|
_process_dump(process, sort_usage, skip_zero_allocations, options.output, options.lflag);
|
||||||
break;
|
break;
|
||||||
case OPT_SORT_MISMATCHED:
|
case OPT_SORT_MISMATCHED:
|
||||||
_process_dump(process, sort_mismatched, skip_non_mismatched, options.output, options.lflag);
|
_process_dump(process, sort_mismatched, skip_none, options.output, options.lflag);
|
||||||
|
break;
|
||||||
|
case OPT_SORT_BADFREE:
|
||||||
|
_process_dump(process, sort_badfree, skip_none, options.output, options.lflag);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
_process_dump(process, sort_allocations, skip_zero_allocations, options.output, options.lflag);
|
_process_dump(process, sort_allocations, skip_zero_allocations, options.output, options.lflag);
|
||||||
@ -1688,7 +1737,7 @@ struct block_helper {
|
|||||||
unsigned long mask;
|
unsigned long mask;
|
||||||
unsigned long fmask;
|
unsigned long fmask;
|
||||||
unsigned long fmode;
|
unsigned long fmode;
|
||||||
void * data;
|
void * data;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void set_block(struct rb_block *block, void *data)
|
static void set_block(struct rb_block *block, void *data)
|
||||||
|
|||||||
@ -112,6 +112,7 @@ void process_dump_sort_allocations(struct process *process, const char *outfile,
|
|||||||
void process_dump_sort_total(struct process *process, const char *outfile, int lflag);
|
void process_dump_sort_total(struct process *process, const char *outfile, int lflag);
|
||||||
void process_dump_sort_tsc(struct process *process, const char *outfile, int lflag);
|
void process_dump_sort_tsc(struct process *process, const char *outfile, int lflag);
|
||||||
void process_dump_sort_mismatched(struct process *process, const char *outfile, int lflag);
|
void process_dump_sort_mismatched(struct process *process, const char *outfile, int lflag);
|
||||||
|
void process_dump_sort_badfree(struct process *process, const char *outfile, int lflag);
|
||||||
void process_dump_stacks(struct process *process, const char *outfile, int lflag);
|
void process_dump_stacks(struct process *process, const char *outfile, int lflag);
|
||||||
|
|
||||||
void add_ignore_regex(regex_t *re);
|
void add_ignore_regex(regex_t *re);
|
||||||
|
|||||||
@ -92,6 +92,7 @@ static int quit;
|
|||||||
static struct cmd_opt dump_opts[] = {
|
static struct cmd_opt dump_opts[] = {
|
||||||
{ "allocations", 2, process_dump_sort_allocations, "sort by number of open allocations" },
|
{ "allocations", 2, process_dump_sort_allocations, "sort by number of open allocations" },
|
||||||
{ "average", 2, process_dump_sort_average, "sort by average allocation of bytes (usage / allocations)" },
|
{ "average", 2, process_dump_sort_average, "sort by average allocation of bytes (usage / allocations)" },
|
||||||
|
{ "badfree", 1, process_dump_sort_badfree, "sort by number of badfree releases" },
|
||||||
{ "bytes-leaked", 1, process_dump_sort_bytes_leaked, "sort by number of leaked bytes" },
|
{ "bytes-leaked", 1, process_dump_sort_bytes_leaked, "sort by number of leaked bytes" },
|
||||||
{ "leaks", 1, process_dump_sort_leaks, "sort by number of detected leaks" },
|
{ "leaks", 1, process_dump_sort_leaks, "sort by number of detected leaks" },
|
||||||
{ "mismatched", 1, process_dump_sort_mismatched, "sort by number of mismatched releases" },
|
{ "mismatched", 1, process_dump_sort_mismatched, "sort by number of mismatched releases" },
|
||||||
@ -170,7 +171,7 @@ static struct cmd_opt cmds[] = {
|
|||||||
{
|
{
|
||||||
set_str,
|
set_str,
|
||||||
2,
|
2,
|
||||||
do_set,
|
do_set,
|
||||||
"change settings",
|
"change settings",
|
||||||
"<option> [arg]",
|
"<option> [arg]",
|
||||||
set_opts
|
set_opts
|
||||||
@ -178,7 +179,7 @@ static struct cmd_opt cmds[] = {
|
|||||||
{
|
{
|
||||||
show_str,
|
show_str,
|
||||||
2,
|
2,
|
||||||
do_show,
|
do_show,
|
||||||
"show settings",
|
"show settings",
|
||||||
"<option> [arg]",
|
"<option> [arg]",
|
||||||
show_opts
|
show_opts
|
||||||
@ -356,7 +357,7 @@ static void readline_handler(char *line)
|
|||||||
|
|
||||||
s = linedup;
|
s = linedup;
|
||||||
i = 0;
|
i = 0;
|
||||||
|
|
||||||
for(;;) {
|
for(;;) {
|
||||||
s = skip_spaces(s);
|
s = skip_spaces(s);
|
||||||
if (!*s)
|
if (!*s)
|
||||||
@ -616,7 +617,7 @@ static int do_help(struct cmd_opt *cmd, int argc, const char *argv[])
|
|||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
unsigned int len;
|
unsigned int len;
|
||||||
|
|
||||||
if (argc <= 1) {
|
if (argc <= 1) {
|
||||||
for(i = 0; i != ARRAY_SIZE(cmds) - 1; ++i)
|
for(i = 0; i != ARRAY_SIZE(cmds) - 1; ++i)
|
||||||
printf(" %s - %s\n", cmds[i].name, cmds[i].info);
|
printf(" %s - %s\n", cmds[i].name, cmds[i].info);
|
||||||
|
|||||||
2
dwarf.c
2
dwarf.c
@ -495,7 +495,7 @@ static int dwarf_read_encoded_pointer(struct dwarf_addr_space *as, int local,
|
|||||||
valp = &val;
|
valp = &val;
|
||||||
tmp_ptr = NULL;
|
tmp_ptr = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (local)
|
if (local)
|
||||||
as = NULL;
|
as = NULL;
|
||||||
|
|
||||||
|
|||||||
2
event.c
2
event.c
@ -259,7 +259,7 @@ static void handle_breakpoint(struct task *task)
|
|||||||
{
|
{
|
||||||
struct breakpoint *bp = task->event.e_un.breakpoint;
|
struct breakpoint *bp = task->event.e_un.breakpoint;
|
||||||
unsigned int hw = bp->hw;
|
unsigned int hw = bp->hw;
|
||||||
|
|
||||||
debug(DEBUG_FUNCTION, "pid=%d, addr=%#lx", task->pid, bp->addr);
|
debug(DEBUG_FUNCTION, "pid=%d, addr=%#lx", task->pid, bp->addr);
|
||||||
|
|
||||||
if (unlikely(options.verbose > 1))
|
if (unlikely(options.verbose > 1))
|
||||||
|
|||||||
@ -265,9 +265,6 @@ static struct library *_library_add(struct task *leader, struct libref *libref)
|
|||||||
|
|
||||||
struct library *lib = malloc(sizeof(*lib));
|
struct library *lib = malloc(sizeof(*lib));
|
||||||
|
|
||||||
if (lib == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
memset(lib, 0, sizeof(*lib));
|
memset(lib, 0, sizeof(*lib));
|
||||||
|
|
||||||
lib->libref = libref_get(libref);
|
lib->libref = libref_get(libref);
|
||||||
|
|||||||
2
list.h
2
list.h
@ -212,7 +212,7 @@ static inline void list_splice_init(struct list_head *list,
|
|||||||
*/
|
*/
|
||||||
#define list_for_each(pos, head) \
|
#define list_for_each(pos, head) \
|
||||||
for (pos = (head)->next; prefetch(pos->next), pos != (head); \
|
for (pos = (head)->next; prefetch(pos->next), pos != (head); \
|
||||||
pos = pos->next)
|
pos = pos->next)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* list_for_each_safe - iterate over a list safe against removal of list entry
|
* list_for_each_safe - iterate over a list safe against removal of list entry
|
||||||
|
|||||||
2
main.c
2
main.c
@ -110,7 +110,7 @@ static void mtrace_init(char **cmd_args)
|
|||||||
|
|
||||||
if (options.command) {
|
if (options.command) {
|
||||||
struct task *task = task_create(cmd_args);
|
struct task *task = task_create(cmd_args);
|
||||||
|
|
||||||
if (!task)
|
if (!task)
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
|
|
||||||
|
|||||||
4
mtelf.c
4
mtelf.c
@ -370,7 +370,7 @@ static int elf_read(struct mt_elf *mte, struct task *task, const char *filename,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mte->dyn_addr = shdr.sh_addr + bias;
|
mte->dyn_addr = shdr.sh_addr + bias;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -448,7 +448,7 @@ static arch_addr_t find_solib_break(struct mt_elf *mte)
|
|||||||
{
|
{
|
||||||
if (mte->symtab && mte->strtab) {
|
if (mte->symtab && mte->strtab) {
|
||||||
arch_addr_t addr = _find_solib_break(mte, mte->symtab, mte->strtab, mte->symtab_count);
|
arch_addr_t addr = _find_solib_break(mte, mte->symtab, mte->strtab, mte->symtab_count);
|
||||||
|
|
||||||
if (addr)
|
if (addr)
|
||||||
return addr;
|
return addr;
|
||||||
}
|
}
|
||||||
|
|||||||
14
mtrace-ng.1
14
mtrace-ng.1
@ -165,6 +165,8 @@ void operator delete(void* p) __THROW
|
|||||||
void operator delete(void* p, const std::nothrow_t& nt) __THROW
|
void operator delete(void* p, const std::nothrow_t& nt) __THROW
|
||||||
void operator delete[](void* p) __THROW
|
void operator delete[](void* p) __THROW
|
||||||
void operator delete[](void* p, const std::nothrow_t& nt) __THROW
|
void operator delete[](void* p, const std::nothrow_t& nt) __THROW
|
||||||
|
void operator delete(void*, unsigned long)
|
||||||
|
void operator delete[](void*, unsigned long)
|
||||||
.fi
|
.fi
|
||||||
.in
|
.in
|
||||||
.PP
|
.PP
|
||||||
@ -306,6 +308,12 @@ Sort by the number of average allocations (number of bytes in used / number of o
|
|||||||
.RE
|
.RE
|
||||||
.RE
|
.RE
|
||||||
.RS
|
.RS
|
||||||
|
\fIbadfree\fR
|
||||||
|
.RS
|
||||||
|
Sort by number of bad free releases (only useful with \-S option).
|
||||||
|
.RE
|
||||||
|
.RE
|
||||||
|
.RS
|
||||||
\fIbytes-leaked\fR
|
\fIbytes-leaked\fR
|
||||||
.RS
|
.RS
|
||||||
Sort by number of bytes leaked (only useful with \-a option).
|
Sort by number of bytes leaked (only useful with \-a option).
|
||||||
@ -348,8 +356,8 @@ Sort by number of bytes in use of all open allocations.
|
|||||||
.RE
|
.RE
|
||||||
.RE
|
.RE
|
||||||
.IP "\-S, \-\-sanity"
|
.IP "\-S, \-\-sanity"
|
||||||
Check mismatching operations against new/delete. This options also
|
Check mismatching operations against new/delete or free releases. This options
|
||||||
sets the sort-by options to mismatched.
|
also sets the sort-by options to mismatched if no other sort option was set.
|
||||||
.IP "\-t, \-\-trace"
|
.IP "\-t, \-\-trace"
|
||||||
Run \fBmtrace-ng\fR in trace mode. In this mode all attached processes will run under
|
Run \fBmtrace-ng\fR in trace mode. In this mode all attached processes will run under
|
||||||
the control of \fBmtrace-ng\fR and all dynamic memory function calls will be traced.
|
the control of \fBmtrace-ng\fR and all dynamic memory function calls will be traced.
|
||||||
@ -399,7 +407,7 @@ at any time. It accepts a maximum of three parameters:
|
|||||||
\fIsortby\fR
|
\fIsortby\fR
|
||||||
.RS
|
.RS
|
||||||
Sort the output of dump by the keyword. The keyword is the same as for the
|
Sort the output of dump by the keyword. The keyword is the same as for the
|
||||||
\-S option (\fIallocations, \fIaverage\fR, \fIbytes-leaked\fR, \fIleaks\fR,
|
\-S option (\fIallocations, \fIaverage\fR, \fIbadfree\fR \fIbytes-leaked\fR, \fIleaks\fR,
|
||||||
\fImismatched\fR, \fIstacks\fR, \fItotal\fR, \fItsc\fR and \fIusage\fR). See
|
\fImismatched\fR, \fIstacks\fR, \fItotal\fR, \fItsc\fR and \fIusage\fR). See
|
||||||
\-S option for more details about the sortby keywords. The default sort order
|
\-S option for more details about the sortby keywords. The default sort order
|
||||||
is \fIallocations\fR when no sortby parameter is used.
|
is \fIallocations\fR when no sortby parameter is used.
|
||||||
|
|||||||
@ -106,7 +106,7 @@ static void usage(void)
|
|||||||
" allocations, average, bytes-leaked, leaks,\n"
|
" allocations, average, bytes-leaked, leaks,\n"
|
||||||
" mismatched, stacks, total, tsc, usage\n"
|
" mismatched, stacks, total, tsc, usage\n"
|
||||||
#endif
|
#endif
|
||||||
" -S, --sanity check mismatching operations against new/delete\n"
|
" -S, --sanity check for mismatching operations\n"
|
||||||
" -t, --trace trace mode\n"
|
" -t, --trace trace mode\n"
|
||||||
" -u, --user=USERNAME run command with the userid, groupid of username\n"
|
" -u, --user=USERNAME run command with the userid, groupid of username\n"
|
||||||
" -V, --version output version information and exit\n"
|
" -V, --version output version information and exit\n"
|
||||||
@ -198,7 +198,7 @@ static void def_config(void)
|
|||||||
{
|
{
|
||||||
char *path;
|
char *path;
|
||||||
char *filename;
|
char *filename;
|
||||||
|
|
||||||
path = getenv("HOME");
|
path = getenv("HOME");
|
||||||
if (!path) {
|
if (!path) {
|
||||||
struct passwd *pwd = getpwuid(getuid());
|
struct passwd *pwd = getpwuid(getuid());
|
||||||
@ -504,6 +504,9 @@ char **process_options(int argc, char **argv)
|
|||||||
if (!strncmp(optarg, "average", 2))
|
if (!strncmp(optarg, "average", 2))
|
||||||
options.sort_by = OPT_SORT_AVERAGE;
|
options.sort_by = OPT_SORT_AVERAGE;
|
||||||
else
|
else
|
||||||
|
if (!strncmp(optarg, "badfree", 1))
|
||||||
|
options.sort_by = OPT_SORT_BADFREE;
|
||||||
|
else
|
||||||
if (!strncmp(optarg, "bytes-leaked", 1))
|
if (!strncmp(optarg, "bytes-leaked", 1))
|
||||||
options.sort_by = OPT_SORT_BYTES_LEAKED;
|
options.sort_by = OPT_SORT_BYTES_LEAKED;
|
||||||
else
|
else
|
||||||
@ -666,7 +669,7 @@ char **process_options(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (options.sanity)
|
if (options.sanity && options.sort_by == -1)
|
||||||
options.sort_by = OPT_SORT_MISMATCHED;
|
options.sort_by = OPT_SORT_MISMATCHED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -39,6 +39,7 @@
|
|||||||
#define OPT_SORT_TSC 6
|
#define OPT_SORT_TSC 6
|
||||||
#define OPT_SORT_USAGE 7
|
#define OPT_SORT_USAGE 7
|
||||||
#define OPT_SORT_MISMATCHED 8
|
#define OPT_SORT_MISMATCHED 8
|
||||||
|
#define OPT_SORT_BADFREE 9
|
||||||
|
|
||||||
struct options_t options;
|
struct options_t options;
|
||||||
|
|
||||||
|
|||||||
2
rbtree.c
2
rbtree.c
@ -400,7 +400,7 @@ int rb_iterate(const struct rb_root *root, int (*func)(struct rb_node *,void *us
|
|||||||
|
|
||||||
do {
|
do {
|
||||||
parent = rb_parent(node);
|
parent = rb_parent(node);
|
||||||
|
|
||||||
ret = func(node, user);
|
ret = func(node, user);
|
||||||
if (ret)
|
if (ret)
|
||||||
break;
|
break;
|
||||||
|
|||||||
4
report.c
4
report.c
@ -63,7 +63,7 @@ static void report_alloc64(struct task *task, enum mt_operation op, unsigned lon
|
|||||||
if (unlikely(!alloc->data[i]))
|
if (unlikely(!alloc->data[i]))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -244,7 +244,7 @@ static void _report_mmap64(struct task *task, struct library_symbol *libsym)
|
|||||||
} size;
|
} size;
|
||||||
|
|
||||||
size.l = fetch_param(task, 1);
|
size.l = fetch_param(task, 1);
|
||||||
|
|
||||||
if (!task_is_64bit(task)) {
|
if (!task_is_64bit(task)) {
|
||||||
size.v.v1 = fetch_param(task, 1);
|
size.v.v1 = fetch_param(task, 1);
|
||||||
size.v.v2 = fetch_param(task, 2);
|
size.v.v2 = fetch_param(task, 2);
|
||||||
|
|||||||
3
server.c
3
server.c
@ -98,8 +98,7 @@ int server_poll(void)
|
|||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
|
if (command_pending) {
|
||||||
if (command_pending) {
|
|
||||||
ret = server_handle_command();
|
ret = server_handle_command();
|
||||||
|
|
||||||
if (options.trace)
|
if (options.trace)
|
||||||
|
|||||||
@ -207,7 +207,7 @@ static int arm_get_next_pcs(struct task *task, const uint32_t pc, uint32_t next_
|
|||||||
if (BITS(this_instr, 12, 15) != ARM_REG_PC)
|
if (BITS(this_instr, 12, 15) != ARM_REG_PC)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (BITS(this_instr, 22, 25) == 0 && BITS(this_instr, 4, 7) == 9) /* multiply */
|
if (BITS(this_instr, 22, 25) == 0 && BITS(this_instr, 4, 7) == 9) /* multiply */
|
||||||
goto invalid;
|
goto invalid;
|
||||||
|
|
||||||
/* BX <reg>, BLX <reg> */
|
/* BX <reg>, BLX <reg> */
|
||||||
|
|||||||
@ -612,7 +612,7 @@ static int arm_frame_step(struct dwarf_addr_space *as)
|
|||||||
ip_loc = DWARF_MEM_LOC(fp);
|
ip_loc = DWARF_MEM_LOC(fp);
|
||||||
fp_loc = DWARF_MEM_LOC(fp - 4);
|
fp_loc = DWARF_MEM_LOC(fp - 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dwarf_get(as, ip_loc, &ip) < 0)
|
if (dwarf_get(as, ip_loc, &ip) < 0)
|
||||||
return -DWARF_EBADFRAME;
|
return -DWARF_EBADFRAME;
|
||||||
|
|
||||||
|
|||||||
@ -59,7 +59,7 @@ struct map {
|
|||||||
unsigned long long start;
|
unsigned long long start;
|
||||||
unsigned long long end;
|
unsigned long long end;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void report_fault(int signo, siginfo_t* siginf, void* arg)
|
static void report_fault(int signo, siginfo_t* siginf, void* arg)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "fault signal %d (%s)\n", signo, strsignal(signo));
|
fprintf(stderr, "fault signal %d (%s)\n", signo, strsignal(signo));
|
||||||
@ -70,37 +70,37 @@ static void report_fault(int signo, siginfo_t* siginf, void* arg)
|
|||||||
void *trace[48];
|
void *trace[48];
|
||||||
char **strings;
|
char **strings;
|
||||||
Dl_info info;
|
Dl_info info;
|
||||||
char linkname[PATH_MAX];
|
char linkname[PATH_MAX];
|
||||||
bfd* abfd = 0;
|
bfd* abfd = 0;
|
||||||
asymbol **syms = 0;
|
asymbol **syms = 0;
|
||||||
asection *text = 0;
|
asection *text = 0;
|
||||||
int l;
|
int l;
|
||||||
|
|
||||||
l = readlink("/proc/self/exe", linkname, sizeof(linkname));
|
l = readlink("/proc/self/exe", linkname, sizeof(linkname));
|
||||||
if (l == -1) {
|
if (l == -1) {
|
||||||
perror("failed to find executable\n");
|
perror("failed to find executable\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
linkname[l] = 0;
|
linkname[l] = 0;
|
||||||
|
|
||||||
bfd_init();
|
|
||||||
|
|
||||||
abfd = bfd_openr(linkname, 0);
|
|
||||||
if (!abfd) {
|
|
||||||
perror("bfd_openr failed: ");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* oddly, this is required for it to work... */
|
|
||||||
bfd_check_format(abfd,bfd_object);
|
|
||||||
|
|
||||||
unsigned storage_needed = bfd_get_symtab_upper_bound(abfd);
|
|
||||||
syms = (asymbol **) malloc(storage_needed);
|
|
||||||
|
|
||||||
bfd_canonicalize_symtab(abfd, syms);
|
bfd_init();
|
||||||
|
|
||||||
|
abfd = bfd_openr(linkname, 0);
|
||||||
|
if (!abfd) {
|
||||||
|
perror("bfd_openr failed: ");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* oddly, this is required for it to work... */
|
||||||
|
bfd_check_format(abfd,bfd_object);
|
||||||
|
|
||||||
|
unsigned storage_needed = bfd_get_symtab_upper_bound(abfd);
|
||||||
|
syms = (asymbol **) malloc(storage_needed);
|
||||||
|
|
||||||
|
bfd_canonicalize_symtab(abfd, syms);
|
||||||
|
|
||||||
text = bfd_get_section_by_name(abfd, ".text");
|
text = bfd_get_section_by_name(abfd, ".text");
|
||||||
|
|
||||||
nptrs = backtrace(trace, ARRAY_SIZE(trace));
|
nptrs = backtrace(trace, ARRAY_SIZE(trace));
|
||||||
|
|
||||||
strings = backtrace_symbols(trace, nptrs);
|
strings = backtrace_symbols(trace, nptrs);
|
||||||
@ -216,7 +216,7 @@ static struct map *get_writeable_mappings(struct task *task)
|
|||||||
|
|
||||||
if (permw != 'w' || permr != 'r')
|
if (permw != 'w' || permr != 'r')
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (map >= maps_size - 1) {
|
if (map >= maps_size - 1) {
|
||||||
maps_size += 16;
|
maps_size += 16;
|
||||||
maps = realloc(maps, maps_size * sizeof(*maps));
|
maps = realloc(maps, maps_size * sizeof(*maps));
|
||||||
|
|||||||
@ -473,7 +473,6 @@ static void linkmap_del(struct task *task, struct lt_r_debug_64 *dbg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int load_debug_struct(struct task *task, arch_addr_t debug_addr, struct lt_r_debug_64 *ret)
|
static int load_debug_struct(struct task *task, arch_addr_t debug_addr, struct lt_r_debug_64 *ret)
|
||||||
|
|
||||||
{
|
{
|
||||||
debug(DEBUG_FUNCTION, "pid=%d", task->pid);
|
debug(DEBUG_FUNCTION, "pid=%d", task->pid);
|
||||||
|
|
||||||
@ -559,7 +558,7 @@ int process_get_entry(struct task *task, unsigned long *entryp, unsigned long *i
|
|||||||
{
|
{
|
||||||
PROC_PID_FILE(fn, "/proc/%d/auxv", task->pid);
|
PROC_PID_FILE(fn, "/proc/%d/auxv", task->pid);
|
||||||
int fd, ret;
|
int fd, ret;
|
||||||
|
|
||||||
fd = open(fn, O_RDONLY);
|
fd = open(fn, O_RDONLY);
|
||||||
if (fd == -1)
|
if (fd == -1)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|||||||
@ -106,7 +106,7 @@ int sock_send_msg(int fd, enum mt_operation op, uint32_t pid, const void *payloa
|
|||||||
}
|
}
|
||||||
|
|
||||||
ret = TEMP_FAILURE_RETRY(sendmsg(fd, &msghdr, MSG_NOSIGNAL));
|
ret = TEMP_FAILURE_RETRY(sendmsg(fd, &msghdr, MSG_NOSIGNAL));
|
||||||
|
|
||||||
if ((size_t)ret != sizeof(mt_msg) + payload_len)
|
if ((size_t)ret != sizeof(mt_msg) + payload_len)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
|||||||
@ -227,7 +227,7 @@ static void process_event(struct task *task, int status)
|
|||||||
start_time(&task->halt_time);
|
start_time(&task->halt_time);
|
||||||
|
|
||||||
task->stopped = 1;
|
task->stopped = 1;
|
||||||
|
|
||||||
leader->threads_stopped++;
|
leader->threads_stopped++;
|
||||||
|
|
||||||
stop_signal = _process_event(task, status);
|
stop_signal = _process_event(task, status);
|
||||||
@ -534,7 +534,7 @@ struct task *wait_event(void)
|
|||||||
struct task *task;
|
struct task *task;
|
||||||
int status;
|
int status;
|
||||||
int pid;
|
int pid;
|
||||||
|
|
||||||
pid = waitpid(-1, &status, __WALL);
|
pid = waitpid(-1, &status, __WALL);
|
||||||
if (unlikely(pid == -1)) {
|
if (unlikely(pid == -1)) {
|
||||||
if (errno != EINTR) {
|
if (errno != EINTR) {
|
||||||
|
|||||||
@ -141,7 +141,7 @@ static int set_breakpoint_mode(struct task *task, unsigned int n, int type, int
|
|||||||
dr7 = task->arch.dr7 & ~mask;
|
dr7 = task->arch.dr7 & ~mask;
|
||||||
|
|
||||||
dr7 |= mode << (16 + 4 * n);
|
dr7 |= mode << (16 + 4 * n);
|
||||||
|
|
||||||
if (local) {
|
if (local) {
|
||||||
dr7 |= 0b01 << (2 * n);
|
dr7 |= 0b01 << (2 * n);
|
||||||
dr7 |= 1 << 8;
|
dr7 |= 1 << 8;
|
||||||
|
|||||||
@ -103,9 +103,9 @@ unsigned int ip_reg_addr(void)
|
|||||||
arch_addr_t get_return_addr(struct task *task)
|
arch_addr_t get_return_addr(struct task *task)
|
||||||
{
|
{
|
||||||
long a;
|
long a;
|
||||||
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
|
|
||||||
a = ptrace(PTRACE_PEEKTEXT, task->pid, get_stack_pointer(task), 0);
|
a = ptrace(PTRACE_PEEKTEXT, task->pid, get_stack_pointer(task), 0);
|
||||||
if (a == -1 && errno) {
|
if (a == -1 && errno) {
|
||||||
if (errno != ESRCH)
|
if (errno != ESRCH)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user