diff options
author | Steven Rostedt <srostedt@redhat.com> | 2009-07-21 18:18:18 -0400 |
---|---|---|
committer | Steven Rostedt <rostedt@goodmis.org> | 2009-07-21 18:18:18 -0400 |
commit | e3b16be293af31394b9d1257e08e94e55d48b3da (patch) | |
tree | 273fc5e328dab47705039f6d4e859f89ecc3c80c | |
parent | 5f2168be9994e284209cb3f02a30932e0a538f5e (diff) |
handle bprint events
The ftrace bprint uses a special binary format to record trace_print
events. This patch changes trace-cmd to handle the format. Part of
that is to read (and record) the printk_formats file in the trace.dat.
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
-rw-r--r-- | parse-events.c | 254 | ||||
-rw-r--r-- | parse-events.h | 2 | ||||
-rw-r--r-- | trace-cmd.c | 25 | ||||
-rw-r--r-- | trace-read.c | 28 |
4 files changed, 308 insertions, 1 deletions
diff --git a/parse-events.c b/parse-events.c index f1d8d74..288af2b 100644 --- a/parse-events.c +++ b/parse-events.c | |||
@@ -262,6 +262,92 @@ void print_funcs(void) | |||
262 | } | 262 | } |
263 | } | 263 | } |
264 | 264 | ||
265 | static struct printk_map { | ||
266 | unsigned long long addr; | ||
267 | char *printk; | ||
268 | } *printk_list; | ||
269 | static unsigned int printk_count; | ||
270 | |||
271 | static int printk_cmp(const void *a, const void *b) | ||
272 | { | ||
273 | const struct func_map *fa = a; | ||
274 | const struct func_map *fb = b; | ||
275 | |||
276 | if (fa->addr < fb->addr) | ||
277 | return -1; | ||
278 | if (fa->addr > fb->addr) | ||
279 | return 1; | ||
280 | |||
281 | return 0; | ||
282 | } | ||
283 | |||
284 | static struct printk_map *find_printk(unsigned long long addr) | ||
285 | { | ||
286 | struct printk_map *printk; | ||
287 | struct printk_map key; | ||
288 | |||
289 | key.addr = addr; | ||
290 | |||
291 | printk = bsearch(&key, printk_list, printk_count, sizeof(*printk_list), | ||
292 | printk_cmp); | ||
293 | |||
294 | return printk; | ||
295 | } | ||
296 | |||
297 | void parse_ftrace_printk(char *file, unsigned int size) | ||
298 | { | ||
299 | struct printk_list { | ||
300 | struct printk_list *next; | ||
301 | unsigned long long addr; | ||
302 | char *printk; | ||
303 | } *list = NULL, *item; | ||
304 | char *line; | ||
305 | char *next; | ||
306 | char *addr_str; | ||
307 | int ret; | ||
308 | int i; | ||
309 | |||
310 | line = strtok_r(file, "\n", &next); | ||
311 | while (line) { | ||
312 | item = malloc_or_die(sizeof(*item)); | ||
313 | ret = sscanf(line, "%as : %as", | ||
314 | &addr_str, | ||
315 | &item->printk); | ||
316 | item->addr = strtoull(addr_str, NULL, 16); | ||
317 | free(addr_str); | ||
318 | |||
319 | item->next = list; | ||
320 | list = item; | ||
321 | line = strtok_r(NULL, "\n", &next); | ||
322 | printk_count++; | ||
323 | } | ||
324 | |||
325 | printk_list = malloc_or_die(sizeof(*printk_list) * printk_count + 1); | ||
326 | |||
327 | i = 0; | ||
328 | while (list) { | ||
329 | printk_list[i].printk = list->printk; | ||
330 | printk_list[i].addr = list->addr; | ||
331 | i++; | ||
332 | item = list; | ||
333 | list = list->next; | ||
334 | free(item); | ||
335 | } | ||
336 | |||
337 | qsort(printk_list, printk_count, sizeof(*printk_list), printk_cmp); | ||
338 | } | ||
339 | |||
340 | void print_printk(void) | ||
341 | { | ||
342 | int i; | ||
343 | |||
344 | for (i = 0; i < printk_count; i++) { | ||
345 | printf("%016llx %s\n", | ||
346 | printk_list[i].addr, | ||
347 | printk_list[i].printk); | ||
348 | } | ||
349 | } | ||
350 | |||
265 | struct event *alloc_event(void) | 351 | struct event *alloc_event(void) |
266 | { | 352 | { |
267 | struct event *event; | 353 | struct event *event; |
@@ -1915,14 +2001,167 @@ static void print_str_arg(void *data, int size, | |||
1915 | } | 2001 | } |
1916 | } | 2002 | } |
1917 | 2003 | ||
2004 | static struct print_arg *make_bprint_args(char *fmt, void *data, int size, struct event *event) | ||
2005 | { | ||
2006 | static struct format_field *field, *ip_field; | ||
2007 | struct print_arg *args, *arg, **next; | ||
2008 | unsigned long long ip, val; | ||
2009 | char *ptr; | ||
2010 | void *bptr; | ||
2011 | |||
2012 | if (!field) { | ||
2013 | field = find_field(event, "buf"); | ||
2014 | if (!field) | ||
2015 | die("can't find buffer field for binary printk"); | ||
2016 | ip_field = find_field(event, "ip"); | ||
2017 | if (!ip_field) | ||
2018 | die("can't find ip field for binary printk"); | ||
2019 | } | ||
2020 | |||
2021 | ip = read_size(data + ip_field->offset, ip_field->size); | ||
2022 | |||
2023 | /* | ||
2024 | * The first arg is the IP pointer. | ||
2025 | */ | ||
2026 | args = malloc_or_die(sizeof(*args)); | ||
2027 | arg = args; | ||
2028 | arg->next = NULL; | ||
2029 | next = &arg->next; | ||
2030 | |||
2031 | arg->type = PRINT_ATOM; | ||
2032 | arg->atom.atom = malloc_or_die(32); | ||
2033 | sprintf(arg->atom.atom, "%lld", ip); | ||
2034 | |||
2035 | /* skip the first "%pf : " */ | ||
2036 | for (ptr = fmt + 6, bptr = data + field->offset; | ||
2037 | bptr < data + size && *ptr; ptr++) { | ||
2038 | int ls = 0; | ||
2039 | |||
2040 | if (*ptr == '%') { | ||
2041 | process_again: | ||
2042 | ptr++; | ||
2043 | switch (*ptr) { | ||
2044 | case '%': | ||
2045 | break; | ||
2046 | case 'l': | ||
2047 | ls++; | ||
2048 | goto process_again; | ||
2049 | case 'L': | ||
2050 | ls = 2; | ||
2051 | goto process_again; | ||
2052 | case '0' ... '9': | ||
2053 | goto process_again; | ||
2054 | case 'p': | ||
2055 | ls = 1; | ||
2056 | /* fall through */ | ||
2057 | case 'd': | ||
2058 | case 'u': | ||
2059 | case 'x': | ||
2060 | case 'i': | ||
2061 | bptr = (void *)(((unsigned long)bptr + (long_size - 1)) & | ||
2062 | ~(long_size - 1)); | ||
2063 | switch (ls) { | ||
2064 | case 0: | ||
2065 | case 1: | ||
2066 | ls = long_size; | ||
2067 | break; | ||
2068 | case 2: | ||
2069 | ls = 8; | ||
2070 | } | ||
2071 | val = read_size(bptr, ls); | ||
2072 | bptr += ls; | ||
2073 | arg = malloc_or_die(sizeof(*arg)); | ||
2074 | arg->next = NULL; | ||
2075 | arg->type = PRINT_ATOM; | ||
2076 | arg->atom.atom = malloc_or_die(32); | ||
2077 | sprintf(arg->atom.atom, "%lld", val); | ||
2078 | *next = arg; | ||
2079 | next = &arg->next; | ||
2080 | break; | ||
2081 | case 's': | ||
2082 | arg = malloc_or_die(sizeof(*arg)); | ||
2083 | arg->next = NULL; | ||
2084 | arg->type = PRINT_STRING; | ||
2085 | arg->string.string = strdup(bptr); | ||
2086 | bptr += strlen(bptr) + 1; | ||
2087 | *next = arg; | ||
2088 | next = &arg->next; | ||
2089 | } | ||
2090 | } | ||
2091 | } | ||
2092 | |||
2093 | return args; | ||
2094 | } | ||
2095 | |||
2096 | static void free_args(struct print_arg *args) | ||
2097 | { | ||
2098 | struct print_arg *next; | ||
2099 | |||
2100 | while (args) { | ||
2101 | next = args->next; | ||
2102 | |||
2103 | if (args->type == PRINT_ATOM) | ||
2104 | free(args->atom.atom); | ||
2105 | else | ||
2106 | free(args->string.string); | ||
2107 | free(args); | ||
2108 | args = next; | ||
2109 | } | ||
2110 | } | ||
2111 | |||
2112 | static char *get_bprint_format(void *data, int size, struct event *event) | ||
2113 | { | ||
2114 | unsigned long long addr; | ||
2115 | static struct format_field *field; | ||
2116 | struct printk_map *printk; | ||
2117 | char *format; | ||
2118 | char *p; | ||
2119 | |||
2120 | if (!field) { | ||
2121 | field = find_field(event, "fmt"); | ||
2122 | if (!field) | ||
2123 | die("can't find format field for binary printk"); | ||
2124 | printf("field->offset = %d size=%d\n", field->offset, field->size); | ||
2125 | } | ||
2126 | |||
2127 | addr = read_size(data + field->offset, field->size); | ||
2128 | |||
2129 | printk = find_printk(addr); | ||
2130 | if (!printk) { | ||
2131 | format = malloc_or_die(45); | ||
2132 | sprintf(format, "%%pf : (NO FORMAT FOUND at %llx)\n", | ||
2133 | addr); | ||
2134 | return format; | ||
2135 | } | ||
2136 | |||
2137 | p = printk->printk; | ||
2138 | /* Remove any quotes. */ | ||
2139 | if (*p == '"') | ||
2140 | p++; | ||
2141 | format = malloc_or_die(strlen(p) + 10); | ||
2142 | sprintf(format, "%s : %s", "%pf", p); | ||
2143 | /* remove ending quotes and new line since we will add one too */ | ||
2144 | p = format + strlen(format) - 1; | ||
2145 | if (*p == '"') | ||
2146 | *p = 0; | ||
2147 | |||
2148 | p -= 2; | ||
2149 | if (strcmp(p, "\\n") == 0) | ||
2150 | *p = 0; | ||
2151 | |||
2152 | return format; | ||
2153 | } | ||
2154 | |||
1918 | static void pretty_print(void *data, int size, struct event *event) | 2155 | static void pretty_print(void *data, int size, struct event *event) |
1919 | { | 2156 | { |
1920 | struct print_fmt *print_fmt = &event->print_fmt; | 2157 | struct print_fmt *print_fmt = &event->print_fmt; |
1921 | struct print_arg *arg = print_fmt->args; | 2158 | struct print_arg *arg = print_fmt->args; |
2159 | struct print_arg *args = NULL; | ||
1922 | const char *ptr = print_fmt->format; | 2160 | const char *ptr = print_fmt->format; |
1923 | unsigned long long val; | 2161 | unsigned long long val; |
1924 | struct func_map *func; | 2162 | struct func_map *func; |
1925 | const char *saveptr; | 2163 | const char *saveptr; |
2164 | char *bprint_fmt = NULL; | ||
1926 | char format[32]; | 2165 | char format[32]; |
1927 | int show_func; | 2166 | int show_func; |
1928 | int len; | 2167 | int len; |
@@ -1931,6 +2170,13 @@ static void pretty_print(void *data, int size, struct event *event) | |||
1931 | if (event->flags & EVENT_FL_ISFUNC) | 2170 | if (event->flags & EVENT_FL_ISFUNC) |
1932 | ptr = " %pF <-- %pF"; | 2171 | ptr = " %pF <-- %pF"; |
1933 | 2172 | ||
2173 | if (event->flags & EVENT_FL_ISBPRINT) { | ||
2174 | bprint_fmt = get_bprint_format(data, size, event); | ||
2175 | args = make_bprint_args(bprint_fmt, data, size, event); | ||
2176 | arg = args; | ||
2177 | ptr = bprint_fmt; | ||
2178 | } | ||
2179 | |||
1934 | for (; *ptr; ptr++) { | 2180 | for (; *ptr; ptr++) { |
1935 | ls = 0; | 2181 | ls = 0; |
1936 | if (*ptr == '%') { | 2182 | if (*ptr == '%') { |
@@ -2023,6 +2269,11 @@ static void pretty_print(void *data, int size, struct event *event) | |||
2023 | } else | 2269 | } else |
2024 | printf("%c", *ptr); | 2270 | printf("%c", *ptr); |
2025 | } | 2271 | } |
2272 | |||
2273 | if (args) { | ||
2274 | free_args(args); | ||
2275 | free(bprint_fmt); | ||
2276 | } | ||
2026 | } | 2277 | } |
2027 | 2278 | ||
2028 | static inline int log10_cpu(int nb) | 2279 | static inline int log10_cpu(int nb) |
@@ -2546,6 +2797,9 @@ int parse_ftrace_file(char *buf, unsigned long size) | |||
2546 | else if (strcmp(event->name, "funcgraph_exit") == 0) | 2797 | else if (strcmp(event->name, "funcgraph_exit") == 0) |
2547 | event->flags |= EVENT_FL_ISFUNCRET; | 2798 | event->flags |= EVENT_FL_ISFUNCRET; |
2548 | 2799 | ||
2800 | else if (strcmp(event->name, "bprint") == 0) | ||
2801 | event->flags |= EVENT_FL_ISBPRINT; | ||
2802 | |||
2549 | event->id = event_read_id(); | 2803 | event->id = event_read_id(); |
2550 | if (event->id < 0) | 2804 | if (event->id < 0) |
2551 | die("failed to read ftrace event id"); | 2805 | die("failed to read ftrace event id"); |
diff --git a/parse-events.h b/parse-events.h index d41abd5..2401c8d 100644 --- a/parse-events.h +++ b/parse-events.h | |||
@@ -159,8 +159,10 @@ void *malloc_or_die(unsigned int size); | |||
159 | 159 | ||
160 | void parse_cmdlines(char *file, int size); | 160 | void parse_cmdlines(char *file, int size); |
161 | void parse_proc_kallsyms(char *file, unsigned int size); | 161 | void parse_proc_kallsyms(char *file, unsigned int size); |
162 | void parse_ftrace_printk(char *file, unsigned int size); | ||
162 | 163 | ||
163 | void print_funcs(void); | 164 | void print_funcs(void); |
165 | void print_printk(void); | ||
164 | 166 | ||
165 | int parse_ftrace_file(char *buf, unsigned long size); | 167 | int parse_ftrace_file(char *buf, unsigned long size); |
166 | int parse_event_file(char *buf, unsigned long size, char *system); | 168 | int parse_event_file(char *buf, unsigned long size, char *system); |
diff --git a/trace-cmd.c b/trace-cmd.c index 12581bc..6973bba 100644 --- a/trace-cmd.c +++ b/trace-cmd.c | |||
@@ -849,6 +849,29 @@ static void read_proc_kallsyms(void) | |||
849 | 849 | ||
850 | } | 850 | } |
851 | 851 | ||
852 | static void read_ftrace_printk(void) | ||
853 | { | ||
854 | unsigned int size, check_size; | ||
855 | const char *path; | ||
856 | struct stat st; | ||
857 | int ret; | ||
858 | |||
859 | path = get_tracing_file("printk_formats"); | ||
860 | ret = stat(path, &st); | ||
861 | if (ret < 0) { | ||
862 | /* not found */ | ||
863 | size = 0; | ||
864 | write_or_die(&size, 4); | ||
865 | return; | ||
866 | } | ||
867 | size = get_size(path); | ||
868 | write_or_die(&size, 4); | ||
869 | check_size = copy_file(path); | ||
870 | if (size != check_size) | ||
871 | die("error in size of file '%s'", path); | ||
872 | |||
873 | } | ||
874 | |||
852 | static void read_tracing_data(void) | 875 | static void read_tracing_data(void) |
853 | { | 876 | { |
854 | char buf[BUFSIZ]; | 877 | char buf[BUFSIZ]; |
@@ -886,6 +909,7 @@ static void read_tracing_data(void) | |||
886 | read_ftrace_files(); | 909 | read_ftrace_files(); |
887 | read_event_files(); | 910 | read_event_files(); |
888 | read_proc_kallsyms(); | 911 | read_proc_kallsyms(); |
912 | read_ftrace_printk(); | ||
889 | } | 913 | } |
890 | 914 | ||
891 | static unsigned long long read_thread_file(int cpu) | 915 | static unsigned long long read_thread_file(int cpu) |
@@ -1006,6 +1030,7 @@ void usage(char **argv) | |||
1006 | " -i input file [default trace.dat]\n" | 1030 | " -i input file [default trace.dat]\n" |
1007 | " -e show file endianess\n" | 1031 | " -e show file endianess\n" |
1008 | " -f show function list\n" | 1032 | " -f show function list\n" |
1033 | " -P show printk list\n" | ||
1009 | "\n" | 1034 | "\n" |
1010 | " %s list [-e][-p]\n" | 1035 | " %s list [-e][-p]\n" |
1011 | " -e list available events\n" | 1036 | " -e list available events\n" |
diff --git a/trace-read.c b/trace-read.c index ed11a71..3be4fe2 100644 --- a/trace-read.c +++ b/trace-read.c | |||
@@ -148,6 +148,23 @@ static void read_proc_kallsyms(void) | |||
148 | free(buf); | 148 | free(buf); |
149 | } | 149 | } |
150 | 150 | ||
151 | static void read_ftrace_printk(void) | ||
152 | { | ||
153 | unsigned int size; | ||
154 | char *buf; | ||
155 | |||
156 | size = read4(); | ||
157 | if (!size) | ||
158 | return; | ||
159 | |||
160 | buf = malloc_or_die(size); | ||
161 | read_or_die(buf, size); | ||
162 | |||
163 | parse_ftrace_printk(buf, size); | ||
164 | |||
165 | free(buf); | ||
166 | } | ||
167 | |||
151 | static void read_header_files(void) | 168 | static void read_header_files(void) |
152 | { | 169 | { |
153 | unsigned long long size; | 170 | unsigned long long size; |
@@ -579,6 +596,7 @@ void trace_report (int argc, char **argv) | |||
579 | int show_funcs = 0; | 596 | int show_funcs = 0; |
580 | int show_endian = 0; | 597 | int show_endian = 0; |
581 | int show_page_size = 0; | 598 | int show_page_size = 0; |
599 | int show_printk = 0; | ||
582 | int c; | 600 | int c; |
583 | 601 | ||
584 | if (argc < 2) | 602 | if (argc < 2) |
@@ -595,7 +613,7 @@ void trace_report (int argc, char **argv) | |||
595 | {NULL, 0, NULL, 0} | 613 | {NULL, 0, NULL, 0} |
596 | }; | 614 | }; |
597 | 615 | ||
598 | c = getopt_long (argc-1, argv+1, "+hi:fep", | 616 | c = getopt_long (argc-1, argv+1, "+hi:fepP", |
599 | long_options, &option_index); | 617 | long_options, &option_index); |
600 | if (c == -1) | 618 | if (c == -1) |
601 | break; | 619 | break; |
@@ -609,6 +627,9 @@ void trace_report (int argc, char **argv) | |||
609 | case 'f': | 627 | case 'f': |
610 | show_funcs = 1; | 628 | show_funcs = 1; |
611 | break; | 629 | break; |
630 | case 'P': | ||
631 | show_printk = 1; | ||
632 | break; | ||
612 | case 'e': | 633 | case 'e': |
613 | show_endian = 1; | 634 | show_endian = 1; |
614 | break; | 635 | break; |
@@ -671,11 +692,16 @@ void trace_report (int argc, char **argv) | |||
671 | read_ftrace_files(); | 692 | read_ftrace_files(); |
672 | read_event_files(); | 693 | read_event_files(); |
673 | read_proc_kallsyms(); | 694 | read_proc_kallsyms(); |
695 | read_ftrace_printk(); | ||
674 | 696 | ||
675 | if (show_funcs) { | 697 | if (show_funcs) { |
676 | print_funcs(); | 698 | print_funcs(); |
677 | return; | 699 | return; |
678 | } | 700 | } |
701 | if (show_printk) { | ||
702 | print_printk(); | ||
703 | return; | ||
704 | } | ||
679 | read_data_info(); | 705 | read_data_info(); |
680 | 706 | ||
681 | return; | 707 | return; |