mirror of
https://github.com/sstefani/mtrace.git
synced 2026-04-30 19:09:15 +08:00
clean up, option for invalid free releases
This commit is contained in:
parent
3e2980613c
commit
3b7a0d0552
@ -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)) {
|
||||||
|
if (unlikely(options.kill)) {
|
||||||
fprintf(stderr, ">>> block missmatch pid:%d MAP<>MALLOC %#lx\n", process->pid, ptr);
|
fprintf(stderr, ">>> block missmatch pid:%d MAP<>MALLOC %#lx\n", process->pid, ptr);
|
||||||
|
|
||||||
if (unlikely(options.kill))
|
|
||||||
abort();
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1388,18 +1422,20 @@ 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)) {
|
||||||
|
if (unlikely(options.kill)) {
|
||||||
fprintf(stderr, ">>> block missmatch pid:%d MAP<>MALLOC %#lx\n", process->pid, ptr);
|
fprintf(stderr, ">>> block missmatch pid:%d MAP<>MALLOC %#lx\n", process->pid, ptr);
|
||||||
|
|
||||||
if (unlikely(options.kill))
|
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stack_size) {
|
||||||
if (!is_sane(block, 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);
|
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) {
|
||||||
struct realloc_entry *re = malloc(sizeof(*re));
|
struct realloc_entry *re = malloc(sizeof(*re));
|
||||||
@ -1420,11 +1456,18 @@ void process_free(struct process *process, struct mt_msg *mt_msg, void *payload)
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (!process->attached) {
|
if (!process->attached) {
|
||||||
|
if (unlikely(options.kill)) {
|
||||||
fprintf(stderr, ">>> block %#lx not found pid:%d\n", ptr, process->pid);
|
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);
|
||||||
|
|||||||
@ -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" },
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
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"
|
||||||
@ -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;
|
||||||
|
|
||||||
|
|||||||
1
server.c
1
server.c
@ -98,7 +98,6 @@ int server_poll(void)
|
|||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
|
|
||||||
if (command_pending) {
|
if (command_pending) {
|
||||||
ret = server_handle_command();
|
ret = server_handle_command();
|
||||||
|
|
||||||
|
|||||||
@ -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);
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user