Skip to content

Commit

Permalink
Merge branch 'pattern-match'
Browse files Browse the repository at this point in the history
Unify pattern match behavior so it users can use a single pattern
matching type consistently.  Now all of function filter (both user and
kernel) as well as events specification use REGEX match.  It can be
changed using --match option.

Fixes #328.

Signed-off-by: Namhyung Kim <namhyung@gmail.com>
  • Loading branch information
namhyung committed Mar 21, 2018
2 parents 8ea2b2f + 67bf3f5 commit 826687d
Show file tree
Hide file tree
Showing 35 changed files with 522 additions and 180 deletions.
36 changes: 36 additions & 0 deletions cmd-info.c
Original file line number Diff line number Diff line change
Expand Up @@ -788,6 +788,37 @@ static int read_record_date(void *arg)
return 0;
}

static int fill_pattern_type(void *arg)
{
struct fill_handler_arg *fha = arg;

dprintf(fha->fd, "pattern_type:%s\n",
get_filter_pattern(fha->opts->patt_type));

return 0;
}

static int read_pattern_type(void *arg)
{
struct ftrace_file_handle *handle = arg;
struct uftrace_info *info = &handle->info;
char buf[4096];
size_t len;

if (fgets(buf, sizeof(buf), handle->fp) == NULL)
return -1;

if (strncmp(buf, "pattern_type:", 13))
return -1;

len = strlen(&buf[13]);
if (buf[13 + len - 1] == '\n')
buf[13 + len - 1] = '\0';

info->patt_type = parse_filter_pattern(&buf[13]);
return 0;
}

struct uftrace_info_handler {
enum uftrace_info_bits bit;
int (*handler)(void *arg);
Expand Down Expand Up @@ -818,6 +849,7 @@ void fill_uftrace_info(uint64_t *info_mask, int fd, struct opts *opts, int statu
{ LOADINFO, fill_loadinfo },
{ ARG_SPEC, fill_arg_spec },
{ RECORD_DATE, fill_record_date },
{ PATTERN_TYPE, fill_pattern_type },
};

for (i = 0; i < ARRAY_SIZE(fill_handlers); i++) {
Expand Down Expand Up @@ -856,6 +888,7 @@ int read_uftrace_info(uint64_t info_mask, struct ftrace_file_handle *handle)
{ LOADINFO, read_loadinfo },
{ ARG_SPEC, read_arg_spec },
{ RECORD_DATE, read_record_date },
{ PATTERN_TYPE, read_pattern_type },
};

memset(&handle->info, 0, sizeof(handle->info));
Expand Down Expand Up @@ -1003,6 +1036,9 @@ int command_info(int argc, char *argv[], struct opts *opts)
pr_out(fmt, "auto-args", "true");
}

if (handle.hdr.info_mask & (1UL << PATTERN_TYPE))
pr_out(fmt, "pattern", get_filter_pattern(handle.info.patt_type));

if (handle.hdr.info_mask & (1UL << EXIT_STATUS)) {
int status = handle.info.exit_status;

Expand Down
21 changes: 16 additions & 5 deletions cmd-record.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
#include <sys/eventfd.h>
#include <sys/resource.h>
#include <sys/epoll.h>
#include <fnmatch.h>

#include "uftrace.h"
#include "libmcount/mcount.h"
Expand Down Expand Up @@ -243,6 +242,9 @@ static void setup_child_environ(struct opts *opts, int pfd)
if (opts->script_file)
setenv("UFTRACE_SCRIPT", opts->script_file, 1);

if (opts->patt_type != PATT_REGEX)
setenv("UFTRACE_PATTERN", get_filter_pattern(opts->patt_type), 1);

if (opts->lib_path)
snprintf(buf, sizeof(buf), "%s/libmcount/", opts->lib_path);
else
Expand Down Expand Up @@ -1470,7 +1472,8 @@ static void check_binary(struct opts *opts)
close(fd);
}

static bool check_linux_perf_event(char *events)
static bool check_linux_schedule_event(char *events,
enum uftrace_pattern_type ptype)
{
struct strv strv = STRV_INIT;
char *evt;
Expand All @@ -1483,10 +1486,17 @@ static bool check_linux_perf_event(char *events)
strv_split(&strv, events, ";");

strv_for_each(&strv, evt, i) {
if (fnmatch(evt, "linux:schedule", 0) == 0) {
struct uftrace_pattern patt;

init_filter_pattern(ptype, &patt, evt);

if (match_filter_pattern(&patt, "linux:schedule"))
found = true;

free_filter_pattern(&patt);

if (found)
break;
}
}

strv_free(&strv);
Expand Down Expand Up @@ -1856,7 +1866,8 @@ int command_record(int argc, char *argv[], struct opts *opts)

check_binary(opts);

has_perf_event = check_linux_perf_event(opts->event);
has_perf_event = check_linux_schedule_event(opts->event,
opts->patt_type);

fflush(stdout);

Expand Down
6 changes: 5 additions & 1 deletion cmd-replay.c
Original file line number Diff line number Diff line change
Expand Up @@ -939,8 +939,12 @@ static bool skip_sys_exit(struct opts *opts, struct ftrace_task_handle *task)

ip = task->func_stack[0].addr;
sym = find_symtabs(&task->h->sessions.first->symtabs, ip);
if (sym == NULL)
return false;

if (sym && !strncmp(sym->name, "sys_exit", 8))
if (!strncmp(sym->name, "sys_exit", 8))
return true;
if (!strcmp(sym->name, "do_syscall_64"))
return true;

return false;
Expand Down
2 changes: 1 addition & 1 deletion cmd-script.c
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ int command_script(int argc, char *argv[], struct opts *opts)
fstack_setup_filters(opts, &handle);

/* initialize script */
if (script_init(opts->script_file) < 0)
if (script_init(opts->script_file, opts->patt_type) < 0)
return -1;

while (read_rstack(&handle, &task) == 0 && !uftrace_done) {
Expand Down
3 changes: 3 additions & 0 deletions doc/uftrace-dump.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ OPTIONS
\--demangle=*TYPE*
: Use demangled C++ symbol names for filters, triggers, arguments and/or return values. Possible values are "full", "simple" and "no". Default is "simple" which ignores function arguments and template parameters.

--match=*TYPE*
: Use pattern match using TYPE. Possible types are `regex` and `glob`. Default is `regex`.


EXAMPLE
=======
Expand Down
3 changes: 3 additions & 0 deletions doc/uftrace-graph.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ OPTIONS
\--demangle=*TYPE*
: Use demangled C++ symbol names for filters, triggers, arguments and/or return values. Possible values are "full", "simple" and "no". Default is "simple" which ignores function arguments and template parameters.

--match=*TYPE*
: Use pattern match using TYPE. Possible types are `regex` and `glob`. Default is `regex`.


EXAMPLES
========
Expand Down
3 changes: 3 additions & 0 deletions doc/uftrace-live.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,9 @@ OPTIONS
\--libname
: Show library name along with function name.

--match=*TYPE*
: Use pattern match using TYPE. Possible types are `regex` and `glob`. Default is `regex`.


FILTERS
=======
Expand Down
5 changes: 4 additions & 1 deletion doc/uftrace-record.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,9 @@ OPTIONS
-S *SCRIPT_PATH*, \--script=*SCRIPT_PATH*
: Add a script to do addtional work at the entry and exit of function. The type of script is detected by the postfix such as '.py' for python.

--match=*TYPE*
: Use pattern match using TYPE. Possible types are `regex` and `glob`. Default is `regex`.


FILTERS
=======
Expand Down Expand Up @@ -203,7 +206,7 @@ You can also set triggers on filtered functions. See *TRIGGERS* section below f

When kernel function tracing is enabled, you can also set the filters on kernel functions by marking the symbol with the `@kernel` modifier. The following example will show all user functions and the (kernel) page fault handler.

$ sudo uftrace -k -F '*page_fault@kernel' ./abc
$ sudo uftrace -k -F '.*page_fault@kernel' ./abc
# DURATION TID FUNCTION
[14721] | main() {
7.713 us [14721] | __do_page_fault();
Expand Down
5 changes: 4 additions & 1 deletion doc/uftrace-replay.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ OPTIONS
: Do not show comments of returned functions.

-k, \--kernel
: Trace kernel functions (and events) as well as user functions (and events). This options has no meaning and so is deprecated now. It will always show kernel functions and events if exists. If you want to hide kernel functions, please use `-N .@kernel` to filter out all kernel functions.
: Trace kernel functions (and events) as well as user functions (and events). This options has no meaning and so is deprecated now. It will always show kernel functions and events if exists. If you want to hide kernel functions, please use `-N .@kernel` to filter out all kernel functions (for the regex match).

\--kernel-full
: Show all kernel functions and events occurred outside of user functions. This option is the inverse of `--kernel-skip-out`.
Expand All @@ -82,6 +82,9 @@ OPTIONS
\--libname
: Show libname name along with function name.

--match=*TYPE*
: Use pattern match using TYPE. Possible types are `regex` and `glob`. Default is `regex`.


FILTERS
=======
Expand Down
3 changes: 3 additions & 0 deletions doc/uftrace-report.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@ OPTIONS
\--demangle=*TYPE*
: Use demangled C++ symbol names for filters, triggers, arguments and/or return values. Possible values are "full", "simple" and "no". Default is "simple" which ignores function arguments and template parameters.

--match=*TYPE*
: Use pattern match using TYPE. Possible types are `regex` and `glob`. Default is `regex`.


EXAMPLE
=======
Expand Down
5 changes: 4 additions & 1 deletion doc/uftrace-script.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ OPTIONS
\--record COMMAND [*command-options*]
: Record a new trace before running a given script.

--match=*TYPE*
: Use pattern match using TYPE. Possible types are `regex` and `glob`. Default is `regex`.


EXAMPLES
========
Expand Down Expand Up @@ -117,7 +120,7 @@ The below is another example that shows the different output compared to previou

The python script above can be modified to do more output customization.

The python script can have an optional "UFTRACE_FUNCS" list which can have name (or regex pattern) of functions to run the script. If it exists, only matched functions will run the script. For example, if you add following lines to the script, it will run only for functions with a single letter name.
The python script can have an optional "UFTRACE_FUNCS" list which can have name (or pattern depending on the --match option) of functions to run the script. If it exists, only matched functions will run the script. For example, if you add following lines to the script, it will run only for functions with a single letter name.

$ echo 'UFTRACE_FUNCS = [ "^.$" ]' >> replay.py
$ uftrace script -S replay.py
Expand Down
30 changes: 11 additions & 19 deletions libmcount/dynamic.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
#include <string.h>
#include <link.h>
#include <regex.h>

/* This should be defined before #include "utils.h" */
#define PR_FMT "dynamic"
Expand Down Expand Up @@ -92,7 +91,8 @@ static int prepare_dynamic_update(void)
return ret;
}

static int do_dynamic_update(struct symtabs *symtabs, char *patch_funcs)
static int do_dynamic_update(struct symtabs *symtabs, char *patch_funcs,
enum uftrace_pattern_type ptype)
{
char *name, *nopatched_name = NULL;
struct symtab *symtab = &symtabs->symtab;
Expand All @@ -105,26 +105,17 @@ static int do_dynamic_update(struct symtabs *symtabs, char *patch_funcs)
strv_split(&funcs, patch_funcs, ";");

strv_for_each(&funcs, name, j) {
bool is_regex;
bool found = false;
regex_t re;
unsigned i;
struct sym *sym;
struct uftrace_pattern patt;

is_regex = strpbrk(name, REGEX_CHARS);
if (is_regex) {
if (regcomp(&re, name, REG_NOSUB | REG_EXTENDED)) {
pr_dbg("regex pattern failed: %s\n", name);
strv_free(&funcs);
return -1;
}
}
init_filter_pattern(ptype, &patt, name);

for (i = 0; i < symtab->nr_sym; i++) {
sym = &symtab->sym[i];

if ((is_regex && regexec(&re, sym->name, 0, NULL, 0)) ||
(!is_regex && strcmp(name, sym->name)))
if (!match_filter_pattern(&patt, sym->name))
continue;

found = true;
Expand All @@ -147,14 +138,14 @@ static int do_dynamic_update(struct symtabs *symtabs, char *patch_funcs)
if (!found)
stats.nomatch++;

if (is_regex)
regfree(&re);
free_filter_pattern(&patt);
}

if (stats.failed || stats.skipped || stats.nomatch)
if (stats.failed || stats.skipped || stats.nomatch) {
pr_out("%s cannot be patched dynamically\n",
(stats.failed + stats.skipped + stats.nomatch) > 1 ?
"some functions" : nopatched_name);
}

strv_free(&funcs);
return 0;
Expand Down Expand Up @@ -184,7 +175,8 @@ static float calc_percent(int n, int total)
return 100.0 * n / total;
}

int mcount_dynamic_update(struct symtabs *symtabs, char *patch_funcs)
int mcount_dynamic_update(struct symtabs *symtabs, char *patch_funcs,
enum uftrace_pattern_type ptype)
{
int ret = 0;
int success;
Expand All @@ -194,7 +186,7 @@ int mcount_dynamic_update(struct symtabs *symtabs, char *patch_funcs)
return -1;
}

ret = do_dynamic_update(symtabs, patch_funcs);
ret = do_dynamic_update(symtabs, patch_funcs, ptype);

success = stats.total - stats.failed - stats.skipped;
pr_dbg("dynamic update stats:\n");
Expand Down
21 changes: 13 additions & 8 deletions libmcount/event.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
#include <link.h>
#include <libelf.h>
#include <gelf.h>
#include <fnmatch.h>

/* This should be defined before #include "utils.h" */
#define PR_FMT "event"
Expand All @@ -15,15 +14,16 @@
#include "libmcount/internal.h"
#include "utils/utils.h"
#include "utils/list.h"
#include "utils/filter.h"

#define SDT_SECT ".note.stapsdt"
#define SDT_NAME "stapsdt"
#define SDT_TYPE 3

struct event_spec {
struct list_head list;
char *provider;
char *event;
struct uftrace_pattern provider;
struct uftrace_pattern event;
};

struct stapsdt {
Expand Down Expand Up @@ -126,9 +126,9 @@ static int search_sdt_event(struct dl_phdr_info *info, size_t sz, void *data)
}

list_for_each_entry(spec, spec_list, list) {
if (fnmatch(spec->provider, vendor, 0) != 0)
if (!match_filter_pattern(&spec->provider, vendor))
continue;
if (fnmatch(spec->event, event, 0) != 0)
if (!match_filter_pattern(&spec->event, event))
continue;
break;
}
Expand Down Expand Up @@ -161,7 +161,8 @@ static int search_sdt_event(struct dl_phdr_info *info, size_t sz, void *data)
goto out;
}

int mcount_setup_events(char *dirname, char *event_str)
int mcount_setup_events(char *dirname, char *event_str,
enum uftrace_pattern_type ptype)
{
int ret = 0;
FILE *fp;
Expand All @@ -187,8 +188,9 @@ int mcount_setup_events(char *dirname, char *event_str)
continue;

es = xmalloc(sizeof(*es));
es->provider = spec;
es->event = sep;

init_filter_pattern(ptype, &es->provider, spec);
init_filter_pattern(ptype, &es->event, sep);
list_add_tail(&es->list, &specs);
}
else {
Expand All @@ -200,6 +202,9 @@ int mcount_setup_events(char *dirname, char *event_str)

list_for_each_entry_safe(es, tmp, &specs, list) {
list_del(&es->list);

free_filter_pattern(&es->provider);
free_filter_pattern(&es->event);
free(es);
}
strv_free(&strv);
Expand Down
Loading

0 comments on commit 826687d

Please sign in to comment.