mirror of
https://github.com/sstefani/mtrace.git
synced 2025-12-07 01:06:41 +08:00
features and fixes
add ignore regex list fix minor bugs
This commit is contained in:
parent
92e40e9ec5
commit
31e81d4f25
1
.gitignore
vendored
1
.gitignore
vendored
@ -29,4 +29,5 @@ stamp-h1
|
|||||||
libtool
|
libtool
|
||||||
docross
|
docross
|
||||||
doremote
|
doremote
|
||||||
|
dokvm
|
||||||
mtrace
|
mtrace
|
||||||
|
|||||||
1
TODO
1
TODO
@ -3,7 +3,6 @@ arm thumb support
|
|||||||
dwarf debug support
|
dwarf debug support
|
||||||
arm & ppc hw bp support
|
arm & ppc hw bp support
|
||||||
dwarf caching
|
dwarf caching
|
||||||
regex
|
|
||||||
invalid stack trace cache for unmapped libraries
|
invalid stack trace cache for unmapped libraries
|
||||||
restore REALLOC_TRY when realloc fails
|
restore REALLOC_TRY when realloc fails
|
||||||
manual page
|
manual page
|
||||||
|
|||||||
184
client/client.c
184
client/client.c
@ -32,6 +32,7 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
|
||||||
#include "binfile.h"
|
#include "binfile.h"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
@ -57,6 +58,167 @@ static int first_pid;
|
|||||||
static struct memtrace_info mt_info;
|
static struct memtrace_info mt_info;
|
||||||
static struct thread *thread;
|
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)
|
static struct rb_process *pid_rb_search(struct rb_root *root, pid_t pid)
|
||||||
{
|
{
|
||||||
struct rb_node *node = root->rb_node;
|
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;
|
pid_table = RB_ROOT;
|
||||||
first_pid = 0;
|
first_pid = 0;
|
||||||
|
|
||||||
mt_info.version = MEMTRACE_SI_VERSION;
|
mt_info.version = MEMTRACE_SI_VERSION;
|
||||||
mt_info.mode = 0;
|
mt_info.mode = 0;
|
||||||
mt_info.do_trace = do_trace;
|
mt_info.do_trace = do_trace;
|
||||||
mt_info.stack_depth = 0;
|
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)
|
int client_start(void)
|
||||||
{
|
{
|
||||||
_client_init(0);
|
if (client_init(0) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
client_fd = connect_to(options.client, options.port);
|
client_fd = connect_to(options.client, options.port);
|
||||||
|
|
||||||
if (client_fd == -1) {
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -434,14 +607,15 @@ void *client_thread(void *unused)
|
|||||||
|
|
||||||
int client_start_pair(int handle)
|
int client_start_pair(int handle)
|
||||||
{
|
{
|
||||||
|
if (client_init(1) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
thread = thread_new();
|
thread = thread_new();
|
||||||
if (!thread)
|
if (!thread)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
client_fd = handle;
|
client_fd = handle;
|
||||||
|
|
||||||
_client_init(1);
|
|
||||||
|
|
||||||
if (thread_start(thread, client_thread, NULL))
|
if (thread_start(thread, client_thread, NULL))
|
||||||
fatal("could not start thread (%s)", strerror(errno));
|
fatal("could not start thread (%s)", strerror(errno));
|
||||||
|
|
||||||
|
|||||||
@ -56,6 +56,7 @@ struct stack {
|
|||||||
uint32_t entries;
|
uint32_t entries;
|
||||||
char **syms;
|
char **syms;
|
||||||
enum mt_operation operation;
|
enum mt_operation operation;
|
||||||
|
unsigned int ignore:1;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct rb_stack {
|
struct rb_stack {
|
||||||
@ -77,9 +78,37 @@ struct map {
|
|||||||
char *filename;
|
char *filename;
|
||||||
char *realpath;
|
char *realpath;
|
||||||
struct bin_file *binfile;
|
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)
|
static const char *str_operation(enum mt_operation operation)
|
||||||
{
|
{
|
||||||
switch(operation) {
|
switch(operation) {
|
||||||
@ -337,6 +366,21 @@ static void stack_resolv(struct process *process, struct stack *stack)
|
|||||||
|
|
||||||
addrs += process->ptr_size;
|
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)
|
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->entries = stack_size / process->ptr_size;
|
||||||
stack->syms = NULL;
|
stack->syms = NULL;
|
||||||
stack->operation = operation;
|
stack->operation = operation;
|
||||||
|
stack->ignore = 0;
|
||||||
|
|
||||||
memcpy(stack->addrs, addrs, stack_size);
|
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) {
|
for(i = 0; i < process->stack_trees; ++i) {
|
||||||
struct rb_stack *stack = arr[i];
|
struct rb_stack *stack = arr[i];
|
||||||
|
|
||||||
if (!skipfunc(stack)) {
|
if (!skipfunc(stack) && !stack->stack->ignore) {
|
||||||
if (dump_printf(
|
if (dump_printf(
|
||||||
"Stack (%s):\n"
|
"Stack (%s):\n"
|
||||||
" bytes used: %llu\n"
|
" bytes used: %llu\n"
|
||||||
@ -1056,11 +1101,8 @@ 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 (options.verbose > 1)
|
|
||||||
fprintf(stderr, ">>> block missmatch MAP<>MALLOC %#lx found\n", ptr);
|
fprintf(stderr, ">>> block missmatch MAP<>MALLOC %#lx found\n", ptr);
|
||||||
if (options.wait)
|
|
||||||
abort();
|
abort();
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (block->addr >= ptr) {
|
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);
|
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 (options.verbose > 1)
|
|
||||||
fprintf(stderr, ">>> block missmatch MAP<>MALLOC %#lx found\n", ptr);
|
fprintf(stderr, ">>> block missmatch MAP<>MALLOC %#lx found\n", ptr);
|
||||||
if (options.wait)
|
|
||||||
abort();
|
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);
|
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);
|
block = process_rb_search(&process->block_table, ptr);
|
||||||
if (block) {
|
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);
|
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();
|
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))
|
||||||
|
|||||||
@ -21,6 +21,8 @@
|
|||||||
#ifndef _INC_CLIENT_PROCESS_H
|
#ifndef _INC_CLIENT_PROCESS_H
|
||||||
#define _INC_CLIENT_PROCESS_H
|
#define _INC_CLIENT_PROCESS_H
|
||||||
|
|
||||||
|
#include <regex.h>
|
||||||
|
|
||||||
#include "list.h"
|
#include "list.h"
|
||||||
#include "memtrace.h"
|
#include "memtrace.h"
|
||||||
#include "rbtree.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_sort_tsc(struct process *process, const char *outfile);
|
||||||
void process_dump_stacks(struct process *process, const char *outfile);
|
void process_dump_stacks(struct process *process, const char *outfile);
|
||||||
|
|
||||||
|
void add_ignore_regex(regex_t *re);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
107
options.c
107
options.c
@ -27,6 +27,8 @@
|
|||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
@ -37,6 +39,8 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <pwd.h>
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "options.h"
|
#include "options.h"
|
||||||
@ -45,9 +49,6 @@
|
|||||||
#define SYSCONFDIR "/etc"
|
#define SYSCONFDIR "/etc"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define SYSTEM_CONFIG_FILE SYSCONFDIR "/mtrace.conf"
|
|
||||||
#define USER_CONFIG_FILE "~/.mtrace.conf"
|
|
||||||
|
|
||||||
#define MIN_STACK 4
|
#define MIN_STACK 4
|
||||||
#define MAX_STACK 128
|
#define MAX_STACK 128
|
||||||
|
|
||||||
@ -56,6 +57,10 @@
|
|||||||
|
|
||||||
struct options_t options;
|
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 char *progname; /* Program name (`mtrace') */
|
||||||
|
|
||||||
static void err_usage(void)
|
static void err_usage(void)
|
||||||
@ -150,6 +155,71 @@ static char *search_for_command(char *filename)
|
|||||||
return 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)
|
static int parse_int(const char *optarg, char opt, int min, int max)
|
||||||
{
|
{
|
||||||
char *endptr;
|
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)
|
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];
|
progname = argv[0];
|
||||||
|
|
||||||
options.auto_scan = 0;
|
options.auto_scan = 0;
|
||||||
@ -282,25 +348,11 @@ char **process_options(int argc, char **argv)
|
|||||||
options.follow = 1;
|
options.follow = 1;
|
||||||
break;
|
break;
|
||||||
case 'F':
|
case 'F':
|
||||||
{
|
if (add_opt_F(strdup(optarg)) == -1) {
|
||||||
struct opt_F_t *tmp = malloc(sizeof(*tmp));
|
fprintf(stderr, "config file not found %s\n", optarg);
|
||||||
|
|
||||||
if (!tmp) {
|
|
||||||
fprintf(stderr, "%s\n", strerror(errno));
|
|
||||||
exit(1);
|
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;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
case 'h':
|
case 'h':
|
||||||
|
|
||||||
usage();
|
usage();
|
||||||
@ -465,13 +517,8 @@ char **process_options(int argc, char **argv)
|
|||||||
if (options.bt_depth > MAX_STACK)
|
if (options.bt_depth > MAX_STACK)
|
||||||
options.bt_depth = MAX_STACK;
|
options.bt_depth = MAX_STACK;
|
||||||
|
|
||||||
if (!options.opt_F) {
|
if (!options.opt_F)
|
||||||
options.opt_F = malloc(sizeof(struct opt_F_t));
|
def_config();
|
||||||
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 (argc > 0)
|
if (argc > 0)
|
||||||
options.command = search_for_command(argv[0]);
|
options.command = search_for_command(argv[0]);
|
||||||
|
|||||||
@ -181,11 +181,9 @@ int connect_to(const char *node, const char *service)
|
|||||||
close(sfd);
|
close(sfd);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!rp) {
|
if (!rp)
|
||||||
fprintf(stderr, "Could not connect\n");
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return sfd;
|
return sfd;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -224,11 +222,9 @@ int bind_to(const char *node, const char *service)
|
|||||||
close(sfd);
|
close(sfd);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!rp) {
|
if (!rp)
|
||||||
fprintf(stderr, "Could not bind\n");
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &const_int_1, sizeof(const_int_1)))
|
if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &const_int_1, sizeof(const_int_1)))
|
||||||
fatal("setsockopt (%s)", strerror(errno));
|
fatal("setsockopt (%s)", strerror(errno));
|
||||||
|
|||||||
2
task.c
2
task.c
@ -43,6 +43,7 @@
|
|||||||
#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"
|
||||||
|
|
||||||
@ -322,6 +323,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;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user