diff options
author | Namhyung Kim <namhyung@gmail.com> | 2011-03-23 22:42:29 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2011-03-24 03:36:10 -0400 |
commit | 0f77a8d378254f27df4a114a5da67223af1fe93f (patch) | |
tree | edc37c211adce744100d4776e4a28fb868c8b3c0 | |
parent | dec2960827c85253d76938dbfa909df3be34958b (diff) |
vsprintf: Introduce %pB format specifier
The %pB format specifier is for stack backtrace. Its handler
sprint_backtrace() does symbol lookup using (address-1) to
ensure the address will not point outside of the function.
If there is a tail-call to the function marked "noreturn",
gcc optimized out the code after the call then causes saved
return address points outside of the function (i.e. the start
of the next function), so pollutes call trace somewhat.
This patch adds the %pB printk mechanism that allows architecture
call-trace printout functions to improve backtrace printouts.
Signed-off-by: Namhyung Kim <namhyung@gmail.com>
Acked-by: Steven Rostedt <rostedt@goodmis.org>
Acked-by: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: linux-arch@vger.kernel.org
LKML-Reference: <1300934550-21394-1-git-send-email-namhyung@gmail.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r-- | include/linux/kallsyms.h | 7 | ||||
-rw-r--r-- | kernel/kallsyms.c | 44 | ||||
-rw-r--r-- | lib/vsprintf.c | 7 |
3 files changed, 54 insertions, 4 deletions
diff --git a/include/linux/kallsyms.h b/include/linux/kallsyms.h index d8e9b3d1c23c..0df513b7a9f8 100644 --- a/include/linux/kallsyms.h +++ b/include/linux/kallsyms.h | |||
@@ -36,6 +36,7 @@ const char *kallsyms_lookup(unsigned long addr, | |||
36 | 36 | ||
37 | /* Look up a kernel symbol and return it in a text buffer. */ | 37 | /* Look up a kernel symbol and return it in a text buffer. */ |
38 | extern int sprint_symbol(char *buffer, unsigned long address); | 38 | extern int sprint_symbol(char *buffer, unsigned long address); |
39 | extern int sprint_backtrace(char *buffer, unsigned long address); | ||
39 | 40 | ||
40 | /* Look up a kernel symbol and print it to the kernel messages. */ | 41 | /* Look up a kernel symbol and print it to the kernel messages. */ |
41 | extern void __print_symbol(const char *fmt, unsigned long address); | 42 | extern void __print_symbol(const char *fmt, unsigned long address); |
@@ -79,6 +80,12 @@ static inline int sprint_symbol(char *buffer, unsigned long addr) | |||
79 | return 0; | 80 | return 0; |
80 | } | 81 | } |
81 | 82 | ||
83 | static inline int sprint_backtrace(char *buffer, unsigned long addr) | ||
84 | { | ||
85 | *buffer = '\0'; | ||
86 | return 0; | ||
87 | } | ||
88 | |||
82 | static inline int lookup_symbol_name(unsigned long addr, char *symname) | 89 | static inline int lookup_symbol_name(unsigned long addr, char *symname) |
83 | { | 90 | { |
84 | return -ERANGE; | 91 | return -ERANGE; |
diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c index 6f6d091b5757..59e879929b17 100644 --- a/kernel/kallsyms.c +++ b/kernel/kallsyms.c | |||
@@ -342,13 +342,15 @@ int lookup_symbol_attrs(unsigned long addr, unsigned long *size, | |||
342 | } | 342 | } |
343 | 343 | ||
344 | /* Look up a kernel symbol and return it in a text buffer. */ | 344 | /* Look up a kernel symbol and return it in a text buffer. */ |
345 | int sprint_symbol(char *buffer, unsigned long address) | 345 | static int __sprint_symbol(char *buffer, unsigned long address, |
346 | int symbol_offset) | ||
346 | { | 347 | { |
347 | char *modname; | 348 | char *modname; |
348 | const char *name; | 349 | const char *name; |
349 | unsigned long offset, size; | 350 | unsigned long offset, size; |
350 | int len; | 351 | int len; |
351 | 352 | ||
353 | address += symbol_offset; | ||
352 | name = kallsyms_lookup(address, &size, &offset, &modname, buffer); | 354 | name = kallsyms_lookup(address, &size, &offset, &modname, buffer); |
353 | if (!name) | 355 | if (!name) |
354 | return sprintf(buffer, "0x%lx", address); | 356 | return sprintf(buffer, "0x%lx", address); |
@@ -357,17 +359,53 @@ int sprint_symbol(char *buffer, unsigned long address) | |||
357 | strcpy(buffer, name); | 359 | strcpy(buffer, name); |
358 | len = strlen(buffer); | 360 | len = strlen(buffer); |
359 | buffer += len; | 361 | buffer += len; |
362 | offset -= symbol_offset; | ||
360 | 363 | ||
361 | if (modname) | 364 | if (modname) |
362 | len += sprintf(buffer, "+%#lx/%#lx [%s]", | 365 | len += sprintf(buffer, "+%#lx/%#lx [%s]", offset, size, modname); |
363 | offset, size, modname); | ||
364 | else | 366 | else |
365 | len += sprintf(buffer, "+%#lx/%#lx", offset, size); | 367 | len += sprintf(buffer, "+%#lx/%#lx", offset, size); |
366 | 368 | ||
367 | return len; | 369 | return len; |
368 | } | 370 | } |
371 | |||
372 | /** | ||
373 | * sprint_symbol - Look up a kernel symbol and return it in a text buffer | ||
374 | * @buffer: buffer to be stored | ||
375 | * @address: address to lookup | ||
376 | * | ||
377 | * This function looks up a kernel symbol with @address and stores its name, | ||
378 | * offset, size and module name to @buffer if possible. If no symbol was found, | ||
379 | * just saves its @address as is. | ||
380 | * | ||
381 | * This function returns the number of bytes stored in @buffer. | ||
382 | */ | ||
383 | int sprint_symbol(char *buffer, unsigned long address) | ||
384 | { | ||
385 | return __sprint_symbol(buffer, address, 0); | ||
386 | } | ||
387 | |||
369 | EXPORT_SYMBOL_GPL(sprint_symbol); | 388 | EXPORT_SYMBOL_GPL(sprint_symbol); |
370 | 389 | ||
390 | /** | ||
391 | * sprint_backtrace - Look up a backtrace symbol and return it in a text buffer | ||
392 | * @buffer: buffer to be stored | ||
393 | * @address: address to lookup | ||
394 | * | ||
395 | * This function is for stack backtrace and does the same thing as | ||
396 | * sprint_symbol() but with modified/decreased @address. If there is a | ||
397 | * tail-call to the function marked "noreturn", gcc optimized out code after | ||
398 | * the call so that the stack-saved return address could point outside of the | ||
399 | * caller. This function ensures that kallsyms will find the original caller | ||
400 | * by decreasing @address. | ||
401 | * | ||
402 | * This function returns the number of bytes stored in @buffer. | ||
403 | */ | ||
404 | int sprint_backtrace(char *buffer, unsigned long address) | ||
405 | { | ||
406 | return __sprint_symbol(buffer, address, -1); | ||
407 | } | ||
408 | |||
371 | /* Look up a kernel symbol and print it to the kernel messages. */ | 409 | /* Look up a kernel symbol and print it to the kernel messages. */ |
372 | void __print_symbol(const char *fmt, unsigned long address) | 410 | void __print_symbol(const char *fmt, unsigned long address) |
373 | { | 411 | { |
diff --git a/lib/vsprintf.c b/lib/vsprintf.c index d3023df8477f..d9e01fc3168e 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c | |||
@@ -574,7 +574,9 @@ char *symbol_string(char *buf, char *end, void *ptr, | |||
574 | unsigned long value = (unsigned long) ptr; | 574 | unsigned long value = (unsigned long) ptr; |
575 | #ifdef CONFIG_KALLSYMS | 575 | #ifdef CONFIG_KALLSYMS |
576 | char sym[KSYM_SYMBOL_LEN]; | 576 | char sym[KSYM_SYMBOL_LEN]; |
577 | if (ext != 'f' && ext != 's') | 577 | if (ext == 'B') |
578 | sprint_backtrace(sym, value); | ||
579 | else if (ext != 'f' && ext != 's') | ||
578 | sprint_symbol(sym, value); | 580 | sprint_symbol(sym, value); |
579 | else | 581 | else |
580 | kallsyms_lookup(value, NULL, NULL, NULL, sym); | 582 | kallsyms_lookup(value, NULL, NULL, NULL, sym); |
@@ -949,6 +951,7 @@ int kptr_restrict = 1; | |||
949 | * - 'f' For simple symbolic function names without offset | 951 | * - 'f' For simple symbolic function names without offset |
950 | * - 'S' For symbolic direct pointers with offset | 952 | * - 'S' For symbolic direct pointers with offset |
951 | * - 's' For symbolic direct pointers without offset | 953 | * - 's' For symbolic direct pointers without offset |
954 | * - 'B' For backtraced symbolic direct pointers with offset | ||
952 | * - 'R' For decoded struct resource, e.g., [mem 0x0-0x1f 64bit pref] | 955 | * - 'R' For decoded struct resource, e.g., [mem 0x0-0x1f 64bit pref] |
953 | * - 'r' For raw struct resource, e.g., [mem 0x0-0x1f flags 0x201] | 956 | * - 'r' For raw struct resource, e.g., [mem 0x0-0x1f flags 0x201] |
954 | * - 'M' For a 6-byte MAC address, it prints the address in the | 957 | * - 'M' For a 6-byte MAC address, it prints the address in the |
@@ -1008,6 +1011,7 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr, | |||
1008 | /* Fallthrough */ | 1011 | /* Fallthrough */ |
1009 | case 'S': | 1012 | case 'S': |
1010 | case 's': | 1013 | case 's': |
1014 | case 'B': | ||
1011 | return symbol_string(buf, end, ptr, spec, *fmt); | 1015 | return symbol_string(buf, end, ptr, spec, *fmt); |
1012 | case 'R': | 1016 | case 'R': |
1013 | case 'r': | 1017 | case 'r': |
@@ -1279,6 +1283,7 @@ qualifier: | |||
1279 | * %ps output the name of a text symbol without offset | 1283 | * %ps output the name of a text symbol without offset |
1280 | * %pF output the name of a function pointer with its offset | 1284 | * %pF output the name of a function pointer with its offset |
1281 | * %pf output the name of a function pointer without its offset | 1285 | * %pf output the name of a function pointer without its offset |
1286 | * %pB output the name of a backtrace symbol with its offset | ||
1282 | * %pR output the address range in a struct resource with decoded flags | 1287 | * %pR output the address range in a struct resource with decoded flags |
1283 | * %pr output the address range in a struct resource with raw flags | 1288 | * %pr output the address range in a struct resource with raw flags |
1284 | * %pM output a 6-byte MAC address with colons | 1289 | * %pM output a 6-byte MAC address with colons |