aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2008-07-06 19:43:12 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-07-06 19:55:51 -0400
commit0fe1ef24f7bd0020f29ffe287dfdb9ead33ca0b2 (patch)
tree0069dd9dba6554f74436ea1d836ecc054a6b95d7 /lib
parent4d8a743cdd2690c0bc8d1b8cbd02cffb1ead849f (diff)
vsprintf: add support for '%pS' and '%pF' pointer formats
They print out a pointer in symbolic format, if possible (ie using symbolic KALLSYMS information). The '%pS' format is for regular direct pointers (which can point to data or code and that you find on the stack during backtraces etc), while '%pF' is for C function pointer types. On most architectures, the two mean exactly the same thing, but some architectures use an indirect pointer for C function pointers, where the function pointer points to a function descriptor (which in turn contains the actual pointer to the code). The '%pF' code automatically does the appropriate function descriptor dereference on such architectures. Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'lib')
-rw-r--r--lib/vsprintf.c41
1 files changed, 40 insertions, 1 deletions
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index 5d6f0718b6d9..1dc2d1d18fa8 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -22,6 +22,8 @@
22#include <linux/string.h> 22#include <linux/string.h>
23#include <linux/ctype.h> 23#include <linux/ctype.h>
24#include <linux/kernel.h> 24#include <linux/kernel.h>
25#include <linux/kallsyms.h>
26#include <linux/uaccess.h>
25 27
26#include <asm/page.h> /* for PAGE_SIZE */ 28#include <asm/page.h> /* for PAGE_SIZE */
27#include <asm/div64.h> 29#include <asm/div64.h>
@@ -511,15 +513,52 @@ static char *string(char *buf, char *end, char *s, int field_width, int precisio
511 return buf; 513 return buf;
512} 514}
513 515
516static inline void *dereference_function_descriptor(void *ptr)
517{
518#if defined(CONFIG_IA64) || defined(CONFIG_PPC64)
519 void *p;
520 if (!probe_kernel_address(ptr, p))
521 ptr = p;
522#endif
523 return ptr;
524}
525
526static char *symbol_string(char *buf, char *end, void *ptr, int field_width, int precision, int flags)
527{
528 unsigned long value = (unsigned long) ptr;
529#ifdef CONFIG_KALLSYMS
530 char sym[KSYM_SYMBOL_LEN];
531 sprint_symbol(sym, value);
532 return string(buf, end, sym, field_width, precision, flags);
533#else
534 field_width = 2*sizeof(void *);
535 flags |= SPECIAL | SMALL | ZEROPAD;
536 return number(buf, end, value, 16, field_width, precision, flags);
537#endif
538}
539
514/* 540/*
515 * Show a '%p' thing. A kernel extension is that the '%p' is followed 541 * Show a '%p' thing. A kernel extension is that the '%p' is followed
516 * by an extra set of alphanumeric characters that are extended format 542 * by an extra set of alphanumeric characters that are extended format
517 * specifiers. 543 * specifiers.
518 * 544 *
519 * Right now don't actually handle any such, but we will.. 545 * Right now we just handle 'F' (for symbolic Function descriptor pointers)
546 * and 'S' (for Symbolic direct pointers), but this can easily be
547 * extended in the future (network address types etc).
548 *
549 * The difference between 'S' and 'F' is that on ia64 and ppc64 function
550 * pointers are really function descriptors, which contain a pointer the
551 * real address.
520 */ 552 */
521static char *pointer(const char *fmt, char *buf, char *end, void *ptr, int field_width, int precision, int flags) 553static char *pointer(const char *fmt, char *buf, char *end, void *ptr, int field_width, int precision, int flags)
522{ 554{
555 switch (*fmt) {
556 case 'F':
557 ptr = dereference_function_descriptor(ptr);
558 /* Fallthrough */
559 case 'S':
560 return symbol_string(buf, end, ptr, field_width, precision, flags);
561 }
523 flags |= SMALL; 562 flags |= SMALL;
524 if (field_width == -1) { 563 if (field_width == -1) {
525 field_width = 2*sizeof(void *); 564 field_width = 2*sizeof(void *);