|
22 | 22 | #include <linux/string.h>
|
23 | 23 | #include <linux/ctype.h>
|
24 | 24 | #include <linux/kernel.h>
|
| 25 | +#include <linux/kallsyms.h> |
| 26 | +#include <linux/uaccess.h> |
25 | 27 |
|
26 | 28 | #include <asm/page.h> /* for PAGE_SIZE */
|
27 | 29 | #include <asm/div64.h>
|
@@ -511,15 +513,52 @@ static char *string(char *buf, char *end, char *s, int field_width, int precisio
|
511 | 513 | return buf;
|
512 | 514 | }
|
513 | 515 |
|
| 516 | +static 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 | + |
| 526 | +static 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 | 541 | * Show a '%p' thing. A kernel extension is that the '%p' is followed
|
516 | 542 | * by an extra set of alphanumeric characters that are extended format
|
517 | 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 | */
|
521 | 553 | static 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 | 562 | flags |= SMALL;
|
524 | 563 | if (field_width == -1) {
|
525 | 564 | field_width = 2*sizeof(void *);
|
|
0 commit comments