From e387219df58a72b15f47098169de099d44bffcd0 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Sun, 10 Sep 2017 19:08:08 +0900 Subject: [PATCH 01/18] mcount: Remove duplicated signal handler SIGSEGV (and SIGABRT) will be handled by segv_handler. Signed-off-by: Namhyung Kim --- libmcount/mcount.c | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/libmcount/mcount.c b/libmcount/mcount.c index 1e42b0cf8..c28c6475c 100644 --- a/libmcount/mcount.c +++ b/libmcount/mcount.c @@ -278,6 +278,8 @@ static void segv_handler(int sig, siginfo_t *si, void *ctx) if (check_thread_data(mtdp)) goto out; + mcount_rstack_restore(); + idx = mtdp->idx - 1; /* flush current rstack on crash */ rstack = &mtdp->rstack[idx]; @@ -1112,16 +1114,6 @@ static int dlopen_base_callback(struct dl_phdr_info *info, return 0; } -static void (*old_segfault_handler)(int); - -static void segfault_handler(int sig) -{ - mcount_rstack_restore(); - - signal(sig, old_segfault_handler); - raise(sig); -} - void mcount_rstack_restore(void) { int idx; @@ -1221,8 +1213,6 @@ static void mcount_startup(void) } } - old_segfault_handler = signal(SIGSEGV, segfault_handler); - if (debug_str) { debug = strtol(debug_str, NULL, 0); build_debug_domain(getenv("UFTRACE_DEBUG_DOMAIN")); From ff10fe9d80b090ef0b7db632fd158696140a0b0f Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Wed, 13 Sep 2017 23:22:56 -0700 Subject: [PATCH 02/18] mcount: Skip duplicate maps in record_proc_maps() When it writes the /proc/self/maps to the map file, it also creates a sinle linked list of struct ftrace_proc_maps. But the list contains duplicated entries and it confuses symbol loading code. Signed-off-by: Namhyung Kim --- libmcount/record.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libmcount/record.c b/libmcount/record.c index d056a5b9e..a63b606c2 100644 --- a/libmcount/record.c +++ b/libmcount/record.c @@ -678,6 +678,7 @@ void record_proc_maps(char *dirname, const char *sess_id, FILE *ifp, *ofp; char buf[4096]; struct ftrace_proc_maps *prev_map = NULL; + char *last_libname = NULL; ifp = fopen("/proc/self/maps", "r"); if (ifp == NULL) @@ -705,6 +706,10 @@ void record_proc_maps(char *dirname, const char *sess_id, if (prot[2] != 'x') goto next; + /* use first mapping only */ + if (last_libname && !strcmp(last_libname, path)) + continue; + /* save map for the executable */ namelen = ALIGN(strlen(path) + 1, 4); @@ -720,6 +725,7 @@ void record_proc_maps(char *dirname, const char *sess_id, map->symtab.nr_alloc = 0; memcpy(map->libname, path, namelen); map->libname[strlen(path)] = '\0'; + last_libname = map->libname; if (prev_map) prev_map->next = map; From 0e0faddaf0edb11d8cb6ad35e22cee37af854080 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Tue, 12 Sep 2017 22:51:51 -0700 Subject: [PATCH 03/18] dump: Fix crash during print string arguments It used fixed size (64) buffer for printing a string argument. So its length is longer than that, it would have undefined behavior. Signed-off-by: Namhyung Kim --- cmd-dump.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cmd-dump.c b/cmd-dump.c index 0048cb2a5..454b0f923 100644 --- a/cmd-dump.c +++ b/cmd-dump.c @@ -313,10 +313,11 @@ static void pr_args(struct fstack_arguments *args) if (spec->fmt == ARG_FMT_STR || spec->fmt == ARG_FMT_STD_STRING) { - char buf[64] = {0}; + char *buf; const int null_str = -1; size = *(unsigned short *)ptr; + buf = xmalloc(size + 1); strncpy(buf, ptr + 2, size); if (!memcmp(buf, &null_str, 4)) @@ -326,6 +327,8 @@ static void pr_args(struct fstack_arguments *args) pr_out(" args[%d] std::string: %s\n", i , buf); else pr_out(" args[%d] str: %s\n", i , buf); + + free(buf); size += 2; } else { From 6ab3ed19f7bdf2b302bedb946c660284e1535553 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Sun, 10 Sep 2017 18:25:42 +0900 Subject: [PATCH 04/18] filter: Rename to have uftrace prefix s/ftrace/uftrace/ Signed-off-by: Namhyung Kim --- arch/aarch64/mcount-support.c | 8 +- arch/arm/mcount-support.c | 8 +- arch/x86_64/mcount-support.c | 8 +- cmd-dump.c | 4 +- cmd-record.c | 10 +- cmd-replay.c | 4 +- cmd-script.c | 2 +- libmcount/mcount.c | 34 +++---- libmcount/mcount.h | 12 +-- libmcount/plthook.c | 2 +- libmcount/record.c | 2 +- utils/filter.c | 174 +++++++++++++++++----------------- utils/filter.h | 34 +++---- utils/fstack.c | 44 ++++----- utils/fstack.h | 4 +- utils/kernel.c | 2 +- utils/script-python.c | 2 +- 17 files changed, 177 insertions(+), 177 deletions(-) diff --git a/arch/aarch64/mcount-support.c b/arch/aarch64/mcount-support.c index 69ead2d65..d964fb4c2 100644 --- a/arch/aarch64/mcount-support.c +++ b/arch/aarch64/mcount-support.c @@ -8,7 +8,7 @@ #include "utils/filter.h" int mcount_get_register_arg(struct mcount_arg_context *ctx, - struct ftrace_arg_spec *spec) + struct uftrace_arg_spec *spec) { struct mcount_regs *regs = ctx->regs; int reg_idx; @@ -112,7 +112,7 @@ int mcount_get_register_arg(struct mcount_arg_context *ctx, } void mcount_get_stack_arg(struct mcount_arg_context *ctx, - struct ftrace_arg_spec *spec) + struct uftrace_arg_spec *spec) { int offset = 1; @@ -140,7 +140,7 @@ void mcount_get_stack_arg(struct mcount_arg_context *ctx, } void mcount_arch_get_arg(struct mcount_arg_context *ctx, - struct ftrace_arg_spec *spec) + struct uftrace_arg_spec *spec) { /* don't support long double, treat it as double */ if (unlikely(spec->size == 10)) @@ -151,7 +151,7 @@ void mcount_arch_get_arg(struct mcount_arg_context *ctx, } void mcount_arch_get_retval(struct mcount_arg_context *ctx, - struct ftrace_arg_spec *spec) + struct uftrace_arg_spec *spec) { /* don't support long double, treat it as double */ if (unlikely(spec->size == 10)) diff --git a/arch/arm/mcount-support.c b/arch/arm/mcount-support.c index 78ed1a251..eda1282b7 100644 --- a/arch/arm/mcount-support.c +++ b/arch/arm/mcount-support.c @@ -305,7 +305,7 @@ void check_float_abi(void) } int mcount_get_register_arg(struct mcount_arg_context *ctx, - struct ftrace_arg_spec *spec) + struct uftrace_arg_spec *spec) { struct mcount_regs *regs = ctx->regs; int reg_idx; @@ -430,7 +430,7 @@ int mcount_get_register_arg(struct mcount_arg_context *ctx, } void mcount_get_stack_arg(struct mcount_arg_context *ctx, - struct ftrace_arg_spec *spec) + struct uftrace_arg_spec *spec) { int offset = 1; @@ -466,7 +466,7 @@ void mcount_get_stack_arg(struct mcount_arg_context *ctx, } void mcount_arch_get_arg(struct mcount_arg_context *ctx, - struct ftrace_arg_spec *spec) + struct uftrace_arg_spec *spec) { if (!float_abi_checked) check_float_abi(); @@ -480,7 +480,7 @@ void mcount_arch_get_arg(struct mcount_arg_context *ctx, } void mcount_arch_get_retval(struct mcount_arg_context *ctx, - struct ftrace_arg_spec *spec) + struct uftrace_arg_spec *spec) { if (!float_abi_checked) check_float_abi(); diff --git a/arch/x86_64/mcount-support.c b/arch/x86_64/mcount-support.c index 615842b80..6af1b69fc 100644 --- a/arch/x86_64/mcount-support.c +++ b/arch/x86_64/mcount-support.c @@ -12,7 +12,7 @@ #include "utils/filter.h" int mcount_get_register_arg(struct mcount_arg_context *ctx, - struct ftrace_arg_spec *spec) + struct uftrace_arg_spec *spec) { struct mcount_regs *regs = ctx->regs; int reg_idx; @@ -83,7 +83,7 @@ int mcount_get_register_arg(struct mcount_arg_context *ctx, } void mcount_get_stack_arg(struct mcount_arg_context *ctx, - struct ftrace_arg_spec *spec) + struct uftrace_arg_spec *spec) { int offset; @@ -111,14 +111,14 @@ void mcount_get_stack_arg(struct mcount_arg_context *ctx, } void mcount_arch_get_arg(struct mcount_arg_context *ctx, - struct ftrace_arg_spec *spec) + struct uftrace_arg_spec *spec) { if (mcount_get_register_arg(ctx, spec) < 0) mcount_get_stack_arg(ctx, spec); } void mcount_arch_get_retval(struct mcount_arg_context *ctx, - struct ftrace_arg_spec *spec) + struct uftrace_arg_spec *spec) { /* type of return value cannot be FLOAT, so check format instead */ if (spec->fmt != ARG_FMT_FLOAT) diff --git a/cmd-dump.c b/cmd-dump.c index 454b0f923..6d2549454 100644 --- a/cmd-dump.c +++ b/cmd-dump.c @@ -301,7 +301,7 @@ static void pr_hex(uint64_t *offset, void *data, size_t len) static void pr_args(struct fstack_arguments *args) { - struct ftrace_arg_spec *spec; + struct uftrace_arg_spec *spec; void *ptr = args->data; size_t size; int i = 0; @@ -348,7 +348,7 @@ static void pr_args(struct fstack_arguments *args) static void pr_retval(struct fstack_arguments *args) { - struct ftrace_arg_spec *spec; + struct uftrace_arg_spec *spec; void *ptr = args->data; size_t size; int i = 0; diff --git a/cmd-record.c b/cmd-record.c index 2f262b8cd..2e57ebd9c 100644 --- a/cmd-record.c +++ b/cmd-record.c @@ -1298,10 +1298,10 @@ static void save_session_symbols(struct opts *opts) load_symtabs(&symtabs, opts->dirname, symtabs.maps->libname); save_symbol_file(&symtabs, opts->dirname, symtabs.filename); - ftrace_setup_filter_module(opts->filter, &modules, symtabs.filename); - ftrace_setup_filter_module(opts->trigger, &modules, symtabs.filename); - ftrace_setup_filter_module(opts->args, &modules, symtabs.filename); - ftrace_setup_filter_module(opts->retval, &modules, symtabs.filename); + uftrace_setup_filter_module(opts->filter, &modules, symtabs.filename); + uftrace_setup_filter_module(opts->trigger, &modules, symtabs.filename); + uftrace_setup_filter_module(opts->args, &modules, symtabs.filename); + uftrace_setup_filter_module(opts->retval, &modules, symtabs.filename); /* shared libraries */ pr_dbg("try to load modules\n"); @@ -1317,7 +1317,7 @@ static void save_session_symbols(struct opts *opts) } symtabs.maps = NULL; - ftrace_cleanup_filter_module(&modules); + uftrace_cleanup_filter_module(&modules); unload_symtabs(&symtabs); } free(map_list); diff --git a/cmd-replay.c b/cmd-replay.c index 12b2a6bde..f5a2f45cc 100644 --- a/cmd-replay.c +++ b/cmd-replay.c @@ -432,7 +432,7 @@ void get_argspec_string(struct ftrace_task_handle *task, const int null_str = -1; void *data = task->args.data; struct list_head *arg_list = task->args.args; - struct ftrace_arg_spec *spec; + struct uftrace_arg_spec *spec; union { long i; float f; @@ -659,7 +659,7 @@ static int print_graph_rstack(struct ftrace_file_handle *handle, struct fstack *fstack; int rstack_depth = rstack->depth; int depth; - struct ftrace_trigger tr = { + struct uftrace_trigger tr = { .flags = 0, }; int ret; diff --git a/cmd-script.c b/cmd-script.c index 1ca580911..e369cc96a 100644 --- a/cmd-script.c +++ b/cmd-script.c @@ -38,7 +38,7 @@ static int run_script_for_rstack(struct ftrace_file_handle *handle, if (rstack->type == UFTRACE_ENTRY) { struct fstack *fstack; int depth; - struct ftrace_trigger tr = { + struct uftrace_trigger tr = { .flags = 0, }; int ret; diff --git a/libmcount/mcount.c b/libmcount/mcount.c index c28c6475c..aab6e8802 100644 --- a/libmcount/mcount.c +++ b/libmcount/mcount.c @@ -407,7 +407,7 @@ extern void * get_argbuf(struct mcount_thread_data *, struct mcount_ret_stack *) /* update filter state from trigger result */ enum filter_result mcount_entry_filter_check(struct mcount_thread_data *mtdp, unsigned long child, - struct ftrace_trigger *tr) + struct uftrace_trigger *tr) { pr_dbg3("<%d> enter %lx\n", mtdp->idx, child); @@ -473,7 +473,7 @@ enum filter_result mcount_entry_filter_check(struct mcount_thread_data *mtdp, /* save current filter state to rstack */ void mcount_entry_filter_record(struct mcount_thread_data *mtdp, struct mcount_ret_stack *rstack, - struct ftrace_trigger *tr, + struct uftrace_trigger *tr, struct mcount_regs *regs) { if (mtdp->filter.out_count > 0 || @@ -681,7 +681,7 @@ void mcount_exit_filter_record(struct mcount_thread_data *mtdp, #else /* DISABLE_MCOUNT_FILTER */ enum filter_result mcount_entry_filter_check(struct mcount_thread_data *mtdp, unsigned long child, - struct ftrace_trigger *tr) + struct uftrace_trigger *tr) { if (mcount_check_rstack(mtdp)) return FILTER_RSTACK; @@ -691,7 +691,7 @@ enum filter_result mcount_entry_filter_check(struct mcount_thread_data *mtdp, void mcount_entry_filter_record(struct mcount_thread_data *mtdp, struct mcount_ret_stack *rstack, - struct ftrace_trigger *tr, + struct uftrace_trigger *tr, struct mcount_regs *regs) { mtdp->record_idx++; @@ -727,7 +727,7 @@ int mcount_entry(unsigned long *parent_loc, unsigned long child, enum filter_result filtered; struct mcount_thread_data *mtdp; struct mcount_ret_stack *rstack; - struct ftrace_trigger tr; + struct uftrace_trigger tr; if (unlikely(mcount_should_stop())) return -1; @@ -812,7 +812,7 @@ static int cygprof_entry(unsigned long parent, unsigned long child) enum filter_result filtered; struct mcount_thread_data *mtdp; struct mcount_ret_stack *rstack; - struct ftrace_trigger tr = { + struct uftrace_trigger tr = { .flags = 0, }; @@ -915,7 +915,7 @@ void xray_entry(unsigned long parent, unsigned long child, enum filter_result filtered; struct mcount_thread_data *mtdp; struct mcount_ret_stack *rstack; - struct ftrace_trigger tr = { + struct uftrace_trigger tr = { .flags = 0, }; @@ -1261,18 +1261,18 @@ static void mcount_startup(void) load_symtabs(&symtabs, NULL, mcount_exename); #ifndef DISABLE_MCOUNT_FILTER - ftrace_setup_filter_module(filter_str, &modules, mcount_exename); - ftrace_setup_filter_module(trigger_str, &modules, mcount_exename); - ftrace_setup_filter_module(argument_str, &modules, mcount_exename); - ftrace_setup_filter_module(retval_str, &modules, mcount_exename); + uftrace_setup_filter_module(filter_str, &modules, mcount_exename); + uftrace_setup_filter_module(trigger_str, &modules, mcount_exename); + uftrace_setup_filter_module(argument_str, &modules, mcount_exename); + uftrace_setup_filter_module(retval_str, &modules, mcount_exename); load_module_symtabs(&symtabs, &modules, nest_libcall); - ftrace_setup_filter(filter_str, &symtabs, &mcount_triggers, + uftrace_setup_filter(filter_str, &symtabs, &mcount_triggers, &mcount_filter_mode); - ftrace_setup_trigger(trigger_str, &symtabs, &mcount_triggers); - ftrace_setup_argument(argument_str, &symtabs, &mcount_triggers); - ftrace_setup_retval(retval_str, &symtabs, &mcount_triggers); + uftrace_setup_trigger(trigger_str, &symtabs, &mcount_triggers); + uftrace_setup_argument(argument_str, &symtabs, &mcount_triggers); + uftrace_setup_retval(retval_str, &symtabs, &mcount_triggers); if (getenv("UFTRACE_DEPTH")) mcount_depth = strtol(getenv("UFTRACE_DEPTH"), NULL, 0); @@ -1309,7 +1309,7 @@ static void mcount_startup(void) script_str = NULL; #ifndef DISABLE_MCOUNT_FILTER - ftrace_cleanup_filter_module(&modules); + uftrace_cleanup_filter_module(&modules); #endif /* DISABLE_MCOUNT_FILTER */ compiler_barrier(); @@ -1325,7 +1325,7 @@ static void mcount_cleanup(void) destroy_dynsym_indexes(); #ifndef DISABLE_MCOUNT_FILTER - ftrace_cleanup_filter(&mcount_triggers); + uftrace_cleanup_filter(&mcount_triggers); #endif if (SCRIPT_ENABLED && script_str) script_finish(); diff --git a/libmcount/mcount.h b/libmcount/mcount.h index a40f5a272..a9cc2ee33 100644 --- a/libmcount/mcount.h +++ b/libmcount/mcount.h @@ -247,8 +247,8 @@ static inline bool mcount_should_stop(void) return mcount_global_flags != 0UL; } -struct ftrace_trigger; -struct ftrace_arg_spec; +struct uftrace_trigger; +struct uftrace_arg_spec; struct mcount_regs; struct mcount_arg_context { @@ -268,16 +268,16 @@ struct mcount_arg_context { }; extern void mcount_arch_get_arg(struct mcount_arg_context *ctx, - struct ftrace_arg_spec *spec); + struct uftrace_arg_spec *spec); extern void mcount_arch_get_retval(struct mcount_arg_context *ctx, - struct ftrace_arg_spec *spec); + struct uftrace_arg_spec *spec); extern enum filter_result mcount_entry_filter_check(struct mcount_thread_data *mtdp, unsigned long child, - struct ftrace_trigger *tr); + struct uftrace_trigger *tr); extern void mcount_entry_filter_record(struct mcount_thread_data *mtdp, struct mcount_ret_stack *rstack, - struct ftrace_trigger *tr, + struct uftrace_trigger *tr, struct mcount_regs *regs); extern void mcount_exit_filter_record(struct mcount_thread_data *mtdp, struct mcount_ret_stack *rstack, diff --git a/libmcount/plthook.c b/libmcount/plthook.c index 72d98e12f..e688a503b 100644 --- a/libmcount/plthook.c +++ b/libmcount/plthook.c @@ -705,7 +705,7 @@ unsigned long plthook_entry(unsigned long *ret_addr, unsigned long child_idx, unsigned long child_ip; struct mcount_thread_data *mtdp; struct mcount_ret_stack *rstack; - struct ftrace_trigger tr = { + struct uftrace_trigger tr = { .flags = 0, }; bool skip = false; diff --git a/libmcount/record.c b/libmcount/record.c index a63b606c2..25d08af05 100644 --- a/libmcount/record.c +++ b/libmcount/record.c @@ -231,7 +231,7 @@ void *get_argbuf(struct mcount_thread_data *mtdp, static unsigned save_to_argbuf(void *argbuf, struct list_head *args_spec, struct mcount_arg_context *ctx) { - struct ftrace_arg_spec *spec; + struct uftrace_arg_spec *spec; unsigned size, total_size = 0; unsigned max_size = ARGBUF_SIZE - sizeof(size); bool is_retval = !!ctx->retval; diff --git a/utils/filter.c b/utils/filter.c index 76e0360ad..40f163ede 100644 --- a/utils/filter.c +++ b/utils/filter.c @@ -30,7 +30,7 @@ static void snprintf_trigger_read(char *buf, size_t len, snprintf(buf, len, "%s%s", buf[0] ? "|" : "", "page-fault"); } -static void print_trigger(struct ftrace_trigger *tr) +static void print_trigger(struct uftrace_trigger *tr) { if (tr->flags & TRIGGER_FL_DEPTH) pr_dbg("\ttrigger: depth %d\n", tr->depth); @@ -54,7 +54,7 @@ static void print_trigger(struct ftrace_trigger *tr) pr_dbg("\ttrigger: finish\n"); if (tr->flags & TRIGGER_FL_ARGUMENT) { - struct ftrace_arg_spec *arg; + struct uftrace_arg_spec *arg; pr_dbg("\ttrigger: argument\n"); list_for_each_entry(arg, tr->pargs, list) { @@ -65,7 +65,7 @@ static void print_trigger(struct ftrace_trigger *tr) } } if (tr->flags & TRIGGER_FL_RETVAL) { - struct ftrace_arg_spec *arg; + struct uftrace_arg_spec *arg; pr_dbg("\ttrigger: return value\n"); list_for_each_entry(arg, tr->pargs, list) { @@ -89,7 +89,7 @@ static void print_trigger(struct ftrace_trigger *tr) } } -static bool match_ip(struct ftrace_filter *filter, unsigned long ip) +static bool match_ip(struct uftrace_filter *filter, unsigned long ip) { return filter->start <= ip && ip < filter->end; } @@ -100,16 +100,16 @@ static bool match_ip(struct ftrace_filter *filter, unsigned long ip) * @root - root of rbtree which has filters * @tr - trigger data */ -struct ftrace_filter *uftrace_match_filter(uint64_t ip, struct rb_root *root, - struct ftrace_trigger *tr) +struct uftrace_filter *uftrace_match_filter(uint64_t ip, struct rb_root *root, + struct uftrace_trigger *tr) { struct rb_node *parent = NULL; struct rb_node **p = &root->rb_node; - struct ftrace_filter *iter; + struct uftrace_filter *iter; while (*p) { parent = *p; - iter = rb_entry(parent, struct ftrace_filter, node); + iter = rb_entry(parent, struct uftrace_filter, node); if (match_ip(iter, ip)) { memcpy(tr, &iter->trigger, sizeof(*tr)); @@ -128,11 +128,11 @@ struct ftrace_filter *uftrace_match_filter(uint64_t ip, struct rb_root *root, return NULL; } -static void add_arg_spec(struct list_head *arg_list, struct ftrace_arg_spec *arg, +static void add_arg_spec(struct list_head *arg_list, struct uftrace_arg_spec *arg, bool exact_match) { bool found = false; - struct ftrace_arg_spec *oarg, *narg; + struct uftrace_arg_spec *oarg, *narg; list_for_each_entry(oarg, arg_list, list) { switch (arg->type) { @@ -180,7 +180,7 @@ static void add_arg_spec(struct list_head *arg_list, struct ftrace_arg_spec *arg } } -static void add_trigger(struct ftrace_filter *filter, struct ftrace_trigger *tr, +static void add_trigger(struct uftrace_filter *filter, struct uftrace_trigger *tr, bool exact_match) { filter->trigger.flags |= tr->flags; @@ -196,7 +196,7 @@ static void add_trigger(struct ftrace_filter *filter, struct ftrace_trigger *tr, filter->trigger.flags &= ~TRIGGER_FL_TRACE_ON; if (tr->flags & (TRIGGER_FL_ARGUMENT | TRIGGER_FL_RETVAL)) { - struct ftrace_arg_spec *arg; + struct uftrace_arg_spec *arg; list_for_each_entry(arg, tr->pargs, list) add_arg_spec(&filter->args, arg, exact_match); @@ -210,12 +210,12 @@ static void add_trigger(struct ftrace_filter *filter, struct ftrace_trigger *tr, filter->trigger.read = tr->read; } -static void add_filter(struct rb_root *root, struct ftrace_filter *filter, - struct ftrace_trigger *tr, bool exact_match) +static void add_filter(struct rb_root *root, struct uftrace_filter *filter, + struct uftrace_trigger *tr, bool exact_match) { struct rb_node *parent = NULL; struct rb_node **p = &root->rb_node; - struct ftrace_filter *iter, *new; + struct uftrace_filter *iter, *new; pr_dbg("add filter for %s\n", filter->name); if (dbg_domain[DBG_FILTER] >= 3) @@ -223,7 +223,7 @@ static void add_filter(struct rb_root *root, struct ftrace_filter *filter, while (*p) { parent = *p; - iter = rb_entry(parent, struct ftrace_filter, node); + iter = rb_entry(parent, struct uftrace_filter, node); if (iter->start == filter->start) { add_trigger(iter, tr, exact_match); @@ -249,9 +249,9 @@ static void add_filter(struct rb_root *root, struct ftrace_filter *filter, } static int add_exact_filter(struct rb_root *root, struct symtab *symtab, - char *filter_str, struct ftrace_trigger *tr) + char *filter_str, struct uftrace_trigger *tr) { - struct ftrace_filter filter; + struct uftrace_filter filter; struct sym *sym; sym = find_symname(symtab, filter_str); @@ -267,9 +267,9 @@ static int add_exact_filter(struct rb_root *root, struct symtab *symtab, } static int add_regex_filter(struct rb_root *root, struct symtab *symtab, - char *filter_str, struct ftrace_trigger *tr) + char *filter_str, struct uftrace_trigger *tr) { - struct ftrace_filter filter; + struct uftrace_filter filter; struct sym *sym; regex_t re; unsigned i; @@ -337,7 +337,7 @@ static int has_shared_object(const char *soname) } /* argument_spec = arg1/i32,arg2/x64,... */ -static int parse_spec(char *str, struct ftrace_arg_spec *arg, char *suffix) +static int parse_spec(char *str, struct uftrace_arg_spec *arg, char *suffix) { int fmt = ARG_FMT_AUTO; int size = sizeof(long); @@ -446,9 +446,9 @@ static int parse_spec(char *str, struct ftrace_arg_spec *arg, char *suffix) } /* argument_spec = arg1/i32,arg2/x64%reg,arg3%stack+1,... */ -static int parse_argument_spec(char *str, struct ftrace_trigger *tr) +static int parse_argument_spec(char *str, struct uftrace_trigger *tr) { - struct ftrace_arg_spec *arg; + struct uftrace_arg_spec *arg; char *suffix; if (!isdigit(str[3])) { @@ -472,9 +472,9 @@ static int parse_argument_spec(char *str, struct ftrace_trigger *tr) return 0; } /* argument_spec = retval/i32 or retval/x64 ... */ -static int parse_retval_spec(char *str, struct ftrace_trigger *tr) +static int parse_retval_spec(char *str, struct uftrace_trigger *tr) { - struct ftrace_arg_spec *arg; + struct uftrace_arg_spec *arg; char *suffix; arg = xmalloc(sizeof(*arg)); @@ -497,9 +497,9 @@ static int parse_retval_spec(char *str, struct ftrace_trigger *tr) } /* argument_spec = fparg1/32,fparg2/64%stack+1,... */ -static int parse_float_argument_spec(char *str, struct ftrace_trigger *tr) +static int parse_float_argument_spec(char *str, struct uftrace_trigger *tr) { - struct ftrace_arg_spec *arg; + struct uftrace_arg_spec *arg; char *suffix; if (!isdigit(str[5])) { @@ -565,7 +565,7 @@ static enum trigger_read_type parse_read_type(char *str) static int setup_module_and_trigger(char *str, struct symtabs *symtabs, struct symtab **psymtab, - struct ftrace_trigger *tr, + struct uftrace_trigger *tr, bool *found_mod) { char *tr_str, *tmp; @@ -716,13 +716,13 @@ static void setup_trigger(char *filter_str, struct symtabs *symtabs, while (name) { struct symtab *symtab = &symtabs->symtab; LIST_HEAD(args); - struct ftrace_trigger tr = { + struct uftrace_trigger tr = { .flags = flags, .pargs = &args, }; int ret = 0; bool mod_found = false; - struct ftrace_arg_spec *arg; + struct uftrace_arg_spec *arg; bool is_regex; if (setup_module_and_trigger(name, symtabs, &symtab, @@ -763,7 +763,7 @@ static void setup_trigger(char *filter_str, struct symtabs *symtabs, name = strtok(NULL, ";"); while (!list_empty(&args)) { - arg = list_first_entry(&args, struct ftrace_arg_spec, list); + arg = list_first_entry(&args, struct uftrace_arg_spec, list); list_del(&arg->list); free(arg); } @@ -774,56 +774,56 @@ static void setup_trigger(char *filter_str, struct symtabs *symtabs, } /** - * ftrace_setup_filter - construct rbtree of filters + * uftrace_setup_filter - construct rbtree of filters * @filter_str - CSV of filter string * @symtabs - symbol tables to find symbol address * @root - root of resulting rbtree * @mode - filter mode: opt-in (-F) or opt-out (-N) */ -void ftrace_setup_filter(char *filter_str, struct symtabs *symtabs, - struct rb_root *root, enum filter_mode *mode) +void uftrace_setup_filter(char *filter_str, struct symtabs *symtabs, + struct rb_root *root, enum filter_mode *mode) { setup_trigger(filter_str, symtabs, root, TRIGGER_FL_FILTER, mode); } /** - * ftrace_setup_trigger - construct rbtree of triggers + * uftrace_setup_trigger - construct rbtree of triggers * @trigger_str - CSV of trigger string (FUNC @ act) * @symtabs - symbol tables to find symbol address * @root - root of resulting rbtree */ -void ftrace_setup_trigger(char *trigger_str, struct symtabs *symtabs, - struct rb_root *root) +void uftrace_setup_trigger(char *trigger_str, struct symtabs *symtabs, + struct rb_root *root) { setup_trigger(trigger_str, symtabs, root, 0, NULL); } /** - * ftrace_setup_argument - construct rbtree of argument + * uftrace_setup_argument - construct rbtree of argument * @args_str - CSV of argument string (FUNC @ arg) * @symtabs - symbol tables to find symbol address * @root - root of resulting rbtree */ -void ftrace_setup_argument(char *args_str, struct symtabs *symtabs, - struct rb_root *root) +void uftrace_setup_argument(char *args_str, struct symtabs *symtabs, + struct rb_root *root) { setup_trigger(args_str, symtabs, root, 0, NULL); } /** - * ftrace_setup_retval - construct rbtree of retval + * uftrace_setup_retval - construct rbtree of retval * @retval_str - CSV of argument string (FUNC @ arg) * @symtabs - symbol tables to find symbol address * @root - root of resulting rbtree */ -void ftrace_setup_retval(char *retval_str, struct symtabs *symtabs, - struct rb_root *root) +void uftrace_setup_retval(char *retval_str, struct symtabs *symtabs, + struct rb_root *root) { setup_trigger(retval_str, symtabs, root, 0, NULL); } -void ftrace_setup_filter_module(char *trigger_str, struct list_head *head, - const char *modname) +void uftrace_setup_filter_module(char *trigger_str, struct list_head *head, + const char *modname) { char *str, *tmp; char *pos, *name, *action; @@ -893,7 +893,7 @@ void ftrace_setup_filter_module(char *trigger_str, struct list_head *head, free(str); } -void ftrace_cleanup_filter_module(struct list_head *head) +void uftrace_cleanup_filter_module(struct list_head *head) { struct filter_module *fm; @@ -905,18 +905,18 @@ void ftrace_cleanup_filter_module(struct list_head *head) } /** - * ftrace_cleanup_filter - delete filters in rbtree + * uftrace_cleanup_filter - delete filters in rbtree * @root - root of the filter rbtree */ -void ftrace_cleanup_filter(struct rb_root *root) +void uftrace_cleanup_filter(struct rb_root *root) { struct rb_node *node; - struct ftrace_filter *filter; - struct ftrace_arg_spec *arg, *tmp; + struct uftrace_filter *filter; + struct uftrace_arg_spec *arg, *tmp; while (!RB_EMPTY_ROOT(root)) { node = rb_first(root); - filter = rb_entry(node, struct ftrace_filter, node); + filter = rb_entry(node, struct uftrace_filter, node); rb_erase(node, root); @@ -929,17 +929,17 @@ void ftrace_cleanup_filter(struct rb_root *root) } /** - * ftrace_print_filter - print all filters in rbtree + * uftrace_print_filter - print all filters in rbtree * @root - root of the filter rbtree */ -void ftrace_print_filter(struct rb_root *root) +void uftrace_print_filter(struct rb_root *root) { struct rb_node *node; - struct ftrace_filter *filter; + struct uftrace_filter *filter; node = rb_first(root); while (node) { - filter = rb_entry(node, struct ftrace_filter, node); + filter = rb_entry(node, struct uftrace_filter, node); pr_dbg("%lx-%lx: %s\n", filter->start, filter->end, filter->name); print_trigger(&filter->trigger); @@ -1004,38 +1004,38 @@ TEST_CASE(filter_setup_exact) }; struct rb_root root = RB_ROOT; struct rb_node *node; - struct ftrace_filter *filter; + struct uftrace_filter *filter; filter_test_load_symtabs(&stabs); /* test1: simple method */ - ftrace_setup_filter("foo::bar", &stabs, &root, NULL); + uftrace_setup_filter("foo::bar", &stabs, &root, NULL); TEST_EQ(RB_EMPTY_ROOT(&root), false); node = rb_first(&root); - filter = rb_entry(node, struct ftrace_filter, node); + filter = rb_entry(node, struct uftrace_filter, node); TEST_STREQ(filter->name, "foo::bar"); TEST_EQ(filter->start, 0x2000UL); TEST_EQ(filter->end, 0x2000UL + 0x1000UL); - ftrace_cleanup_filter(&root); + uftrace_cleanup_filter(&root); TEST_EQ(RB_EMPTY_ROOT(&root), true); /* test2: destructor */ - ftrace_setup_filter("foo::~foo", &stabs, &root, NULL); + uftrace_setup_filter("foo::~foo", &stabs, &root, NULL); TEST_EQ(RB_EMPTY_ROOT(&root), false); node = rb_first(&root); - filter = rb_entry(node, struct ftrace_filter, node); + filter = rb_entry(node, struct uftrace_filter, node); TEST_STREQ(filter->name, "foo::~foo"); TEST_EQ(filter->start, 0x6000UL); TEST_EQ(filter->end, 0x6000UL + 0x1000UL); - ftrace_cleanup_filter(&root); + uftrace_cleanup_filter(&root); TEST_EQ(RB_EMPTY_ROOT(&root), true); /* test3: unknown symbol */ - ftrace_setup_filter("invalid_name", &stabs, &root, NULL); + uftrace_setup_filter("invalid_name", &stabs, &root, NULL); TEST_EQ(RB_EMPTY_ROOT(&root), true); return TEST_OK; @@ -1048,38 +1048,38 @@ TEST_CASE(filter_setup_regex) };; struct rb_root root = RB_ROOT; struct rb_node *node; - struct ftrace_filter *filter; + struct uftrace_filter *filter; filter_test_load_symtabs(&stabs); - ftrace_setup_filter("foo::b.*", &stabs, &root, NULL); + uftrace_setup_filter("foo::b.*", &stabs, &root, NULL); TEST_EQ(RB_EMPTY_ROOT(&root), false); node = rb_first(&root); - filter = rb_entry(node, struct ftrace_filter, node); + filter = rb_entry(node, struct uftrace_filter, node); TEST_STREQ(filter->name, "foo::bar"); TEST_EQ(filter->start, 0x2000UL); TEST_EQ(filter->end, 0x2000UL + 0x1000UL); node = rb_next(node); - filter = rb_entry(node, struct ftrace_filter, node); + filter = rb_entry(node, struct uftrace_filter, node); TEST_STREQ(filter->name, "foo::baz1"); TEST_EQ(filter->start, 0x3000UL); TEST_EQ(filter->end, 0x3000UL + 0x1000UL); node = rb_next(node); - filter = rb_entry(node, struct ftrace_filter, node); + filter = rb_entry(node, struct uftrace_filter, node); TEST_STREQ(filter->name, "foo::baz2"); TEST_EQ(filter->start, 0x4000UL); TEST_EQ(filter->end, 0x4000UL + 0x1000UL); node = rb_next(node); - filter = rb_entry(node, struct ftrace_filter, node); + filter = rb_entry(node, struct uftrace_filter, node); TEST_STREQ(filter->name, "foo::baz3"); TEST_EQ(filter->start, 0x5000UL); TEST_EQ(filter->end, 0x5000UL + 0x1000UL); - ftrace_cleanup_filter(&root); + uftrace_cleanup_filter(&root); TEST_EQ(RB_EMPTY_ROOT(&root), true); return TEST_OK; @@ -1092,32 +1092,32 @@ TEST_CASE(filter_setup_notrace) };; struct rb_root root = RB_ROOT; struct rb_node *node; - struct ftrace_filter *filter; + struct uftrace_filter *filter; enum filter_mode fmode; filter_test_load_symtabs(&stabs); - ftrace_setup_filter("foo::.*", &stabs, &root, &fmode); + uftrace_setup_filter("foo::.*", &stabs, &root, &fmode); TEST_EQ(RB_EMPTY_ROOT(&root), false); TEST_EQ(fmode, FILTER_MODE_IN); - ftrace_setup_filter("!foo::foo", &stabs, &root, &fmode); + uftrace_setup_filter("!foo::foo", &stabs, &root, &fmode); TEST_EQ(RB_EMPTY_ROOT(&root), false); TEST_EQ(fmode, FILTER_MODE_IN); /* overall filter mode doesn't change */ node = rb_first(&root); - filter = rb_entry(node, struct ftrace_filter, node); + filter = rb_entry(node, struct uftrace_filter, node); TEST_STREQ(filter->name, "foo::foo"); TEST_EQ(filter->trigger.flags, TRIGGER_FL_FILTER); TEST_EQ(filter->trigger.fmode, FILTER_MODE_OUT); node = rb_next(node); - filter = rb_entry(node, struct ftrace_filter, node); + filter = rb_entry(node, struct uftrace_filter, node); TEST_STREQ(filter->name, "foo::bar"); TEST_EQ(filter->trigger.flags, TRIGGER_FL_FILTER); TEST_EQ(filter->trigger.fmode, FILTER_MODE_IN); - ftrace_cleanup_filter(&root); + uftrace_cleanup_filter(&root); TEST_EQ(RB_EMPTY_ROOT(&root), true); return TEST_OK; @@ -1130,13 +1130,13 @@ TEST_CASE(filter_match) };; struct rb_root root = RB_ROOT; struct rb_node *node; - struct ftrace_filter *filter; + struct uftrace_filter *filter; enum filter_mode fmode; - struct ftrace_trigger tr; + struct uftrace_trigger tr; filter_test_load_symtabs(&stabs); - ftrace_setup_filter("foo::foo", &stabs, &root, &fmode); + uftrace_setup_filter("foo::foo", &stabs, &root, &fmode); TEST_EQ(RB_EMPTY_ROOT(&root), false); TEST_EQ(fmode, FILTER_MODE_IN); @@ -1158,7 +1158,7 @@ TEST_CASE(filter_match) TEST_EQ(uftrace_match_filter(0x2000, &root, &tr), NULL); TEST_NE(tr.flags, TRIGGER_FL_FILTER); - ftrace_cleanup_filter(&root); + uftrace_cleanup_filter(&root); TEST_EQ(RB_EMPTY_ROOT(&root), true); return TEST_OK; @@ -1171,12 +1171,12 @@ TEST_CASE(trigger_setup) };; struct rb_root root = RB_ROOT; struct rb_node *node; - struct ftrace_filter *filter; - struct ftrace_trigger tr; + struct uftrace_filter *filter; + struct uftrace_trigger tr; filter_test_load_symtabs(&stabs); - ftrace_setup_trigger("foo::bar@depth=2", &stabs, &root); + uftrace_setup_trigger("foo::bar@depth=2", &stabs, &root); TEST_EQ(RB_EMPTY_ROOT(&root), false); memset(&tr, 0, sizeof(tr)); @@ -1184,23 +1184,23 @@ TEST_CASE(trigger_setup) TEST_EQ(tr.flags, TRIGGER_FL_DEPTH); TEST_EQ(tr.depth, 2); - ftrace_setup_trigger("foo::bar@backtrace", &stabs, &root); + uftrace_setup_trigger("foo::bar@backtrace", &stabs, &root); memset(&tr, 0, sizeof(tr)); TEST_NE(uftrace_match_filter(0x2500, &root, &tr), NULL); TEST_EQ(tr.flags, TRIGGER_FL_DEPTH | TRIGGER_FL_BACKTRACE); - ftrace_setup_trigger("foo::baz1@traceon", &stabs, &root); + uftrace_setup_trigger("foo::baz1@traceon", &stabs, &root); memset(&tr, 0, sizeof(tr)); TEST_NE(uftrace_match_filter(0x3000, &root, &tr), NULL); TEST_EQ(tr.flags, TRIGGER_FL_TRACE_ON); - ftrace_setup_trigger("foo::baz3@trace_off,depth=1", &stabs, &root); + uftrace_setup_trigger("foo::baz3@trace_off,depth=1", &stabs, &root); memset(&tr, 0, sizeof(tr)); TEST_NE(uftrace_match_filter(0x5000, &root, &tr), NULL); TEST_EQ(tr.flags, TRIGGER_FL_TRACE_OFF | TRIGGER_FL_DEPTH); TEST_EQ(tr.depth, 1); - ftrace_cleanup_filter(&root); + uftrace_cleanup_filter(&root); TEST_EQ(RB_EMPTY_ROOT(&root), true); return TEST_OK; diff --git a/utils/filter.h b/utils/filter.h index 21bc8cde9..9a39f8cc7 100644 --- a/utils/filter.h +++ b/utils/filter.h @@ -36,7 +36,7 @@ enum filter_mode { FILTER_MODE_OUT, }; -enum ftrace_arg_format { +enum uftrace_arg_format { ARG_FMT_AUTO, ARG_FMT_SINT, ARG_FMT_UINT, @@ -71,10 +71,10 @@ enum trigger_read_type { */ #define RETVAL_IDX 0 -struct ftrace_arg_spec { +struct uftrace_arg_spec { struct list_head list; int idx; - enum ftrace_arg_format fmt; + enum uftrace_arg_format fmt; int size; bool exact; unsigned char type; @@ -84,7 +84,7 @@ struct ftrace_arg_spec { }; }; -struct ftrace_trigger { +struct uftrace_trigger { enum trigger_flag flags; int depth; char color; @@ -94,13 +94,13 @@ struct ftrace_trigger { struct list_head *pargs; }; -struct ftrace_filter { +struct uftrace_filter { struct rb_node node; char *name; unsigned long start; unsigned long end; struct list_head args; - struct ftrace_trigger trigger; + struct uftrace_trigger trigger; }; struct filter_module { @@ -120,25 +120,25 @@ struct uftrace_page_fault { uint64_t minor; }; -typedef void (*trigger_fn_t)(struct ftrace_trigger *tr, void *arg); +typedef void (*trigger_fn_t)(struct uftrace_trigger *tr, void *arg); -void ftrace_setup_filter(char *filter_str, struct symtabs *symtabs, +void uftrace_setup_filter(char *filter_str, struct symtabs *symtabs, struct rb_root *root, enum filter_mode *mode); -void ftrace_setup_trigger(char *trigger_str, struct symtabs *symtabs, +void uftrace_setup_trigger(char *trigger_str, struct symtabs *symtabs, struct rb_root *root); -void ftrace_setup_argument(char *trigger_str, struct symtabs *symtabs, +void uftrace_setup_argument(char *trigger_str, struct symtabs *symtabs, struct rb_root *root); -void ftrace_setup_retval(char *trigger_str, struct symtabs *symtabs, +void uftrace_setup_retval(char *trigger_str, struct symtabs *symtabs, struct rb_root *root); -void ftrace_setup_filter_module(char *trigger_str, struct list_head *head, +void uftrace_setup_filter_module(char *trigger_str, struct list_head *head, const char *modname); -void ftrace_cleanup_filter_module(struct list_head *head); +void uftrace_cleanup_filter_module(struct list_head *head); -struct ftrace_filter *uftrace_match_filter(uint64_t ip, struct rb_root *root, - struct ftrace_trigger *tr); -void ftrace_cleanup_filter(struct rb_root *root); -void ftrace_print_filter(struct rb_root *root); +struct uftrace_filter *uftrace_match_filter(uint64_t ip, struct rb_root *root, + struct uftrace_trigger *tr); +void uftrace_cleanup_filter(struct rb_root *root); +void uftrace_print_filter(struct rb_root *root); char * uftrace_clear_kernel(char *filter_str); diff --git a/utils/fstack.c b/utils/fstack.c index 44a8c9c41..bb48d00de 100644 --- a/utils/fstack.c +++ b/utils/fstack.c @@ -206,13 +206,13 @@ static int setup_filters(struct uftrace_session *s, void *arg) char *filter_str = arg; LIST_HEAD(modules); - ftrace_setup_filter_module(filter_str, &modules, s->exename); + uftrace_setup_filter_module(filter_str, &modules, s->exename); load_module_symtabs(&s->symtabs, &modules, false); - ftrace_setup_filter(filter_str, &s->symtabs, &s->filters, + uftrace_setup_filter(filter_str, &s->symtabs, &s->filters, &fstack_filter_mode); - ftrace_cleanup_filter_module(&modules); + uftrace_cleanup_filter_module(&modules); return 0; } @@ -221,12 +221,12 @@ static int setup_trigger(struct uftrace_session *s, void *arg) char *trigger_str = arg; LIST_HEAD(modules); - ftrace_setup_filter_module(trigger_str, &modules, s->exename); + uftrace_setup_filter_module(trigger_str, &modules, s->exename); load_module_symtabs(&s->symtabs, &modules, false); - ftrace_setup_trigger(trigger_str, &s->symtabs, &s->filters); + uftrace_setup_trigger(trigger_str, &s->symtabs, &s->filters); - ftrace_cleanup_filter_module(&modules); + uftrace_cleanup_filter_module(&modules); return 0; } @@ -296,8 +296,8 @@ static int build_fixup_filter(struct uftrace_session *s, void *arg) size_t i; for (i = 0; i < ARRAY_SIZE(fixup_syms); i++) { - ftrace_setup_trigger((char *)fixup_syms[i], &s->symtabs, - &s->fixups); + uftrace_setup_trigger((char *)fixup_syms[i], &s->symtabs, + &s->fixups); } return 0; } @@ -319,12 +319,12 @@ static int build_arg_spec(struct uftrace_session *s, void *arg) char *argspec = arg; LIST_HEAD(modules); - ftrace_setup_filter_module(argspec, &modules, s->exename); + uftrace_setup_filter_module(argspec, &modules, s->exename); load_module_symtabs(&s->symtabs, &modules, false); - ftrace_setup_argument(argspec, &s->symtabs, &s->filters); + uftrace_setup_argument(argspec, &s->symtabs, &s->filters); - ftrace_cleanup_filter_module(&modules); + uftrace_cleanup_filter_module(&modules); return 0; } @@ -384,7 +384,7 @@ int fstack_setup_filters(struct opts *opts, struct ftrace_file_handle *handle) */ int fstack_entry(struct ftrace_task_handle *task, struct uftrace_record *rstack, - struct ftrace_trigger *tr) + struct uftrace_trigger *tr) { struct fstack *fstack; struct uftrace_session_link *sessions = &task->h->sessions; @@ -419,7 +419,7 @@ int fstack_entry(struct ftrace_task_handle *task, } if (sess) { - struct ftrace_filter *fixup; + struct uftrace_filter *fixup; fixup = uftrace_match_filter(addr, &sess->fixups, tr); if (unlikely(fixup)) { @@ -599,7 +599,7 @@ static int fstack_check_skip(struct ftrace_task_handle *task, struct uftrace_session_link *sessions = &task->h->sessions; struct uftrace_session *sess; uint64_t addr = get_real_address(rstack->addr); - struct ftrace_trigger tr = { 0 }; + struct uftrace_trigger tr = { 0 }; int depth = task->filter.depth; struct fstack *fstack; @@ -680,7 +680,7 @@ struct ftrace_task_handle *fstack_skip(struct ftrace_file_handle *handle, while (true) { struct uftrace_record *next_stack = next->rstack; - struct ftrace_trigger tr = { 0 }; + struct uftrace_trigger tr = { 0 }; /* skip filtered entries until current matching EXIT records */ if (next == task && curr_stack == next_stack && @@ -741,7 +741,7 @@ struct ftrace_task_handle *fstack_skip(struct ftrace_file_handle *handle, bool fstack_check_filter(struct ftrace_task_handle *task) { struct fstack *fstack; - struct ftrace_trigger tr = {}; + struct uftrace_trigger tr = {}; if (task->rstack->type == UFTRACE_ENTRY) { fstack = &task->func_stack[task->stack_count - 1]; @@ -921,7 +921,7 @@ static int __read_task_ustack(struct ftrace_task_handle *task) } static int read_task_arg(struct ftrace_task_handle *task, - struct ftrace_arg_spec *spec) + struct uftrace_arg_spec *spec) { FILE *fp = task->fp; struct fstack_arguments *args = &task->args; @@ -972,9 +972,9 @@ int read_task_args(struct ftrace_task_handle *task, bool is_retval) { struct uftrace_session *sess; - struct ftrace_trigger tr = {}; - struct ftrace_filter *fl; - struct ftrace_arg_spec *arg; + struct uftrace_trigger tr = {}; + struct uftrace_filter *fl; + struct uftrace_arg_spec *arg; int rem; sess = find_task_session(&task->h->sessions, task->tid, rstack->time); @@ -1151,7 +1151,7 @@ get_task_ustack(struct ftrace_file_handle *handle, int idx) */ while (read_task_ustack(handle, task) == 0) { struct uftrace_session *sess; - struct ftrace_trigger tr = {}; + struct uftrace_trigger tr = {}; uint64_t time_filter = handle->time_filter; curr = &task->ustack; @@ -1871,7 +1871,7 @@ TEST_CASE(fstack_skip) { struct ftrace_file_handle *handle = &fstack_test_handle; struct ftrace_task_handle *task; - struct ftrace_trigger tr = { 0, }; + struct uftrace_trigger tr = { 0, }; int i; dbg_domain[DBG_FSTACK] = 1; diff --git a/utils/fstack.h b/utils/fstack.h index e05f41a63..433284030 100644 --- a/utils/fstack.h +++ b/utils/fstack.h @@ -8,7 +8,7 @@ #include "../uftrace.h" struct sym; -struct ftrace_trigger; +struct uftrace_trigger; enum fstack_flag { FSTACK_FL_FILTERED = (1U << 0), @@ -133,7 +133,7 @@ int fstack_setup_filters(struct opts *opts, struct ftrace_file_handle *handle); int fstack_entry(struct ftrace_task_handle *task, struct uftrace_record *rstack, - struct ftrace_trigger *tr); + struct uftrace_trigger *tr); void fstack_exit(struct ftrace_task_handle *task); int fstack_update(int type, struct ftrace_task_handle *task, struct fstack *fstack); diff --git a/utils/kernel.c b/utils/kernel.c index 21ef9fc76..3c1de4b4c 100644 --- a/utils/kernel.c +++ b/utils/kernel.c @@ -1375,7 +1375,7 @@ static int read_kernel_cpu(struct ftrace_file_handle *handle, int cpu) while (read_kernel_cpu_data(kernel, cpu) == 0) { struct uftrace_session *sess = handle->sessions.first; struct ftrace_task_handle *task; - struct ftrace_trigger tr = {}; + struct uftrace_trigger tr = {}; uint64_t real_addr; uint64_t time_filter = handle->time_filter; diff --git a/utils/script-python.c b/utils/script-python.c index 8bbee88ab..7c4338e5a 100644 --- a/utils/script-python.c +++ b/utils/script-python.c @@ -260,7 +260,7 @@ static void setup_common_context(PyObject **pDict, struct script_context *sc_ctx static void setup_argument_context(PyObject **pDict, bool is_retval, struct script_context *sc_ctx) { - struct ftrace_arg_spec *spec; + struct uftrace_arg_spec *spec; void *data = sc_ctx->argbuf; PyObject *args; union { From ff02ed844e9fcfef7b61ec710e1533cbfe54d995 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Fri, 15 Sep 2017 13:57:40 -0700 Subject: [PATCH 05/18] test: Save minimal map info for sessions Later change would require that each session has valid maps at least for one. This patch fixes crash during unit test due to that change. Signed-off-by: Namhyung Kim --- utils/session.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/utils/session.c b/utils/session.c index 6a38ceed7..5477ddb37 100644 --- a/utils/session.c +++ b/utils/session.c @@ -617,6 +617,7 @@ struct sym * task_find_sym_addr(struct uftrace_session_link *sessions, #ifdef UNIT_TEST static struct uftrace_session_link test_sessions; +static const char session_map[] = "00400000-00401000 r-xp 00000000 08:03 4096 unittest\n"; TEST_CASE(session_search) { @@ -635,8 +636,11 @@ TEST_CASE(session_search) .sid = "test", .namelen = 8, /* = strlen("unittest") */ }; + int fd; - close(creat("sid-test.map", 0400)); + fd = creat("sid-test.map", 0400); + write(fd, session_map, sizeof(session_map)-1); + close(fd); create_session(&test_sessions, &msg, ".", "unittest", false); remove("sid-test.map"); } @@ -668,6 +672,7 @@ TEST_CASE(task_search) { struct uftrace_task *task; struct uftrace_session *sess; + int fd; /* 1. create initial task */ { @@ -686,7 +691,9 @@ TEST_CASE(task_search) .time = 100, }; - close(creat("sid-initial.map", 0400)); + fd = creat("sid-initial.map", 0400); + write(fd, session_map, sizeof(session_map)-1); + close(fd); create_session(&test_sessions, &smsg, ".", "unittest", false); create_task(&test_sessions, &tmsg, false, true); remove("sid-initial.map"); @@ -788,7 +795,9 @@ TEST_CASE(task_search) .time = 500, }; - close(creat("sid-after_exec.map", 0400)); + fd = creat("sid-after_exec.map", 0400); + write(fd, session_map, sizeof(session_map)-1); + close(fd); create_session(&test_sessions, &smsg, ".", "unittest", false); create_task(&test_sessions, &tmsg, false, true); remove("sid-after_exec.map"); @@ -947,7 +956,9 @@ TEST_CASE(task_symbol_dlopen) FILE *fp; struct uftrace_dlopen_list *udl; - close(creat("sid-test.map", 0400)); + fp = fopen("sid-test.map", "w"); + fprintf(fp, "00400000-00401000 r-xp 00000000 08:03 4096 unittest\n"); + fclose(fp); fp = fopen("libuftrace-test.so.0.sym", "w"); fprintf(fp, "0100 P __tls_get_addr\n"); From 11087d86f9deee1929f82af8b016f64b59bd47c9 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Sun, 10 Sep 2017 19:47:33 +0900 Subject: [PATCH 06/18] symbol: Load and save all module symbols With --nest-libcall uftrace can trace (library) functions from any modules. To make user easier to setup filters or triggers, it needs to apply them to all available modules. But it's tricky to determine which one is available. Since symbol data is not big (compared to trace data), it'd rather save all symbols unconditionally. Signed-off-by: Namhyung Kim --- cmd-record.c | 17 ++---- libmcount/mcount.c | 31 ++--------- utils/fstack.c | 18 ------ utils/session.c | 2 + utils/symbol.c | 136 +++++++++++---------------------------------- utils/symbol.h | 6 +- 6 files changed, 48 insertions(+), 162 deletions(-) diff --git a/cmd-record.c b/cmd-record.c index 2e57ebd9c..4010114c6 100644 --- a/cmd-record.c +++ b/cmd-record.c @@ -1281,32 +1281,26 @@ static void save_session_symbols(struct opts *opts) for (i = 0; i < maps; i++) { struct symtabs symtabs = { .loaded = false, + .flags = SYMTAB_FL_ADJ_OFFSET, }; struct ftrace_proc_maps *map, *tmp; char sid[20] = { 0, }; - LIST_HEAD(modules); if (sid[0] == '\0') sscanf(map_list[i]->d_name, "sid-%[^.].map", sid); free(map_list[i]); - pr_dbg("reading symbols for session %s\n", sid); + pr_dbg2("reading symbols for session %s\n", sid); read_session_map(opts->dirname, &symtabs, sid); /* main executable */ - pr_dbg("try to load main: %s\n", symtabs.maps->libname); + pr_dbg2("try to load main: %s\n", symtabs.maps->libname); load_symtabs(&symtabs, opts->dirname, symtabs.maps->libname); save_symbol_file(&symtabs, opts->dirname, symtabs.filename); - uftrace_setup_filter_module(opts->filter, &modules, symtabs.filename); - uftrace_setup_filter_module(opts->trigger, &modules, symtabs.filename); - uftrace_setup_filter_module(opts->args, &modules, symtabs.filename); - uftrace_setup_filter_module(opts->retval, &modules, symtabs.filename); - /* shared libraries */ - pr_dbg("try to load modules\n"); - load_module_symtabs(&symtabs, &modules, opts->nest_libcall); - save_module_symtabs(&symtabs, &modules, opts->nest_libcall); + load_module_symtabs(&symtabs); + save_module_symtabs(&symtabs); map = symtabs.maps; while (map) { @@ -1317,7 +1311,6 @@ static void save_session_symbols(struct opts *opts) } symtabs.maps = NULL; - uftrace_cleanup_filter_module(&modules); unload_symtabs(&symtabs); } free(map_list); diff --git a/libmcount/mcount.c b/libmcount/mcount.c index aab6e8802..0ddff0969 100644 --- a/libmcount/mcount.c +++ b/libmcount/mcount.c @@ -35,8 +35,7 @@ uint64_t mcount_threshold; /* nsec */ struct symtabs symtabs = { - .flags = SYMTAB_FL_DEMANGLE | SYMTAB_FL_ADJ_OFFSET | - SYMTAB_FL_SKIP_NORMAL | SYMTAB_FL_SKIP_DYNAMIC, + .flags = SYMTAB_FL_DEMANGLE | SYMTAB_FL_ADJ_OFFSET, }; int shmem_bufsize = SHMEM_BUFFER_SIZE; unsigned long mcount_global_flags = MCOUNT_GFL_SETUP; @@ -1160,17 +1159,12 @@ static void mcount_startup(void) char *threshold_str; char *color_str; char *demangle_str; - char *filter_str; - char *trigger_str; - char *argument_str; - char *retval_str; char *plthook_str; char *patch_str; char *event_str; char *dirname; struct stat statbuf; bool nest_libcall; - LIST_HEAD(modules); if (!(mcount_global_flags & MCOUNT_GFL_SETUP) || mtd.recursion_guard) return; @@ -1191,10 +1185,6 @@ static void mcount_startup(void) color_str = getenv("UFTRACE_COLOR"); threshold_str = getenv("UFTRACE_THRESHOLD"); demangle_str = getenv("UFTRACE_DEMANGLE"); - filter_str = getenv("UFTRACE_FILTER"); - trigger_str = getenv("UFTRACE_TRIGGER"); - argument_str = getenv("UFTRACE_ARGUMENT"); - retval_str = getenv("UFTRACE_RETVAL"); plthook_str = getenv("UFTRACE_PLTHOOK"); patch_str = getenv("UFTRACE_PATCH"); event_str = getenv("UFTRACE_EVENT"); @@ -1250,23 +1240,18 @@ static void mcount_startup(void) symtabs.dirname = dirname; - if (filter_str || trigger_str || argument_str || retval_str || patch_str) - symtabs.flags &= ~SYMTAB_FL_SKIP_NORMAL; - if (plthook_str) - symtabs.flags &= ~SYMTAB_FL_SKIP_DYNAMIC; - mcount_exename = read_exename(); record_proc_maps(dirname, session_name(), &symtabs); set_kernel_base(&symtabs, session_name()); load_symtabs(&symtabs, NULL, mcount_exename); #ifndef DISABLE_MCOUNT_FILTER - uftrace_setup_filter_module(filter_str, &modules, mcount_exename); - uftrace_setup_filter_module(trigger_str, &modules, mcount_exename); - uftrace_setup_filter_module(argument_str, &modules, mcount_exename); - uftrace_setup_filter_module(retval_str, &modules, mcount_exename); + char *filter_str = getenv("UFTRACE_FILTER"); + char *trigger_str = getenv("UFTRACE_TRIGGER"); + char *argument_str = getenv("UFTRACE_ARGUMENT"); + char *retval_str = getenv("UFTRACE_RETVAL"); - load_module_symtabs(&symtabs, &modules, nest_libcall); + load_module_symtabs(&symtabs); uftrace_setup_filter(filter_str, &symtabs, &mcount_triggers, &mcount_filter_mode); @@ -1308,10 +1293,6 @@ static void mcount_startup(void) if (script_init(script_str) < 0) script_str = NULL; -#ifndef DISABLE_MCOUNT_FILTER - uftrace_cleanup_filter_module(&modules); -#endif /* DISABLE_MCOUNT_FILTER */ - compiler_barrier(); pr_dbg("mcount setup done\n"); diff --git a/utils/fstack.c b/utils/fstack.c index bb48d00de..b9bc935a3 100644 --- a/utils/fstack.c +++ b/utils/fstack.c @@ -204,29 +204,17 @@ void setup_task_filter(char *tid_filter, struct ftrace_file_handle *handle) static int setup_filters(struct uftrace_session *s, void *arg) { char *filter_str = arg; - LIST_HEAD(modules); - - uftrace_setup_filter_module(filter_str, &modules, s->exename); - load_module_symtabs(&s->symtabs, &modules, false); uftrace_setup_filter(filter_str, &s->symtabs, &s->filters, &fstack_filter_mode); - - uftrace_cleanup_filter_module(&modules); return 0; } static int setup_trigger(struct uftrace_session *s, void *arg) { char *trigger_str = arg; - LIST_HEAD(modules); - - uftrace_setup_filter_module(trigger_str, &modules, s->exename); - load_module_symtabs(&s->symtabs, &modules, false); uftrace_setup_trigger(trigger_str, &s->symtabs, &s->filters); - - uftrace_cleanup_filter_module(&modules); return 0; } @@ -317,14 +305,8 @@ static void fstack_prepare_fixup(struct ftrace_file_handle *handle) static int build_arg_spec(struct uftrace_session *s, void *arg) { char *argspec = arg; - LIST_HEAD(modules); - - uftrace_setup_filter_module(argspec, &modules, s->exename); - load_module_symtabs(&s->symtabs, &modules, false); uftrace_setup_argument(argspec, &s->symtabs, &s->filters); - - uftrace_cleanup_filter_module(&modules); return 0; } diff --git a/utils/session.c b/utils/session.c index 5477ddb37..ca45ac470 100644 --- a/utils/session.c +++ b/utils/session.c @@ -147,6 +147,8 @@ void create_session(struct uftrace_session_link *sessions, load_symtabs(&s->symtabs, dirname, s->exename); set_kernel_base(&s->symtabs, s->sid); + load_module_symtabs(&s->symtabs); + if (sessions->first == NULL) sessions->first = s; diff --git a/utils/symbol.c b/utils/symbol.c index 249b4bd33..be42f90a4 100644 --- a/utils/symbol.c +++ b/utils/symbol.c @@ -951,93 +951,50 @@ void load_dlopen_symtabs(struct symtabs *symtabs, unsigned long offset, static int load_module_symbol(struct symtab *symtab, const char *symfile, unsigned long offset); -void load_module_symtabs(struct symtabs *symtabs, struct list_head *head, - bool load_all_dynsyms) +void load_module_symtabs(struct symtabs *symtabs) { - struct filter_module *fm; struct ftrace_proc_maps *maps; + static const char * const skip_libs[] = { + /* uftrace internal libraries */ + "libmcount.so", + "libmcount-fast.so", + "libmcount-single.so", + "libmcount-fast-single.so", + /* system base libraries */ + "libc.so.6", + "libgcc_s.so.1", + "libpthread.so.0", + "linux-vdso.so.1", + "linux-gate.so.1", + "ld-linux-x86-64.so.2", + }; + size_t k; + unsigned long flags = symtabs->flags; assert(symtabs->maps); - list_for_each_entry(fm, head, list) { - if (!strcasecmp(fm->name, "main") || - !strcasecmp(fm->name, "PLT") || - !strcasecmp(fm->name, "kernel")) - continue; - - maps = find_map_by_name(symtabs, fm->name); - if (maps == NULL || maps->symtab.nr_sym) - continue; - - if (symtabs->flags & SYMTAB_FL_USE_SYMFILE) { - char *symfile = NULL; - bool ok = false; - unsigned long offset = 0; - - if (symtabs->flags & SYMTAB_FL_ADJ_OFFSET) - offset = maps->start; - - xasprintf(&symfile, "%s/%s.sym", symtabs->dirname, - basename(maps->libname)); - if (!load_module_symbol(&maps->symtab, symfile, offset)) - ok = true; - free(symfile); - - if (ok) - continue; - } + maps = symtabs->maps; + while (maps) { + struct symtab dsymtab = {}; - pr_dbg2("load module symbol: %s\n", maps->libname); - load_symtab(&maps->symtab, maps->libname, - maps->start, symtabs->flags); - } + if (!strcmp(maps->libname, symtabs->filename)) + goto next; + if (maps->libname[0] == '[') + goto next; - if (load_all_dynsyms) { - static const char * const skip_libs[] = { - /* uftrace internal libraries */ - "libmcount.so", - "libmcount-fast.so", - "libmcount-single.so", - "libmcount-fast-single.so", - /* system base libraries */ - "libc.so.6", - "libgcc_s.so.1", - "libpthread.so.0", - "linux-vdso.so.1", - "linux-gate.so.1", - "ld-linux-x86-64.so.2", - }; - size_t k; - - maps = symtabs->maps; - while (maps) { - if (!strcmp(maps->libname, symtabs->filename)) - goto next; - if (maps->libname[0] == '[') + for (k = 0; k < ARRAY_SIZE(skip_libs); k++) { + if (!strcmp(basename(maps->libname), skip_libs[k])) goto next; + } - for (k = 0; k < ARRAY_SIZE(skip_libs); k++) { - if (!strcmp(basename(maps->libname), skip_libs[k])) - goto next; - } - - pr_dbg2("load module dynamic symbol: %s\n", maps->libname); + pr_dbg2("load module symbol table: %s\n", maps->libname); - if (maps->symtab.nr_sym) { - struct symtab dsymtab = {}; - - load_dynsymtab(&dsymtab, maps->libname, - maps->start, symtabs->flags); - merge_symtabs(&maps->symtab, &dsymtab); - } - else { - load_dynsymtab(&maps->symtab, maps->libname, - maps->start, symtabs->flags); - } + load_symtab(&maps->symtab, maps->libname, maps->start, flags); + load_dynsymtab(&dsymtab, maps->libname, maps->start, flags); + merge_symtabs(&maps->symtab, &dsymtab); next: - maps = maps->next; - } + maps = maps->next; } } @@ -1397,39 +1354,13 @@ static void save_module_symbol(struct symtab *stab, const char *symfile, fclose(fp); } -void save_module_symtabs(struct symtabs *symtabs, struct list_head *modules, - bool save_all_dynsyms) +void save_module_symtabs(struct symtabs *symtabs) { char *symfile = NULL; - struct filter_module *fm; struct ftrace_proc_maps *map; - list_for_each_entry(fm, modules, list) { - map = find_map_by_name(symtabs, fm->name); - if (map == NULL) { - pr_dbg("cannot find module: %s\n", fm->name); - continue; - } - - xasprintf(&symfile, "%s/%s.sym", symtabs->dirname, - basename(map->libname)); - - save_module_symbol(&map->symtab, symfile, map->start); - - free(symfile); - symfile = NULL; - } - - if (!save_all_dynsyms) - return; - map = symtabs->maps; while (map) { - list_for_each_entry(fm, modules, list) { - if (!strcmp(fm->name, map->libname)) - goto next; - } - xasprintf(&symfile, "%s/%s.sym", symtabs->dirname, basename(map->libname)); @@ -1438,7 +1369,6 @@ void save_module_symtabs(struct symtabs *symtabs, struct list_head *modules, free(symfile); symfile = NULL; -next: map = map->next; } } diff --git a/utils/symbol.h b/utils/symbol.h index 04b32a343..73e294c66 100644 --- a/utils/symbol.h +++ b/utils/symbol.h @@ -100,10 +100,8 @@ int arch_load_dynsymtab_bindnow(Elf *elf, struct symtab *dsymtab, int load_elf_dynsymtab(struct symtab *dsymtab, Elf *elf, unsigned long offset, unsigned long flags); -void load_module_symtabs(struct symtabs *symtabs, struct list_head *head, - bool load_all_dynsyms); -void save_module_symtabs(struct symtabs *symtabs, struct list_head *head, - bool save_all_dynsyms); +void load_module_symtabs(struct symtabs *symtabs); +void save_module_symtabs(struct symtabs *symtabs); void load_dlopen_symtabs(struct symtabs *symtabs, unsigned long offset, const char *filename); From 91f84d04f1c99c64779c7c4e1cce772d473519f7 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Sun, 10 Sep 2017 21:02:07 +0900 Subject: [PATCH 07/18] filter: Apply filter to all modules by default Change to trigger action (including filter, trigger, argument and return value) to be applied to all modules unless specified explicitly. If module name is given (e.g. -F open@myprog), it would be applied to the module only (like before). Signed-off-by: Namhyung Kim --- utils/filter.c | 94 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 56 insertions(+), 38 deletions(-) diff --git a/utils/filter.c b/utils/filter.c index 40f163ede..61488ae6c 100644 --- a/utils/filter.c +++ b/utils/filter.c @@ -563,10 +563,8 @@ static enum trigger_read_type parse_read_type(char *str) return TRIGGER_READ_NONE; } -static int setup_module_and_trigger(char *str, struct symtabs *symtabs, - struct symtab **psymtab, - struct uftrace_trigger *tr, - bool *found_mod) +static int setup_trigger_action(char *str, struct uftrace_trigger *tr, + char **module) { char *tr_str, *tmp; char *pos = strchr(str, '@'); @@ -670,26 +668,7 @@ static int setup_module_and_trigger(char *str, struct symtabs *symtabs, continue; } - /* module name */ - if (!strcasecmp(pos, "plt")) - *psymtab = &symtabs->dsymtab; - else if (!strcasecmp(pos, "kernel")) - *psymtab = get_kernel_symtab(); - else if (!strcmp(pos, basename(symtabs->filename))) - *psymtab = &symtabs->symtab; - else { - struct ftrace_proc_maps *map; - - map = find_map_by_name(symtabs, pos); - if (map == NULL) { - pr_dbg("cannot find module %s\n", pos); - goto out; - } - - *psymtab = &map->symtab; - } - - *found_mod = true; + *module = xstrdup(pos); } ret = 0; @@ -698,6 +677,16 @@ static int setup_module_and_trigger(char *str, struct symtabs *symtabs, return ret; } +static int add_trigger_entry(struct rb_root *root, struct symtab *symtab, + char *name, bool is_regex, + struct uftrace_trigger *tr) +{ + if (is_regex) + return add_regex_filter(root, symtab, name, tr); + else + return add_exact_filter(root, symtab, name, tr); +} + static void setup_trigger(char *filter_str, struct symtabs *symtabs, struct rb_root *root, unsigned long flags, enum filter_mode *fmode) @@ -714,23 +703,22 @@ static void setup_trigger(char *filter_str, struct symtabs *symtabs, name = strtok(pos, ";"); while (name) { - struct symtab *symtab = &symtabs->symtab; LIST_HEAD(args); struct uftrace_trigger tr = { .flags = flags, .pargs = &args, }; int ret = 0; - bool mod_found = false; + char *module = NULL; struct uftrace_arg_spec *arg; + struct ftrace_proc_maps *map; bool is_regex; - if (setup_module_and_trigger(name, symtabs, &symtab, - &tr, &mod_found) < 0) + if (setup_trigger_action(name, &tr, &module) < 0) goto next; /* skip unintended kernel symbols */ - if (symtab == NULL) + if (module && !strcasecmp(module, "kernel")) goto next; if (name[0] == '!') { @@ -741,16 +729,46 @@ static void setup_trigger(char *filter_str, struct symtabs *symtabs, is_regex = strpbrk(name, REGEX_CHARS); -again: - if (is_regex) - ret += add_regex_filter(root, symtab, name, &tr); - else - ret += add_exact_filter(root, symtab, name, &tr); + if (module) { + map = find_map_by_name(symtabs, module); + if (map == NULL && strcasecmp(module, "PLT")) { + free(module); + goto next; + } + + /* is it the main executable? */ + if (!strncmp(module, basename(symtabs->filename), + strlen(module))) { + ret += add_trigger_entry(root, &symtabs->symtab, + name, is_regex, &tr); + ret += add_trigger_entry(root, &symtabs->dsymtab, + name, is_regex, &tr); + } + else if (!strcasecmp(module, "PLT")) { + ret = add_trigger_entry(root, &symtabs->dsymtab, + name, is_regex, &tr); + } + else { + ret = add_trigger_entry(root, &map->symtab, + name, is_regex, &tr); + } - if (!mod_found && (ret == 0 || is_regex)) { - symtab = &symtabs->dsymtab; - mod_found = true; - goto again; + free(module); + } + else { + /* check main executable's symtab first */ + ret += add_trigger_entry(root, &symtabs->symtab, name, + is_regex, &tr); + ret += add_trigger_entry(root, &symtabs->dsymtab, name, + is_regex, &tr); + + /* and then find all module's symtabs */ + map = symtabs->maps; + while (map) { + ret += add_trigger_entry(root, &map->symtab, + name, is_regex, &tr); + map = map->next; + } } if (ret > 0 && fmode != NULL) { From 926d884e8f46642ff9811e34284f9d7750fc3b7a Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Fri, 15 Sep 2017 18:12:36 -0700 Subject: [PATCH 08/18] symbol: Save correct (relative) symbol address The symbol files intended to save relative addresses so that they can be recalculated to the real address using map info in a session. But it was found that it failed to do so. The SYMTAB_FL_ADJ_OFFSET flag was to adjust current load address with ELF load address to calcuate real symbol address with the offset (especially for main executables and prelink-ed libraries). Signed-off-by: Namhyung Kim --- cmd-record.c | 8 ++++++-- utils/symbol.c | 50 +++++++++----------------------------------------- utils/symbol.h | 2 +- 3 files changed, 16 insertions(+), 44 deletions(-) diff --git a/cmd-record.c b/cmd-record.c index 4010114c6..ae75c5129 100644 --- a/cmd-record.c +++ b/cmd-record.c @@ -948,6 +948,7 @@ static bool check_tid_list(void) struct dlopen_list { struct list_head list; char *libname; + uint64_t addr; }; static LIST_HEAD(dlopen_libs); @@ -1148,6 +1149,7 @@ static void read_record_mmap(int pfd, const char *dirname, int bufsize) dlib = xmalloc(sizeof(*dlib)); dlib->libname = exename; + dlib->addr = dmsg.base_addr; list_add_tail(&dlib->list, &dlopen_libs); write_dlopen_info(dirname, &dmsg, exename); @@ -1296,7 +1298,8 @@ static void save_session_symbols(struct opts *opts) /* main executable */ pr_dbg2("try to load main: %s\n", symtabs.maps->libname); load_symtabs(&symtabs, opts->dirname, symtabs.maps->libname); - save_symbol_file(&symtabs, opts->dirname, symtabs.filename); + save_symbol_file(&symtabs, opts->dirname, symtabs.filename, + symtabs.maps->start); /* shared libraries */ load_module_symtabs(&symtabs); @@ -1734,7 +1737,8 @@ static void write_symbol_files(struct writer_data *wd, struct opts *opts) }; load_symtabs(&dlib_symtabs, opts->dirname, dlib->libname); - save_symbol_file(&dlib_symtabs, opts->dirname, dlib->libname); + save_symbol_file(&dlib_symtabs, opts->dirname, dlib->libname, + dlib->addr); list_del(&dlib->list); diff --git a/utils/symbol.c b/utils/symbol.c index be42f90a4..29c84eb50 100644 --- a/utils/symbol.c +++ b/utils/symbol.c @@ -1131,18 +1131,13 @@ int load_symbol_file(struct symtabs *symtabs, const char *symfile, } void save_symbol_file(struct symtabs *symtabs, const char *dirname, - const char *exename) + const char *exename, unsigned long base_addr) { FILE *fp; unsigned i; char *symfile = NULL; struct symtab *stab = &symtabs->symtab; struct symtab *dtab = &symtabs->dsymtab; - unsigned long offset = 0; - int fd; - Elf *elf = NULL; - GElf_Phdr phdr; - size_t nr = 0; xasprintf(&symfile, "%s/%s.sym", dirname, basename(exename)); @@ -1155,56 +1150,29 @@ void save_symbol_file(struct symtabs *symtabs, const char *dirname, pr_dbg2("saving symbols to %s\n", symfile); - fd = open(exename, O_RDONLY); - if (fd < 0) { - pr_dbg("error during open elf file: %s: %m\n", exename); - goto do_it; - } - - elf_version(EV_CURRENT); - - elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); - if (elf == NULL) - goto do_it; - - if (elf_getphdrnum(elf, &nr) < 0) - goto do_it; - - for (i = 0; i < nr; i++) { - if (!gelf_getphdr(elf, i, &phdr)) - break; - if (phdr.p_type == PT_LOAD) { - offset = phdr.p_vaddr; - break; - } - } - - /* save relative offset of symbol address */ - symtabs->flags |= SYMTAB_FL_ADJ_OFFSET; - -do_it: /* dynamic symbols */ - for (i = 0; i < dtab->nr_sym; i++) - fprintf(fp, "%016"PRIx64" %c %s\n", dtab->sym_names[i]->addr - offset, + for (i = 0; i < dtab->nr_sym; i++) { + fprintf(fp, "%016"PRIx64" %c %s\n", + dtab->sym_names[i]->addr - base_addr, (char) dtab->sym_names[i]->type, dtab->sym_names[i]->name); + } /* this last entry should come from ->sym[] to know the real end */ if (i > 0) { - fprintf(fp, "%016"PRIx64" %c %s\n", dtab->sym[i-1].addr + dtab->sym[i-1].size - offset, + fprintf(fp, "%016"PRIx64" %c %s\n", + dtab->sym[i-1].addr + dtab->sym[i-1].size - base_addr, (char) dtab->sym[i-1].type, "__dynsym_end"); } /* normal symbols */ for (i = 0; i < stab->nr_sym; i++) - fprintf(fp, "%016"PRIx64" %c %s\n", stab->sym[i].addr - offset, + fprintf(fp, "%016"PRIx64" %c %s\n", stab->sym[i].addr - base_addr, (char) stab->sym[i].type, stab->sym[i].name); if (i > 0) { fprintf(fp, "%016"PRIx64" %c %s\n", - stab->sym[i-1].addr + stab->sym[i-1].size - offset, + stab->sym[i-1].addr + stab->sym[i-1].size - base_addr, (char) stab->sym[i-1].type, "__sym_end"); } - elf_end(elf); - close(fd); free(symfile); fclose(fp); } diff --git a/utils/symbol.h b/utils/symbol.h index 73e294c66..5aa1d6321 100644 --- a/utils/symbol.h +++ b/utils/symbol.h @@ -122,7 +122,7 @@ struct symtab * get_kernel_symtab(void); int load_symbol_file(struct symtabs *symtabs, const char *symfile, unsigned long offset); void save_symbol_file(struct symtabs *symtabs, const char *dirname, - const char *exename); + const char *exename, unsigned long addr); char *symbol_getname(struct sym *sym, uint64_t addr); void symbol_putname(struct sym *sym, char *name); From e4022e029af25cf327ec3c3f886929e407216615 Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Thu, 21 Sep 2017 23:01:06 -0700 Subject: [PATCH 09/18] symbol: Save correct addresses for dlopen() It failed to save relative addresses for dlopen-ed libraries. So it makes the dlopen test case failed - fix it. Signed-off-by: Namhyung Kim --- cmd-record.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/cmd-record.c b/cmd-record.c index ae75c5129..430356914 100644 --- a/cmd-record.c +++ b/cmd-record.c @@ -1732,16 +1732,25 @@ static void write_symbol_files(struct writer_data *wd, struct opts *opts) /* dynamically loaded libraries using dlopen() */ list_for_each_entry_safe(dlib, tmp, &dlopen_libs, list) { + struct ftrace_proc_maps *dlib_map; struct symtabs dlib_symtabs = { - .loaded = false, + .flags = SYMTAB_FL_ADJ_OFFSET, }; + dlib_map = xzalloc(sizeof(*dlib_map) + strlen(dlib->libname) + 1); + dlib_map->start = dlib->addr; + memcpy(dlib_map->libname, dlib->libname, strlen(dlib->libname) + 1); + dlib_symtabs.maps = dlib_map; + load_symtabs(&dlib_symtabs, opts->dirname, dlib->libname); save_symbol_file(&dlib_symtabs, opts->dirname, dlib->libname, dlib->addr); list_del(&dlib->list); + unload_symtabs(&dlib_symtabs); + free(dlib_map); + free(dlib->libname); free(dlib); } From 12aacbef56bde76798eb2dd62e0c523c3e3ca56e Mon Sep 17 00:00:00 2001 From: Namhyung Kim Date: Thu, 21 Sep 2017 22:59:58 -0700 Subject: [PATCH 10/18] test: Fix arg-module test result It now applies argument setting to PLT functions in modules too. Signed-off-by: Namhyung Kim --- tests/t127_arg_module.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/t127_arg_module.py b/tests/t127_arg_module.py index 16aab795e..28c4ab847 100644 --- a/tests/t127_arg_module.py +++ b/tests/t127_arg_module.py @@ -14,7 +14,7 @@ def __init__(self): [32130] | alloc3(1) { [32130] | alloc4(1) { [32130] | alloc5(1) { - 1.850 us [32130] | malloc(); + 1.850 us [32130] | malloc(1); 4.284 us [32130] | } /* alloc5 */ 11.517 us [32130] | } /* alloc4 */ 12.357 us [32130] | } /* alloc3 */ From 732e8d8785c0720b272c016a9e58837ed12e8d88 Mon Sep 17 00:00:00 2001 From: Honggyu Kim Date: Mon, 18 Sep 2017 17:50:19 +0900 Subject: [PATCH 11/18] Add some more git ignore rules This adds *.sw[opn], *.patch and .orig rules to .gitignore. Signed-off-by: Honggyu Kim --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index eb7a67dd0..1d6837249 100644 --- a/.gitignore +++ b/.gitignore @@ -31,3 +31,6 @@ TAGS tags cscope.* *.pyc +*.sw[opn] +*.patch +*.orig From 458b48480bc056b476b46ea1f10b6c2131377c02 Mon Sep 17 00:00:00 2001 From: Honggyu Kim Date: Tue, 12 Sep 2017 20:03:56 +0900 Subject: [PATCH 12/18] uftrace: Add --auto-args option This is a preparation for adding a new option --auto-args, which displays arguments / return values for known library functions such as libc functions. Signed-off-by: Honggyu Kim --- cmd-record.c | 3 +++ doc/uftrace-record.md | 3 +++ uftrace.c | 6 ++++++ uftrace.h | 1 + 4 files changed, 13 insertions(+) diff --git a/cmd-record.c b/cmd-record.c index 430356914..f201c24d2 100644 --- a/cmd-record.c +++ b/cmd-record.c @@ -153,6 +153,9 @@ static void setup_child_environ(struct opts *opts, int pfd) } } + if (opts->auto_args) + setenv("UFTRACE_AUTO_ARGS", "1", 1); + if (opts->patch) { char *patch_str = uftrace_clear_kernel(opts->patch); diff --git a/doc/uftrace-record.md b/doc/uftrace-record.md index ebde57a01..77631404c 100644 --- a/doc/uftrace-record.md +++ b/doc/uftrace-record.md @@ -81,6 +81,9 @@ OPTIONS -R *SPEC*, \--retval=*SPEC* : Record function return values. This option can be used more than once. See *ARGUMENTS*. +\--auto-args +: Automatically record arguments and return values of well-known library functions. Recommend to use it with `--nest-libcall`. + \--num-thread=*NUM* : Use NUM threads to record trace data. Default is 1/4 of online CPUs (but when full kernel tracing is enabled, it will use the full number of CPUs). diff --git a/uftrace.c b/uftrace.c index fa13899b6..dbe71f3e5 100644 --- a/uftrace.c +++ b/uftrace.c @@ -90,6 +90,7 @@ enum options { OPT_event_full, OPT_nest_libcall, OPT_record, + OPT_auto_args, }; static struct argp_option uftrace_options[] = { @@ -159,6 +160,7 @@ static struct argp_option uftrace_options[] = { { "event-full", OPT_event_full, 0, 0, "Show all events outside of function" }, { "nest-libcall", OPT_nest_libcall, 0, 0, "Show nested library calls" }, { "record", OPT_record, 0, 0, "Record a new trace data before running command" }, + { "auto-args", OPT_auto_args, 0, 0, "Show function arguments/return values for useful libc functions" }, { 0 } }; @@ -693,6 +695,10 @@ static error_t parse_option(int key, char *arg, struct argp_state *state) opts->record = true; break; + case OPT_auto_args: + opts->auto_args = true; + break; + case ARGP_KEY_ARG: if (state->arg_num) { /* diff --git a/uftrace.h b/uftrace.h index 108016b38..066ecbe44 100644 --- a/uftrace.h +++ b/uftrace.h @@ -234,6 +234,7 @@ struct opts { bool event_skip_out; bool nest_libcall; bool record; + bool auto_args; struct uftrace_time_range range; }; From 1c18dee10763d8ed7a3578cfbd13c5b614fcb488 Mon Sep 17 00:00:00 2001 From: Honggyu Kim Date: Wed, 13 Sep 2017 15:44:32 +0900 Subject: [PATCH 13/18] record: Limit the length of string of args/retval Since some of strings are too long to store inside buffer, it sometimes exceeds ARGBUF_SIZE and fails. This patch limits the maximum string size is to 48 with NULL to prevent such problems. Signed-off-by: Honggyu Kim --- libmcount/record.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/libmcount/record.c b/libmcount/record.c index 25d08af05..f86636099 100644 --- a/libmcount/record.c +++ b/libmcount/record.c @@ -18,6 +18,8 @@ #define SHMEM_SESSION_FMT "/uftrace-%s-%d-%03d" /* session-id, tid, seq */ +#define ARGS_STR_LIMIT 48 + static struct mcount_shmem_buffer *allocate_shmem_buffer(char *buf, size_t size, int tid, int idx) { @@ -276,7 +278,14 @@ static unsigned save_to_argbuf(void *argbuf, struct list_head *args_spec, len = 0; for (i = 0; i < max_size - total_size; i++) { dst[i] = str[i]; - if (!str[i]) + /* maximum length is 48 characters */ + if (i > ARGS_STR_LIMIT) { + dst[i-3] = '.'; + dst[i-2] = '.'; + dst[i-1] = '.'; + dst[i] = '\0'; + } + if (!dst[i]) break; len++; } From fcdfcbdf1e1dd0521e56db1568f02e056e9d9e24 Mon Sep 17 00:00:00 2001 From: Honggyu Kim Date: Mon, 18 Sep 2017 16:24:05 +0900 Subject: [PATCH 14/18] misc: Add args/retval format generator from prototype This adds a list prototypes of well-known library functions in "prototypes.h" and its parser that generates uftrace format argspec. The usage is as follows: $ ./misc/gen-autoargs.py -i ./misc/prototypes.h Then it generates "autoargs.h" that can be directly included by uftrace for --auto-args option support. In the below example, "simple_prototypes.h" has only 5 functions. It can be passed to "gen-autoargs.py" and the output is as follows: $ cat simple_prototypes.h void *malloc(size_t size); void free(void* ptr); const char* strcpy(char* dest, const char* src); int open(const char* pathname, int flags); int pthread_mutex_lock(pthread_mutex_t *mutex); $ ./gen-autoargs.py simple_prototypes.h GEN autoargs.h $ cat autoargs.h ... static char *auto_args_list = "malloc@arg1/u;" "free@arg1/x;" "strcpy@arg1/s,arg2/s;" "open@arg1/s,arg2;" "pthread_mutex_lock@arg1/x;" ; static char *auto_retvals_list = "malloc@retval/x;" "strcpy@retval/s;" "open@retval;" "pthread_mutex_lock@retval;" ; Signed-off-by: Honggyu Kim --- misc/gen-autoargs.py | 271 +++++++++++++++++++++++++++++++++++++++++++ misc/prototypes.h | 224 +++++++++++++++++++++++++++++++++++ 2 files changed, 495 insertions(+) create mode 100755 misc/gen-autoargs.py create mode 100644 misc/prototypes.h diff --git a/misc/gen-autoargs.py b/misc/gen-autoargs.py new file mode 100755 index 000000000..4d649c6d4 --- /dev/null +++ b/misc/gen-autoargs.py @@ -0,0 +1,271 @@ +#!/usr/bin/env python + +# +# Arguments / return type option tables generator for automatic value display +# +# Copyright (C) 2017, LG Electronics, Honggyu Kim +# +# Released under the GPL v2. +# + +from __future__ import print_function +import os +import sys +import re + +# The syntax of C in Backus-Naur Form +# https://cs.wmich.edu/~gupta/teaching/cs4850/sumII06/The%20syntax%20of%20C%20in%20Backus-Naur%20form.htm + +# generated file name +argspec_file = "autoargs.h" + +storage_class_specifier = ["auto", "register", "static", "extern", "typedef"] +type_qualifier = ["const", "volatile"] + +type_specifier = ["void", "char", "short", "int", "long", "float", "double", \ + "signed", "unsigned" ] + +struct_or_union_specifier = ["struct", "union"] +enum_specifier = ["enum"] + +typedef_name = [ \ + "size_t", "ssize_t", "pid_t", "off_t", "FILE", \ + "sigset_t", "socklen_t", "intptr_t", "nfds_t", \ + "pthread_t", "pthread_once_t", "pthread_attr_t", \ + "pthread_mutex_t", "pthread_mutexattr_t", \ + ] + +pointer = "*" +reference = "&" + +type_specifier.extend(struct_or_union_specifier) +type_specifier.extend(enum_specifier) +type_specifier.extend(typedef_name) +type_specifier.extend(["std::string"]) + +# The contents of libnames will be made to genearte library name specifier for arg spec +#libnames = ["", "libstdc++"] +libnames = [""] + +header = """\ +/* + * Arguments / return type option tables for automatic value display + * + * This file is auto-generated by "gen-autoargs.py" based on prototypes.h + */ + +""" + +verbose = False + +def parse_return_type(words): + global storage_class_specifier + global type_qualifier + global struct_or_union_specifier + global enum_specifier + global typedef_specifier + global pointer + + i = 0 + return_type = "" + struct_or_union_flag = False + for word in words: + if word in storage_class_specifier: + # skip + pass + elif word in type_qualifier: + # skip + pass + elif word in struct_or_union_specifier: + return_type = word + struct_or_union_flag = True + elif word in type_specifier: + if return_type == "": + return_type = word + else: + return_type += " " + word + elif word == pointer: + return_type += word + elif word == reference: + # skip reference + pass + elif struct_or_union_flag: + return_type += " " + word + struct_or_union_flag = False + elif word == ",": + pass + else: + break + i += 1 + return (return_type, words[i:]) + + +def parse_func_name(words): + funcname = words[0] + return (funcname, words[1:]) + + +def parse_args(words): + if words[0] != '(' and words[-1] != ')': + return [] # fail + + arg_type = [] + struct_or_union_flag = False + for word in words[1:-1]: + if word in type_qualifier: + # skip + pass + elif word in struct_or_union_specifier: + arg_type.append(word) + struct_or_union_flag = True + elif word in type_specifier: + arg_type.append(word) + elif word == pointer: + arg_type[-1] += pointer + elif word == reference: + # skip reference + pass + elif struct_or_union_flag: + struct_or_union_flag = False + arg_type[-1] += " " + word + elif word == ",": + pass + else: + struct_or_union_flag = False + return arg_type + + +def parse_func_decl(func): + #chunks = re.split('(\W)| |\(|\)|,|;', func) + chunks = re.split('([a-zA-Z0-9_:]+)|\ |(\()|(\))|(,)|;', func) + words = [x for x in chunks if x and x != '' and x != ' ' and x != ';' and x != '\n'] + (return_type, words) = parse_return_type(words) + (funcname, words) = parse_func_name(words) + args = parse_args(words) + return (return_type, funcname, args) + + +def make_uftrace_retval_format(ctype, funcname, libname = ""): + retval_format = "%s@%s" % (funcname, libname) + if libname: + retval_format += "," + + if ctype == "void": + retval_format = "" + pass + elif ctype == "char": + retval_format += "retval/c" + elif ctype == "char*": + retval_format += "retval/s" + elif ctype == "std::string": + retval_format += "retval/S" + elif ctype[-1] == "*": + retval_format += "retval/x" + elif "unsigned" in ctype or ctype == "size_t" or ctype == "pid_t": + retval_format += "retval/u" + else: + retval_format += "retval" + + return retval_format + + +def make_uftrace_args_format(args, funcname, libname = ""): + args_format = "%s@%s" % (funcname, libname) + if libname: + args_format += "," + + i = 0 + for arg in args: + i += 1 + if (i > 1): + args_format += "," + if arg == "void": + args_format = "" + break + elif arg == "char": + args_format += "arg%d/c" % i + elif arg == "char*": + args_format += "arg%d/s" % i + elif arg == "std::string": + args_format += "arg%d/S" % i + elif arg[-1] == "*": + args_format += "arg%d/x" % i + elif "unsigned" in arg or arg == "size_t" or arg == "pid_t": + args_format += "arg%d/u" % i + else: + args_format += "arg%d" % i + + return args_format + + +def parse_argument(): + import argparse + + parser = argparse.ArgumentParser() + parser.add_argument("-i", "--input-file", dest='infile', default="prototypes.h", + help="input prototype header file (default: prototypes.h") + parser.add_argument("-o", "--output-file", dest='outfile', default="autoargs.h", + help="output uftrace argspec file (default: autoargs.h)") + parser.add_argument("-v", "--verbose", dest='verbose', action='store_true', + help="show internal command and result for debugging") + + return parser.parse_args() + + +if __name__ == "__main__": + arg = parse_argument() + if arg.verbose: + print(arg) + + argspec_file = arg.outfile + prototype_file = arg.infile + verbose = arg.verbose + + args_list = "" + retvals_list = "" + + with open(prototype_file) as fin: + for line in fin: + if len(line) <= 1 or line[0] == '#' or line[0:2] == "//" \ + or line[0:7] == "typedef": + continue + + if verbose: + print(line, end='') + + (return_type, funcname, args) = parse_func_decl(line) + if verbose: + print(args) + + retval_format = make_uftrace_retval_format(return_type, funcname) + args_format = make_uftrace_args_format(args, funcname) + + if verbose: + print("ret : " + retval_format) + print("arg : " + args_format) + print("") + + for lib in libnames: + retval_format = make_uftrace_retval_format(return_type, funcname, lib) + args_format = make_uftrace_args_format(args, funcname, lib) + + if retval_format: + retvals_list += "\t\"" + retval_format + ";\"\n" + + if args_format: + args_list += "\t\"" + args_format + ";\"\n" + + if verbose: + print(args_list) + print(retvals_list) + + with open(argspec_file, "w") as fout: + fout.write(header) + + fout.write("static char *auto_args_list =\n") + fout.write(args_list) + fout.write(";\n\n") + + fout.write("static char *auto_retvals_list =\n") + fout.write(retvals_list) + fout.write(";\n\n") diff --git a/misc/prototypes.h b/misc/prototypes.h new file mode 100644 index 000000000..4ed43e8b1 --- /dev/null +++ b/misc/prototypes.h @@ -0,0 +1,224 @@ +// +// Prototype functions for automatic arguments / return value display +// +// Copyright (C) 2017, LG Electronics, Honggyu Kim +// +// Released under the GPL v2. +// +// This file is processed by gen-autoargs.py and it generates autoargs.h to be +// used for --auto-args option. Due to the limitation of space, it cannot +// contain more function prototypes as of now. +// + +#include +#include + + +//////////////////////////////////////////////////////////////////////////////// +// memory +#include +void *malloc(size_t size); +void free(void* ptr); +void* calloc(size_t nmemb, size_t size); +void* realloc(void* ptr, size_t size); + +#include +void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset); +int munmap(void *addr, size_t length); +int mprotect(void *addr, size_t len, int prot); + +int brk(void *addr); +void *sbrk(intptr_t increment); + +#include +void *memalign(size_t alignment, size_t size); +void *pvalloc(size_t size); +int posix_memalign(void **memptr, size_t alignment, size_t size); +void *aligned_alloc(size_t alignment, size_t size); +void *valloc(size_t size); +//////////////////////////////////////////////////////////////////////////////// + + + +//////////////////////////////////////////////////////////////////////////////// +// string +#include +const char* strcpy(char* dest, const char* src); +char* strncpy(char* dest, const char* src, size_t n); +size_t strlen(const char *s); +size_t strnlen(const char *s, size_t maxlen); +int strcmp(const char *s1, const char *s2); +int strncmp(const char *s1, const char *s2, size_t n); + +char *strdup(const char *s); +char *strndup(const char *s, size_t n); +char *strdupa(const char *s); +char *strndupa(const char *s, size_t n); + +int strcoll(const char *s1, const char *s2); + +char *strstr(const char *haystack, const char *needle); +char *strcasestr(const char *haystack, const char *needle); +char *strchr(const char *s, char c); +char *strrchr(const char *s, char c); +char *strchrnul(const char *s, char c); + +void *memcpy(void *dest, const void *src, size_t n); +void *memset(void *s, int c, size_t n); +int memcmp(const void *s1, const void *s2, size_t n); +void *memmove(void *dest, const void *src, size_t n); + +void *memchr(const void *s, int c, size_t n); +void *memrchr(const void *s, int c, size_t n); +void *rawmemchr(const void *s, int c); +//////////////////////////////////////////////////////////////////////////////// + + + +//////////////////////////////////////////////////////////////////////////////// +// stdio +#include +int printf(const char *format, ...); +int fprintf(FILE *stream, const char *format, ...); +int dprintf(int fd, const char *format, ...); +int sprintf(char *str, const char *format, ...); +int snprintf(char *str, size_t size, const char *format, ...); + +int fputc(char c, FILE *stream); +int fputs(const char *s, FILE *stream); +int putc(char c, FILE *stream); +int putchar(char c); +int puts(const char *s); + +char fgetc(FILE *stream); +char *fgets(char *s, int size, FILE *stream); +char getc(FILE *stream); +char getchar(void); +char ungetc(char c, FILE *stream); + +char *getenv(const char *name); +int setenv(const char *name, const char *value, int overwrite); +int unsetenv(const char *name); +//////////////////////////////////////////////////////////////////////////////// + + + +//////////////////////////////////////////////////////////////////////////////// +// file +#include +#include +int open(const char* pathname, int flags); +int close(int fd); +off_t lseek(int fd, off_t offset, int whence); + +FILE *fopen(const char *path, const char *mode); +FILE *fopen64(const char *filename, const char *type); +FILE *fdopen(int fd, const char *mode); +FILE *freopen(const char *path, const char *mode, FILE *stream); +int fclose(FILE *stream); +int fseek(FILE *stream, long offset, int whence); +long ftell(FILE *stream); + +ssize_t read(int fd, void *buf, size_t count); +ssize_t write(int fd, const void *buf, size_t count); +size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream); +size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream); +//////////////////////////////////////////////////////////////////////////////// + + + +//////////////////////////////////////////////////////////////////////////////// +// fork and exec +pid_t fork(void); +pid_t vfork(void); + +int execl(const char *path, const char *arg, ...); +int execlp(const char *file, const char *arg, ...); +int execle(const char *path, const char *arg, ...); + +//int execv(const char *path, char *const argv[]); // cannot understand argv type +int execv(const char *path, ...); +//int execvp(const char *file, char *const argv[]); // cannot understand argv type +int execvp(const char *file, ...); +//int execvpe(const char *file, char *const argv[], char *const envp[]); +int execvpe(const char *file, ...); + +#include +pid_t wait(int *status); +pid_t waitpid(pid_t pid, int *status, int options); + +pid_t getpid(void); +pid_t getppid(void); +pid_t gettid(void); + +#include +void *dlopen(const char *filename, int flags); +//////////////////////////////////////////////////////////////////////////////// + + + +//////////////////////////////////////////////////////////////////////////////// +// pthread +#include +//int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg); +int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void* *start_routine(), void *arg); +//int pthread_once(pthread_once_t *once_control, void (*init_routine)(void)); +int pthread_once(pthread_once_t *once_control, void *init_routine()); +int pthread_join(pthread_t thread, void **retval); +int pthread_detach(pthread_t thread); + +int pthread_mutex_lock(pthread_mutex_t *mutex); +int pthread_mutex_trylock(pthread_mutex_t *mutex); +int pthread_mutex_unlock(pthread_mutex_t *mutex); +int pthread_mutex_destroy(pthread_mutex_t *mutex); +int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr); +//////////////////////////////////////////////////////////////////////////////// + + + +//////////////////////////////////////////////////////////////////////////////// +// socket +#include +int socket(int domain, int type, int protocol); +int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen); +int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen); +int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); +int accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags); + +#include +struct hostent *gethostbyname(const char *name); +struct hostent *gethostbyaddr(const void *addr, socklen_t len, int type); +int getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res); +void freeaddrinfo(struct addrinfo *res); +//////////////////////////////////////////////////////////////////////////////// + + + +//////////////////////////////////////////////////////////////////////////////// +// signal +#include +int kill(pid_t pid, int sig); +int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact); +int sigemptyset(sigset_t *set); +int sigfillset(sigset_t *set); +int sigaddset(sigset_t *set, int signum); +int sigdelset(sigset_t *set, int signum); +int sigismember(const sigset_t *set, int signum); +//////////////////////////////////////////////////////////////////////////////// + + + +//////////////////////////////////////////////////////////////////////////////// +// etc. +#include +int prctl(int option, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5); + +#include +int poll(struct pollfd *fds, nfds_t nfds, int timeout); + +#include /* For SYS_xxx definitions */ +long syscall(long number, ...); + +#include +int ioctl(int fd, unsigned long request, ...); +//////////////////////////////////////////////////////////////////////////////// From d84d8fd3a9150448d29d5a331176194aef77227c Mon Sep 17 00:00:00 2001 From: Honggyu Kim Date: Tue, 19 Sep 2017 00:53:34 +0900 Subject: [PATCH 15/18] info: Expand buffer size to store huge args/retval list Since gen-autoargs.py generates a very long list of args/retval list, uftrace fails to store the entire list into the current buffer. It needs a huge buffer to store the list to properly support --auto-args option. This patch expands the size 8 times bigger. Signed-off-by: Honggyu Kim --- cmd-info.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmd-info.c b/cmd-info.c index 7cf0b124a..00fe4e862 100644 --- a/cmd-info.c +++ b/cmd-info.c @@ -668,11 +668,12 @@ static int fill_arg_spec(void *arg) return 0; } +static char buf[32768]; /* 4096 * 8 */ + static int read_arg_spec(void *arg) { struct ftrace_file_handle *handle = arg; struct uftrace_info *info = &handle->info; - char buf[4096]; if (fgets(buf, sizeof(buf), handle->fp) == NULL) return -1; From d6a56fb1a371e1931c81312513d71612bd5e85cc Mon Sep 17 00:00:00 2001 From: Honggyu Kim Date: Wed, 13 Sep 2017 00:46:10 +0900 Subject: [PATCH 16/18] record: Use autoargs.h to support automatic args/retval display "utils/prototypes.h" contains the prototypes of well-known library functions, especially libc functions. uftrace understandable argspec format is generated by "gen-autoargs.py" based on "utils/prototypes.h" file. Then the generated "autoargs.h" file is directly included by uftrace for --auto-args support. This patch adds automatic args/retval rules directly to uftrace when --auto-args is enabled. It allows uftrace to display args/retval even for distributed binaries without -pg or -finstrument-functions build. Signed-off-by: Honggyu Kim --- cmd-record.c | 20 +++++++++++++++++--- libmcount/mcount.c | 19 ++++++++++++++++++- utils/utils.c | 21 +++++++++++++++++++++ utils/utils.h | 2 ++ 4 files changed, 58 insertions(+), 4 deletions(-) diff --git a/cmd-record.c b/cmd-record.c index f201c24d2..09a85afa1 100644 --- a/cmd-record.c +++ b/cmd-record.c @@ -27,6 +27,7 @@ #include "utils/filter.h" #include "utils/kernel.h" #include "utils/perf.h" +#include "autoargs.h" #define SHMEM_NAME_SIZE (64 - (int)sizeof(struct list_head)) @@ -66,7 +67,8 @@ static bool can_use_fast_libmcount(struct opts *opts) return false; if (getenv("UFTRACE_FILTER") || getenv("UFTRACE_TRIGGER") || getenv("UFTRACE_ARGUMENT") || getenv("UFTRACE_RETVAL") || - getenv("UFTRACE_PATCH") || getenv("UFTRACE_SCRIPT")) + getenv("UFTRACE_PATCH") || getenv("UFTRACE_SCRIPT") || + getenv("UFTRACE_AUTO_ARGS")) return false; return true; } @@ -300,10 +302,10 @@ static uint64_t calc_feat_mask(struct opts *opts) if (opts->kernel) features |= KERNEL; - if (opts->args) + if (opts->args || opts->auto_args) features |= ARGUMENT; - if (opts->retval) + if (opts->retval || opts->auto_args) features |= RETVAL; if (opts->event) @@ -352,6 +354,18 @@ static int fill_file_header(struct opts *opts, int status, struct rusage *rusage if (write(fd, &hdr, sizeof(hdr)) != (int)sizeof(hdr)) pr_err("writing header info failed"); + if (opts->auto_args) { + /* add auto-args info to write into info file */ + pr_dbg2("extending args/retval using builtin auto-arg list\n"); + + char *orig_args = opts->args; + char *orig_retval = opts->retval; + opts->args = make_args_list(auto_args_list, orig_args); + opts->retval = make_args_list(auto_retvals_list, orig_retval); + free(orig_args); + free(orig_retval); + } + fill_uftrace_info(&hdr.info_mask, fd, opts, status, rusage, elapsed_time); diff --git a/libmcount/mcount.c b/libmcount/mcount.c index 0ddff0969..5f432f788 100644 --- a/libmcount/mcount.c +++ b/libmcount/mcount.c @@ -32,6 +32,9 @@ #include "utils/symbol.h" #include "utils/filter.h" #include "utils/script.h" +#ifndef DISABLE_MCOUNT_FILTER +#include "autoargs.h" +#endif uint64_t mcount_threshold; /* nsec */ struct symtabs symtabs = { @@ -1165,6 +1168,7 @@ static void mcount_startup(void) char *dirname; struct stat statbuf; bool nest_libcall; + LIST_HEAD(modules); if (!(mcount_global_flags & MCOUNT_GFL_SETUP) || mtd.recursion_guard) return; @@ -1190,7 +1194,6 @@ static void mcount_startup(void) event_str = getenv("UFTRACE_EVENT"); script_str = getenv("UFTRACE_SCRIPT"); nest_libcall = !!getenv("UFTRACE_NEST_LIBCALL"); - page_size_in_kb = getpagesize() / KB; if (logfd_str) { @@ -1250,6 +1253,15 @@ static void mcount_startup(void) char *trigger_str = getenv("UFTRACE_TRIGGER"); char *argument_str = getenv("UFTRACE_ARGUMENT"); char *retval_str = getenv("UFTRACE_RETVAL"); + bool auto_args = !!getenv("UFTRACE_AUTO_ARGS"); + + if (auto_args) { + /* add auto-args to read args/retvals of well-known functions */ + pr_dbg2("extending args/retval using builtin auto-args list\n"); + + argument_str = make_args_list(auto_args_list, argument_str); + retval_str = make_args_list(auto_retvals_list, retval_str); + } load_module_symtabs(&symtabs); @@ -1259,6 +1271,11 @@ static void mcount_startup(void) uftrace_setup_argument(argument_str, &symtabs, &mcount_triggers); uftrace_setup_retval(retval_str, &symtabs, &mcount_triggers); + if (auto_args) { + free(argument_str); + free(retval_str); + } + if (getenv("UFTRACE_DEPTH")) mcount_depth = strtol(getenv("UFTRACE_DEPTH"), NULL, 0); diff --git a/utils/utils.c b/utils/utils.c index de7dd1b37..516f2c046 100644 --- a/utils/utils.c +++ b/utils/utils.c @@ -618,6 +618,27 @@ char *absolute_dirname(const char *path, char *resolved_path) return resolved_path; } +/** + * make_args_list - make a concatenated string if args_env is not NULL + * + * @auto_args_list: given original args_list + * @args_env: args info given by user in environmental variable + * this can be NULL if environmental variable is not set. + * + * This returns a concatenated string that has to be free(3)-ed after using. + */ +char *make_args_list(const char *auto_args_list, const char *args_env) +{ + char *dst_args; + + if (args_env) + xasprintf(&dst_args, "%s;%s", auto_args_list, args_env); + else + dst_args = xstrdup(auto_args_list); + + return dst_args; +} + #ifdef UNIT_TEST TEST_CASE(parse_cmdline) { diff --git a/utils/utils.h b/utils/utils.h index 562466caa..1856c7a2f 100644 --- a/utils/utils.h +++ b/utils/utils.h @@ -260,4 +260,6 @@ char *get_event_name(struct ftrace_file_handle *handle, unsigned evt_id); char *absolute_dirname(const char *path, char *resolved_path); +char *make_args_list(const char *auto_args_list, const char *args_env); + #endif /* __FTRACE_UTILS_H__ */ From 003be9f0b0e2ba0efa3e452ed00f55ed28bd59b3 Mon Sep 17 00:00:00 2001 From: Honggyu Kim Date: Mon, 18 Sep 2017 17:28:04 +0900 Subject: [PATCH 17/18] test: Add a test case for --auto-args $ uftrace --auto-args tests/t-autoargs hello hello # DURATION TID FUNCTION [11503] | main() { 2.044 us [11503] | strlen("autoargs test") = 13; 1.583 us [11503] | calloc(1, 14) = 0x1b28a80; 1.193 us [11503] | free(0x1b28a80); 1.344 us [11503] | strcmp("hello", "hello") = 0; 4.056 us [11503] | puts("hello") = 6; 18.513 us [11503] | } /* main */ Signed-off-by: Honggyu Kim --- tests/s-autoargs.c | 22 ++++++++++++++++++++++ tests/t172_autoargs.py | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 tests/s-autoargs.c create mode 100644 tests/t172_autoargs.py diff --git a/tests/s-autoargs.c b/tests/s-autoargs.c new file mode 100644 index 000000000..2605c61c6 --- /dev/null +++ b/tests/s-autoargs.c @@ -0,0 +1,22 @@ +#include +#include +#include + +char *hello = "hello"; +char *msg = "autoargs test"; + +int main(int argc, char *argv[]) +{ + char buf[1024]; + size_t len = strlen(msg); + + char *ptr = (char*)calloc(1, len + 1); + free(ptr); + + if (!strcmp(hello, argv[1])) + puts(hello); + else + puts(msg); + + return 0; +} diff --git a/tests/t172_autoargs.py b/tests/t172_autoargs.py new file mode 100644 index 000000000..3f670146b --- /dev/null +++ b/tests/t172_autoargs.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python + +from runtest import TestBase +import re + +class TestCase(TestBase): + def __init__(self): + TestBase.__init__(self, 'autoargs', result=""" +hello +# DURATION TID FUNCTION + [162523] | main() { + 2.670 us [162523] | strlen("autoargs test") = 13; + 1.353 us [162523] | calloc(1, 14) = 0xADDR; + 1.150 us [162523] | free(0xADDR); + 1.336 us [162523] | strcmp("hello", "hello") = 0; + 4.017 us [162523] | puts("hello") = 6; + 18.574 us [162523] | } /* main */ +""") + + def runcmd(self): + #return '%s -A "getenv|atoi@arg1/s" -A malloc@arg1 %s 100' % + return '%s -F main --auto-args %s hello' % \ + (TestBase.ftrace, 't-' + self.name) + + def sort(self, output): + result = [] + for ln in output.split('\n'): + # ignore blank lines and comments + if ln.strip() == '' or ln.startswith('#'): + continue + line = ln.split('|', 1)[-1] + func = re.sub(r'0x[0-9a-f]+', '0xADDR', line) + result.append(func) + + return '\n'.join(result) From 86840f7ca9f35bda14f53edc4b6d85952934f85c Mon Sep 17 00:00:00 2001 From: Honggyu Kim Date: Mon, 18 Sep 2017 17:56:09 +0900 Subject: [PATCH 18/18] build: Add gen-autoargs.py rule gen-autoargs.py generates autoargs.h for --auto-args option support. So this patch adds a build rule to generate it. Signed-off-by: Honggyu Kim --- .gitignore | 1 + Makefile | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/.gitignore b/.gitignore index 1d6837249..ab1392ec1 100644 --- a/.gitignore +++ b/.gitignore @@ -23,6 +23,7 @@ check-deps/* !check-deps/Makefile* FLAGS version.h +autoargs.h .config GPATH GRTAGS diff --git a/Makefile b/Makefile index 8748a5332..7328befe9 100644 --- a/Makefile +++ b/Makefile @@ -95,6 +95,7 @@ UFTRACE_ARCH_OBJS := $(objdir)/arch/$(ARCH)/uftrace.o UFTRACE_HDRS := $(filter-out $(srcdir)/version.h,$(wildcard $(srcdir)/*.h $(srcdir)/utils/*.h)) UFTRACE_HDRS += $(srcdir)/libmcount/mcount.h $(wildcard $(srcdir)/arch/$(ARCH)/*.h) +UFTRACE_HDRS += $(srcdir)/autoargs.h LIBMCOUNT_SRCS := $(filter-out %-nop.c,$(wildcard $(srcdir)/libmcount/*.c)) LIBMCOUNT_OBJS := $(patsubst $(srcdir)/%.c,$(objdir)/%.op,$(LIBMCOUNT_SRCS)) @@ -193,6 +194,9 @@ $(filter-out $(objdir)/uftrace.o,$(UFTRACE_OBJS)): $(objdir)/%.o: $(srcdir)/%.c $(objdir)/version.h: PHONY @$(srcdir)/misc/version.sh $@ $(VERSION_GIT) +$(objdir)/autoargs.h: $(srcdir)/misc/gen-autoargs.py $(srcdir)/misc/prototypes.h + $(QUIET_GEN)$(srcdir)/misc/gen-autoargs.py -i $(srcdir)/misc/prototypes.h + $(objdir)/uftrace: $(UFTRACE_OBJS) $(UFTRACE_ARCH_OBJS) $(objdir)/libtraceevent/libtraceevent.a $(QUIET_LINK)$(CC) $(UFTRACE_CFLAGS) -o $@ $(UFTRACE_OBJS) $(UFTRACE_ARCH_OBJS) $(UFTRACE_LDFLAGS)