diff options
| -rw-r--r-- | Documentation/trace-cmd-record.1.txt | 7 | ||||
| -rw-r--r-- | trace-record.c | 59 | ||||
| -rw-r--r-- | trace-usage.c | 2 |
3 files changed, 67 insertions, 1 deletions
diff --git a/Documentation/trace-cmd-record.1.txt b/Documentation/trace-cmd-record.1.txt index 87e4f97..b78182a 100644 --- a/Documentation/trace-cmd-record.1.txt +++ b/Documentation/trace-cmd-record.1.txt | |||
| @@ -64,6 +64,13 @@ OPTIONS | |||
| 64 | => cpu_idle (ffffffff8100a38c) | 64 | => cpu_idle (ffffffff8100a38c) |
| 65 | => start_secondary (ffffffff814ab828) | 65 | => start_secondary (ffffffff814ab828) |
| 66 | 66 | ||
| 67 | *--func-stack*:: | ||
| 68 | Enable a stack trace on all functions. Note this is only applicable | ||
| 69 | for the "function" plugin tracer, and will only take effect if the | ||
| 70 | -l option is used and succeeds in limiting functions. If the function | ||
| 71 | tracer is not filtered, and the stack trace is enabled, you can live | ||
| 72 | lock the machine. | ||
| 73 | |||
| 67 | *-f* 'filter':: | 74 | *-f* 'filter':: |
| 68 | Specify a filter for the previous event. This must come after a *-e*. This | 75 | Specify a filter for the previous event. This must come after a *-e*. This |
| 69 | will filter what events get recorded based on the content of the event. | 76 | will filter what events get recorded based on the content of the event. |
diff --git a/trace-record.c b/trace-record.c index 2a6872c..031e084 100644 --- a/trace-record.c +++ b/trace-record.c | |||
| @@ -54,6 +54,7 @@ | |||
| 54 | #define ITER_CTRL "trace_options" | 54 | #define ITER_CTRL "trace_options" |
| 55 | #define MAX_LATENCY "tracing_max_latency" | 55 | #define MAX_LATENCY "tracing_max_latency" |
| 56 | #define STAMP "stamp" | 56 | #define STAMP "stamp" |
| 57 | #define FUNC_STACK_TRACE "func_stack_trace" | ||
| 57 | 58 | ||
| 58 | #define UDP_MAX_PACKET (65536 - 20) | 59 | #define UDP_MAX_PACKET (65536 - 20) |
| 59 | 60 | ||
| @@ -97,6 +98,8 @@ static struct func_list *filter_funcs; | |||
| 97 | static struct func_list *notrace_funcs; | 98 | static struct func_list *notrace_funcs; |
| 98 | static struct func_list *graph_funcs; | 99 | static struct func_list *graph_funcs; |
| 99 | 100 | ||
| 101 | static int func_stack; | ||
| 102 | |||
| 100 | struct filter_pids { | 103 | struct filter_pids { |
| 101 | struct filter_pids *next; | 104 | struct filter_pids *next; |
| 102 | int pid; | 105 | int pid; |
| @@ -560,6 +563,7 @@ static void set_plugin(const char *name) | |||
| 560 | { | 563 | { |
| 561 | FILE *fp; | 564 | FILE *fp; |
| 562 | char *path; | 565 | char *path; |
| 566 | char zero = '0'; | ||
| 563 | 567 | ||
| 564 | path = tracecmd_get_tracing_file("current_tracer"); | 568 | path = tracecmd_get_tracing_file("current_tracer"); |
| 565 | fp = fopen(path, "w"); | 569 | fp = fopen(path, "w"); |
| @@ -569,6 +573,16 @@ static void set_plugin(const char *name) | |||
| 569 | 573 | ||
| 570 | fwrite(name, 1, strlen(name), fp); | 574 | fwrite(name, 1, strlen(name), fp); |
| 571 | fclose(fp); | 575 | fclose(fp); |
| 576 | |||
| 577 | if (strncmp(name, "function", 8) != 0) | ||
| 578 | return; | ||
| 579 | |||
| 580 | /* Make sure func_stack_trace option is disabled */ | ||
| 581 | path = tracecmd_get_tracing_file("options/func_stack_trace"); | ||
| 582 | fp = fopen(path, "w"); | ||
| 583 | tracecmd_put_tracing_file(path); | ||
| 584 | fwrite(&zero, 1, 1, fp); | ||
| 585 | fclose(fp); | ||
| 572 | } | 586 | } |
| 573 | 587 | ||
| 574 | static void save_option(const char *option) | 588 | static void save_option(const char *option) |
| @@ -1525,11 +1539,44 @@ static void write_func_file(const char *file, struct func_list **list) | |||
| 1525 | tracecmd_put_tracing_file(path); | 1539 | tracecmd_put_tracing_file(path); |
| 1526 | } | 1540 | } |
| 1527 | 1541 | ||
| 1542 | static int functions_filtered(void) | ||
| 1543 | { | ||
| 1544 | char buf[1] = { '#' }; | ||
| 1545 | char *path; | ||
| 1546 | int fd; | ||
| 1547 | |||
| 1548 | path = tracecmd_get_tracing_file("set_ftrace_filter"); | ||
| 1549 | fd = open(path, O_RDONLY); | ||
| 1550 | tracecmd_put_tracing_file(path); | ||
| 1551 | if (fd < 0) | ||
| 1552 | return 0; | ||
| 1553 | |||
| 1554 | /* | ||
| 1555 | * If functions are not filtered, than the first character | ||
| 1556 | * will be '#'. Make sure it is not an '#' and also not space. | ||
| 1557 | */ | ||
| 1558 | read(fd, buf, 1); | ||
| 1559 | close(fd); | ||
| 1560 | |||
| 1561 | if (buf[0] == '#' || isspace(buf[0])) | ||
| 1562 | return 0; | ||
| 1563 | return 1; | ||
| 1564 | } | ||
| 1565 | |||
| 1528 | static void set_funcs(void) | 1566 | static void set_funcs(void) |
| 1529 | { | 1567 | { |
| 1530 | write_func_file("set_ftrace_filter", &filter_funcs); | 1568 | write_func_file("set_ftrace_filter", &filter_funcs); |
| 1531 | write_func_file("set_ftrace_notrace", ¬race_funcs); | 1569 | write_func_file("set_ftrace_notrace", ¬race_funcs); |
| 1532 | write_func_file("set_graph_function", &graph_funcs); | 1570 | write_func_file("set_graph_function", &graph_funcs); |
| 1571 | |||
| 1572 | /* make sure we are filtering functions */ | ||
| 1573 | if (func_stack) { | ||
| 1574 | if (!functions_filtered()) { | ||
| 1575 | disable_all(); | ||
| 1576 | die("Function stack trace set, but functions not filtered"); | ||
| 1577 | } | ||
| 1578 | save_option(FUNC_STACK_TRACE); | ||
| 1579 | } | ||
| 1533 | } | 1580 | } |
| 1534 | 1581 | ||
| 1535 | static void add_func(struct func_list **list, const char *func) | 1582 | static void add_func(struct func_list **list, const char *func) |
| @@ -1810,6 +1857,7 @@ static void record_all_events(void) | |||
| 1810 | } | 1857 | } |
| 1811 | 1858 | ||
| 1812 | enum { | 1859 | enum { |
| 1860 | OPT_funcstack = 254, | ||
| 1813 | OPT_date = 255, | 1861 | OPT_date = 255, |
| 1814 | }; | 1862 | }; |
| 1815 | 1863 | ||
| @@ -1867,6 +1915,7 @@ void trace_record (int argc, char **argv) | |||
| 1867 | int option_index = 0; | 1915 | int option_index = 0; |
| 1868 | static struct option long_options[] = { | 1916 | static struct option long_options[] = { |
| 1869 | {"date", no_argument, NULL, OPT_date}, | 1917 | {"date", no_argument, NULL, OPT_date}, |
| 1918 | {"func-stack", no_argument, NULL, OPT_funcstack}, | ||
| 1870 | {"help", no_argument, NULL, '?'}, | 1919 | {"help", no_argument, NULL, '?'}, |
| 1871 | {NULL, 0, NULL, 0} | 1920 | {NULL, 0, NULL, 0} |
| 1872 | }; | 1921 | }; |
| @@ -1957,7 +2006,8 @@ void trace_record (int argc, char **argv) | |||
| 1957 | case 'p': | 2006 | case 'p': |
| 1958 | if (plugin) | 2007 | if (plugin) |
| 1959 | die("only one plugin allowed"); | 2008 | die("only one plugin allowed"); |
| 1960 | plugin = optarg; | 2009 | for (plugin = optarg; isspace(*plugin); plugin++) |
| 2010 | ; | ||
| 1961 | fprintf(stderr, " plugin %s\n", plugin); | 2011 | fprintf(stderr, " plugin %s\n", plugin); |
| 1962 | break; | 2012 | break; |
| 1963 | case 'd': | 2013 | case 'd': |
| @@ -2012,11 +2062,18 @@ void trace_record (int argc, char **argv) | |||
| 2012 | case OPT_date: | 2062 | case OPT_date: |
| 2013 | date = 1; | 2063 | date = 1; |
| 2014 | break; | 2064 | break; |
| 2065 | case OPT_funcstack: | ||
| 2066 | func_stack = 1; | ||
| 2067 | break; | ||
| 2015 | default: | 2068 | default: |
| 2016 | usage(argv); | 2069 | usage(argv); |
| 2017 | } | 2070 | } |
| 2018 | } | 2071 | } |
| 2019 | 2072 | ||
| 2073 | if (strncmp(plugin, "function", 8) == 0 && | ||
| 2074 | func_stack && !filter_funcs) | ||
| 2075 | die("Must supply function filtering with --func-stack\n"); | ||
| 2076 | |||
| 2020 | if (do_ptrace && !filter_task && (filter_pid < 0)) | 2077 | if (do_ptrace && !filter_task && (filter_pid < 0)) |
| 2021 | die(" -c can only be used with -F or -P"); | 2078 | die(" -c can only be used with -F or -P"); |
| 2022 | 2079 | ||
diff --git a/trace-usage.c b/trace-usage.c index 1ecc8fa..4b171fe 100644 --- a/trace-usage.c +++ b/trace-usage.c | |||
| @@ -40,6 +40,8 @@ static struct usage_help usage_help[] = { | |||
| 40 | " -b change kernel buffersize (in kilobytes per CPU)\n" | 40 | " -b change kernel buffersize (in kilobytes per CPU)\n" |
| 41 | " -k do not reset the buffers after tracing.\n" | 41 | " -k do not reset the buffers after tracing.\n" |
| 42 | " -i do not fail if an event is not found\n" | 42 | " -i do not fail if an event is not found\n" |
| 43 | " --func-stack perform a stack trace for function tracer\n" | ||
| 44 | " (use with caution)\n" | ||
| 43 | }, | 45 | }, |
| 44 | { | 46 | { |
| 45 | "start", | 47 | "start", |
