features and fixes

add ignore regex list
fix minor bugs
This commit is contained in:
Stefani Seibold 2015-04-27 10:58:08 +02:00
parent 92e40e9ec5
commit 31e81d4f25
8 changed files with 322 additions and 65 deletions

1
.gitignore vendored
View File

@ -29,4 +29,5 @@ stamp-h1
libtool
docross
doremote
dokvm
mtrace

1
TODO
View File

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

View File

@ -32,6 +32,7 @@
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/mman.h>
#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));

View File

@ -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;
}
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();
}
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,14 +1229,10 @@ 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);
}
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))

View File

@ -21,6 +21,8 @@
#ifndef _INC_CLIENT_PROCESS_H
#define _INC_CLIENT_PROCESS_H
#include <regex.h>
#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

107
options.c
View File

@ -27,6 +27,8 @@
#include "config.h"
#define _GNU_SOURCE
#include <sys/ioctl.h>
#include <assert.h>
#include <errno.h>
@ -37,6 +39,8 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <pwd.h>
#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));
if (add_opt_F(strdup(optarg)) == -1) {
fprintf(stderr, "config file not found %s\n", optarg);
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;
}
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]);

View File

@ -181,11 +181,9 @@ 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,11 +222,9 @@ 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)))
fatal("setsockopt (%s)", strerror(errno));

2
task.c
View File

@ -43,6 +43,7 @@
#include "library.h"
#include "mtelf.h"
#include "report.h"
#include "server.h"
#include "task.h"
#include "trace.h"
@ -322,6 +323,7 @@ int task_clone(struct task *task, struct task *newtask)
if (backtrace_init(newtask) < 0)
goto fail;
if (server_connected())
breakpoint_hw_clone(newtask);
return 0;