On Sun, 6 Jul 2008, Ingo Molnar wrote: > > applied (with the commit message below) to tip/x86/debug for v2.6.27 > merging, thanks Linus. Can i add your SOB too? Sure, add my S-O-B. But I hope/assuem that you also added my earlier patch that added the support for '%pS' too? I'm not entirely sure that should go in an x86-specific branch, since it has nothing x86-specific in it. Also, I've cleaned up the lib/vsnprintf.c patch to fix up some minor details. For example, it should not default to a field width of "2*sizeof(unsigned long)" - it should do that only if it ends up printing the pointer as a hex number. So this is my current version.. (the "precision" thing was moved into the 'pointer()' function, and to after the special case handling). Linus --- lib/vsprintf.c | 118 ++++++++++++++++++++++++++++++++++++++++---------------- 1 files changed, 85 insertions(+), 33 deletions(-) diff --git a/lib/vsprintf.c b/lib/vsprintf.c index 6021757..f60c7c0 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -22,6 +22,8 @@ #include <linux/string.h> #include <linux/ctype.h> #include <linux/kernel.h> +#include <linux/kallsyms.h> +#include <linux/uaccess.h> #include <asm/page.h> /* for PAGE_SIZE */ #include <asm/div64.h> @@ -482,6 +484,82 @@ static char *number(char *buf, char *end, unsigned long long num, int base, int return buf; } +static char *string(char *buf, char *end, char *s, int field_width, int precision, int flags) +{ + int len, i; + + if ((unsigned long)s < PAGE_SIZE) + s = "<NULL>"; + + len = strnlen(s, precision); + + if (!(flags & LEFT)) { + while (len < field_width--) { + if (buf < end) + *buf = ' '; + ++buf; + } + } + for (i = 0; i < len; ++i) { + if (buf < end) + *buf = *s; + ++buf; ++s; + } + while (len < field_width--) { + if (buf < end) + *buf = ' '; + ++buf; + } + return buf; +} + +static inline void *dereference_function_descriptor(void *ptr) +{ +#if defined(CONFIG_IA64) || defined(CONFIG_PPC64) + void *p; + if (!probe_kernel_address(ptr, p)) + ptr = p; +#endif + return ptr; +} + + +/* + * Show a '%p' thing. A kernel extension is that the '%p' is followed + * by an extra set of alphanumeric characters that are extended format + * specifiers. Right now we just handle 'F' (for symbolic Function + * pointers) and 'S' (for Symbolic data pointers), but this can easily + * be extended in the future (network address types etc). + * + * The difference between 'S' and 'F' is that on ia64 and ppc64 function + * pointers are really function descriptors, which contain a pointer the + * real address. + */ +static char *pointer(const char *fmt, char *buf, char *end, void *ptr, int base, int size, int precision, int type) +{ + switch (*fmt) { + case 'F': + ptr = dereference_function_descriptor(ptr); + /* Fallthrough */ + case 'S': { /* Other (direct) pointer */ +#if CONFIG_KALLSYMS + char sym[KSYM_SYMBOL_LEN]; + sprint_symbol(sym, (unsigned long) ptr); + return string(buf, end, sym, size, precision, type); +#else + type |= SPECIAL; + break; +#endif + } + } + type |= SMALL; + if (precision == -1) { + precision = 2*sizeof(void *); + type |= ZEROPAD; + } + return number(buf, end, (unsigned long long) ptr, base, size, precision, type); +} + /** * vsnprintf - Format a string and place it in a buffer * @buf: The buffer to place the result into @@ -502,11 +580,9 @@ static char *number(char *buf, char *end, unsigned long long num, int base, int */ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args) { - int len; unsigned long long num; - int i, base; + int base; char *str, *end, c; - const char *s; int flags; /* flags to number() */ @@ -622,40 +698,16 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args) continue; case 's': - s = va_arg(args, char *); - if ((unsigned long)s < PAGE_SIZE) - s = "<NULL>"; - - len = strnlen(s, precision); - - if (!(flags & LEFT)) { - while (len < field_width--) { - if (str < end) - *str = ' '; - ++str; - } - } - for (i = 0; i < len; ++i) { - if (str < end) - *str = *s; - ++str; ++s; - } - while (len < field_width--) { - if (str < end) - *str = ' '; - ++str; - } + str = string(str, end, va_arg(args, char *), field_width, precision, flags); continue; case 'p': - flags |= SMALL; - if (field_width == -1) { - field_width = 2*sizeof(void *); - flags |= ZEROPAD; - } - str = number(str, end, - (unsigned long) va_arg(args, void *), + str = pointer(fmt+1, str, end, + va_arg(args, void *), 16, field_width, precision, flags); + /* Skip all alphanumeric pointer suffixes */ + while (isalnum(fmt[1])) + fmt++; continue; -- To unsubscribe from this list: send the line "unsubscribe linux-ia64" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html
![]() |