From 31e81d4f25532b358531e1662ccca75c1f370114 Mon Sep 17 00:00:00 2001 From: Stefani Seibold Date: Mon, 27 Apr 2015 10:58:08 +0200 Subject: [PATCH] features and fixes add ignore regex list fix minor bugs --- .gitignore | 1 + TODO | 1 - client/client.c | 184 ++++++++++++++++++++++++++++++++++++- client/process.c | 74 +++++++++++---- client/process.h | 4 + options.c | 111 +++++++++++++++------- sysdeps/linux-gnu/socket.c | 8 +- task.c | 4 +- 8 files changed, 322 insertions(+), 65 deletions(-) diff --git a/.gitignore b/.gitignore index 5a14398..2b74939 100644 --- a/.gitignore +++ b/.gitignore @@ -29,4 +29,5 @@ stamp-h1 libtool docross doremote +dokvm mtrace diff --git a/TODO b/TODO index 57b219a..8ed3131 100644 --- a/TODO +++ b/TODO @@ -3,7 +3,6 @@ arm thumb support dwarf debug support arm & ppc hw bp support dwarf caching -regex invalid stack trace cache for unmapped libraries restore REALLOC_TRY when realloc fails manual page diff --git a/client/client.c b/client/client.c index aee3e4b..9453ad2 100644 --- a/client/client.c +++ b/client/client.c @@ -32,6 +32,7 @@ #include #include #include +#include #include "binfile.h" #include "common.h" @@ -57,6 +58,167 @@ static int first_pid; static struct memtrace_info mt_info; static struct thread *thread; +static unsigned long skip_nl(const char *p, unsigned long n) +{ + unsigned long c = 0; + + while(n > c) { + if (p[c] != '\n' && p[c] != '\r') + break; + ++c; + } + + return c; +} + +static unsigned long get_line(const char *p, unsigned long n) +{ + unsigned long c = 0; + + while(n > c) { + if (p[c] == '\n' || p[c] == '\r') + break; + ++c; + } + + return c; +} + +static unsigned long skip_space(const char *p, unsigned long n) +{ + unsigned long c = 0; + + while(n > c) { + if (p[c] != ' ' && p[c] != '\t') + break; + ++c; + } + + return c; +} + +static unsigned long trim_space(const char *p, unsigned long n) +{ + unsigned long c = n; + + while(c) { + if (p[c - 1] != ' ' && p[c - 1] != '\t') + break; + --c; + } + + return c; +} + +static unsigned long cmp_n(const char *p, const char *str, unsigned long n) +{ + unsigned long c = 0; + + while(n > c) { + if (!str[c]) { + if (p[c] == ' ' || p[c] == '\t') + return c; + break; + } + + if (p[c] != str[c]) + break; + + c++; + } + + return 0; +} + +static void _parse_config(const char *filename, const char *p, unsigned long n) +{ + unsigned long c, l; + + for(;;) { + c = skip_nl(p, n); + + p += c; + n -= c; + + if (!n) + break; + + l = get_line(p, n); + + c = skip_space(p, l); + + p += c; + n -= c; + l -= c; + + if (!n) + break; + + if (*p != '#') { + c = cmp_n(p, "ignore", l); + if (c) { + c += skip_space(p + c, l - c); + + if (c != l) { + int ret; + regex_t re; + char *regex; + + regex = strndup(p + c, trim_space(p + c, l - c)); + + ret = regcomp(&re, regex, REG_NOSUB); + if (ret) { + char errbuf[128]; + + regerror(ret, &re, errbuf, sizeof(errbuf)); + + fprintf(stderr, "%s: invalid regular expression: `%s' (%s)\n", filename, regex, errbuf); + } + else + add_ignore_regex(&re); + + free(regex); + } + } + else + fprintf(stderr, "%s: invalid line `%.*s'\n", filename, (int)l, p); + } + + p += l; + n -= l; + + if (!n) + break; + } +} + +static int parse_config(const char *filename) +{ + char *p; + struct stat statbuf; + int fd; + + fd = open(filename, O_RDONLY); + if (fd == -1) + fatal("could not open config file: `%s' (%s)", filename, strerror(errno)); + + if (fstat(fd, &statbuf) == -1) + fatal("could not read config file: `%s' (%s)", filename, strerror(errno)); + + if (statbuf.st_size) { + p = mmap(NULL, statbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0); + if (p == MAP_FAILED) + fatal("could map config file: `%s' (%s)", filename, strerror(errno)); + + _parse_config(filename, p, statbuf.st_size); + + munmap(p, statbuf.st_size); + } + close(fd); + + return 0; +} + static struct rb_process *pid_rb_search(struct rb_root *root, pid_t pid) { struct rb_node *node = root->rb_node; @@ -379,24 +541,35 @@ void client_remove_process(struct process *process) } -void _client_init(int do_trace) +static int client_init(int do_trace) { + struct opt_F_t *p; + pid_table = RB_ROOT; first_pid = 0; + mt_info.version = MEMTRACE_SI_VERSION; mt_info.mode = 0; mt_info.do_trace = do_trace; mt_info.stack_depth = 0; + + for(p = options.opt_F; p; p = p->next) { + if (parse_config(p->filename) < 0) + return -1; + } + + return 0; } int client_start(void) { - _client_init(0); + if (client_init(0) < 0) + return -1; client_fd = connect_to(options.client, options.port); if (client_fd == -1) { - fprintf(stderr, "could not connect: %s:%s", options.client, options.port); + fprintf(stderr, "could not connect: %s:%s\n", options.client, options.port); return -1; } @@ -434,14 +607,15 @@ void *client_thread(void *unused) int client_start_pair(int handle) { + if (client_init(1) < 0) + return -1; + thread = thread_new(); if (!thread) return -1; client_fd = handle; - _client_init(1); - if (thread_start(thread, client_thread, NULL)) fatal("could not start thread (%s)", strerror(errno)); diff --git a/client/process.c b/client/process.c index 73f506f..9625330 100644 --- a/client/process.c +++ b/client/process.c @@ -56,6 +56,7 @@ struct stack { uint32_t entries; char **syms; enum mt_operation operation; + unsigned int ignore:1; }; struct rb_stack { @@ -77,9 +78,37 @@ struct map { char *filename; char *realpath; struct bin_file *binfile; - int ignore; + unsigned int ignore:1; }; +struct regex_list { + regex_t re; + struct regex_list *next; +}; + +static struct regex_list *regex_ignore_list; +static struct regex_list *regex_ignore_last; + +void add_ignore_regex(regex_t *re) +{ + struct regex_list *tmp = malloc(sizeof(*tmp)); + + if (!tmp) { + fprintf(stderr, "%s\n", strerror(errno)); + exit(1); + } + + tmp->re = *re; + tmp->next = NULL; + + if (regex_ignore_last) + regex_ignore_last->next = tmp; + regex_ignore_last = tmp; + + if (!regex_ignore_list) + regex_ignore_list = tmp; +} + static const char *str_operation(enum mt_operation operation) { switch(operation) { @@ -337,6 +366,21 @@ static void stack_resolv(struct process *process, struct stack *stack) addrs += process->ptr_size; } + + if (regex_ignore_list) { + for(i = 0; i < stack->entries; ++i) { + struct regex_list *p; + + for(p = regex_ignore_list; p; p = p->next) + if (stack->syms[i] && !regexec(&p->re, stack->syms[i], 0, NULL, 0)) { + stack->ignore = 1; + break; + } + + if (stack->ignore) + break; + } + } } static void stack_unref(struct stack *stack) @@ -439,6 +483,7 @@ static struct rb_stack *stack_add(struct process *process, pid_t pid, void *addr stack->entries = stack_size / process->ptr_size; stack->syms = NULL; stack->operation = operation; + stack->ignore = 0; memcpy(stack->addrs, addrs, stack_size); @@ -859,7 +904,7 @@ static void _process_dump(struct process *process, int (*sortby)(const struct rb for(i = 0; i < process->stack_trees; ++i) { struct rb_stack *stack = arr[i]; - if (!skipfunc(stack)) { + if (!skipfunc(stack) && !stack->stack->ignore) { if (dump_printf( "Stack (%s):\n" " bytes used: %llu\n" @@ -1056,11 +1101,8 @@ void process_munmap(struct process *process, struct mt_msg *mt_msg, void *payloa break; if (!is_mmap(block->stack_node->stack->operation)) { - if (options.verbose > 1) - fprintf(stderr, ">>> block missmatch MAP<>MALLOC %#lx found\n", ptr); - if (options.wait) - abort(); - break; + fprintf(stderr, ">>> block missmatch MAP<>MALLOC %#lx found\n", ptr); + abort(); } if (block->addr >= ptr) { @@ -1139,18 +1181,14 @@ void process_free(struct process *process, struct mt_msg *mt_msg, void *payload) block = process_rb_search(&process->block_table, ptr); if (block) { if (is_mmap(block->stack_node->stack->operation)) { - if (options.verbose > 1) - fprintf(stderr, ">>> block missmatch MAP<>MALLOC %#lx found\n", ptr); - if (options.wait) - abort(); + fprintf(stderr, ">>> block missmatch MAP<>MALLOC %#lx found\n", ptr); + abort(); } process_rb_delete_block(process, block); } else { - if (!process->attached) { + if (!process->attached) fprintf(stderr, ">>> block %#lx not found (pid=%d, tid=%d)\n", ptr, process->pid, mt_msg->tid); - abort(); - } } } @@ -1191,12 +1229,8 @@ void process_alloc(struct process *process, struct mt_msg *mt_msg, void *payload block = process_rb_search(&process->block_table, ptr); if (block) { - if (options.verbose > 1) { - 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); - abort(); - } - - process_rb_delete_block(process, 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); + abort(); } struct rb_stack *stack = stack_add(process, process->pid, stack_data, stack_size, mt_msg->operation); diff --git a/client/process.h b/client/process.h index b375342..afa6218 100644 --- a/client/process.h +++ b/client/process.h @@ -21,6 +21,8 @@ #ifndef _INC_CLIENT_PROCESS_H #define _INC_CLIENT_PROCESS_H +#include + #include "list.h" #include "memtrace.h" #include "rbtree.h" @@ -106,5 +108,7 @@ void process_dump_sort_total(struct process *process, const char *outfile); void process_dump_sort_tsc(struct process *process, const char *outfile); void process_dump_stacks(struct process *process, const char *outfile); +void add_ignore_regex(regex_t *re); + #endif diff --git a/options.c b/options.c index f4b2822..fe84729 100644 --- a/options.c +++ b/options.c @@ -27,6 +27,8 @@ #include "config.h" +#define _GNU_SOURCE + #include #include #include @@ -37,6 +39,8 @@ #include #include #include +#include +#include #include "common.h" #include "options.h" @@ -45,9 +49,6 @@ #define SYSCONFDIR "/etc" #endif -#define SYSTEM_CONFIG_FILE SYSCONFDIR "/mtrace.conf" -#define USER_CONFIG_FILE "~/.mtrace.conf" - #define MIN_STACK 4 #define MAX_STACK 128 @@ -56,6 +57,10 @@ struct options_t options; +static struct opt_F_t *opt_F_last; +static struct opt_p_t *opt_p_last; +static struct opt_b_t *opt_b_last; + static char *progname; /* Program name (`mtrace') */ static void err_usage(void) @@ -150,6 +155,71 @@ static char *search_for_command(char *filename) return filename; } +static int add_opt_F(char *filename) +{ + struct opt_F_t *tmp = malloc(sizeof(*tmp)); + + if (access(filename, R_OK)) + return -1; + + if (!tmp) { + fprintf(stderr, "%s\n", strerror(errno)); + exit(1); + } + + tmp->filename = strdup(filename); + tmp->next = NULL; + + if (opt_F_last) + opt_F_last->next = tmp; + opt_F_last = tmp; + + if (!options.opt_F) + options.opt_F = tmp; + + return 0; +} + +static void def_config(void) +{ + char *path; + char *filename; + + path = getenv("HOME"); + if (!path) { + struct passwd *pwd = getpwuid(getuid()); + + if (pwd != NULL) + path = pwd->pw_dir; + } + + if (path) { + if (asprintf(&filename, "%s/.mtrace", path) != -1) { + if (add_opt_F(filename)) + free(filename); + } + } + else { + path = getenv("XDG_CONFIG_HOME"); + if (path) { + if (asprintf(&filename, "%s/mtrace", path) != -1) { + if (add_opt_F(filename)) + free(filename); + } + } + } + + if (asprintf(&filename, "%s/mtrace.conf", SYSCONFDIR) != -1) { + if (add_opt_F(filename)) + free(filename); + } + else + if (asprintf(&filename, "%s/mtrace.conf", "/etc") != -1) { + if (add_opt_F(filename)) + free(filename); + } +} + static int parse_int(const char *optarg, char opt, int min, int max) { char *endptr; @@ -165,10 +235,6 @@ static int parse_int(const char *optarg, char opt, int min, int max) char **process_options(int argc, char **argv) { - struct opt_F_t *opt_F_last = NULL; - struct opt_p_t *opt_p_last = NULL; - struct opt_b_t *opt_b_last = NULL; - progname = argv[0]; options.auto_scan = 0; @@ -282,25 +348,11 @@ char **process_options(int argc, char **argv) options.follow = 1; break; case 'F': - { - struct opt_F_t *tmp = malloc(sizeof(*tmp)); - - if (!tmp) { - fprintf(stderr, "%s\n", strerror(errno)); - exit(1); - } - tmp->filename = optarg; - tmp->next = NULL; - - if (opt_F_last) - opt_F_last->next = tmp; - opt_F_last = tmp; - - if (!options.opt_F) - options.opt_F = tmp; - break; + if (add_opt_F(strdup(optarg)) == -1) { + fprintf(stderr, "config file not found %s\n", optarg); + exit(1); } - + break; case 'h': usage(); @@ -465,13 +517,8 @@ char **process_options(int argc, char **argv) if (options.bt_depth > MAX_STACK) options.bt_depth = MAX_STACK; - if (!options.opt_F) { - options.opt_F = malloc(sizeof(struct opt_F_t)); - options.opt_F->filename = USER_CONFIG_FILE; - options.opt_F->next = malloc(sizeof(struct opt_F_t)); - options.opt_F->next->filename = SYSTEM_CONFIG_FILE; - options.opt_F->next->next = NULL; - } + if (!options.opt_F) + def_config(); if (argc > 0) options.command = search_for_command(argv[0]); diff --git a/sysdeps/linux-gnu/socket.c b/sysdeps/linux-gnu/socket.c index fabbee3..4c69d4c 100644 --- a/sysdeps/linux-gnu/socket.c +++ b/sysdeps/linux-gnu/socket.c @@ -181,10 +181,8 @@ int connect_to(const char *node, const char *service) close(sfd); } - if (!rp) { - fprintf(stderr, "Could not connect\n"); + if (!rp) return -1; - } } return sfd; } @@ -224,10 +222,8 @@ int bind_to(const char *node, const char *service) close(sfd); } - if (!rp) { - fprintf(stderr, "Could not bind\n"); + if (!rp) return -1; - } } if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &const_int_1, sizeof(const_int_1))) diff --git a/task.c b/task.c index 8cdb716..d710ebe 100644 --- a/task.c +++ b/task.c @@ -43,6 +43,7 @@ #include "library.h" #include "mtelf.h" #include "report.h" +#include "server.h" #include "task.h" #include "trace.h" @@ -322,7 +323,8 @@ int task_clone(struct task *task, struct task *newtask) if (backtrace_init(newtask) < 0) goto fail; - breakpoint_hw_clone(newtask); + if (server_connected()) + breakpoint_hw_clone(newtask); return 0; fail: