Re: the printk problem

Linus Torvalds <[email protected]> Fri, 4 Jul 2008 16:25:30 -0700 (PDT)
Newsgroups gmane.linux.ports.ia64,gmane.linux.ports.ppc64.devel,gmane.linux.ports.hppa
Message-ID <[email protected]>

On Sat, 5 Jul 2008, Benjamin Herrenschmidt wrote:
>=20
> I'll give it a try using =EF=BB=BFprobe_kernel_address() instead on m=
onday.

Here's the updated patch which uses probe_kernel_address() instead (and=
=20
moves the whole #ifdef mess out of the code that wants it and into a=20
helper function - and maybe we should then put that helper into=20
kallsyms.h, but that's a different issue).

Still all happily untested, of course. And still with no actual users=20
converted.

			Linus

---
 lib/vsprintf.c |  108 +++++++++++++++++++++++++++++++++++++++++-------=
-------
 1 files changed, 80 insertions(+), 28 deletions(-)

diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index 6021757..1fbb1c0 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>
=20
 #include <asm/page.h>		/* for PAGE_SIZE */
 #include <asm/div64.h>
@@ -482,6 +484,77 @@ static char *number(char *buf, char *end, unsigned=
 long long num, int base, int
 	return buf;
 }
=20
+static char *string(char *buf, char *end, char *s, int field_width, in=
t precision, int flags)
+{
+	int len, i;
+
+	if ((unsigned long)s < PAGE_SIZE)
+		s =3D "<NULL>";
+
+	len =3D strnlen(s, precision);
+
+	if (!(flags & LEFT)) {
+		while (len < field_width--) {
+			if (buf < end)
+				*buf =3D ' ';
+			++buf;
+		}
+	}
+	for (i =3D 0; i < len; ++i) {
+		if (buf < end)
+			*buf =3D *s;
+		++buf; ++s;
+	}
+	while (len < field_width--) {
+		if (buf < end)
+			*buf =3D ' ';
+		++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 =3D 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 functi=
on
+ * pointers are really function descriptors, which contain a pointer t=
he
+ * real address.=20
+ */
+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 =3D 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 |=3D SPECIAL;
+		break;
+#endif
+	}
+	}
+	return number(buf, end, (unsigned long long) ptr, base, size, precisi=
on, type);
+}
+
 /**
  * vsnprintf - Format a string and place it in a buffer
  * @buf: The buffer to place the result into
@@ -502,11 +575,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;
=20
 	int flags;		/* flags to number() */
=20
@@ -622,29 +693,7 @@ int vsnprintf(char *buf, size_t size, const char *=
fmt, va_list args)
 				continue;
=20
 			case 's':
-				s =3D va_arg(args, char *);
-				if ((unsigned long)s < PAGE_SIZE)
-					s =3D "<NULL>";
-
-				len =3D strnlen(s, precision);
-
-				if (!(flags & LEFT)) {
-					while (len < field_width--) {
-						if (str < end)
-							*str =3D ' ';
-						++str;
-					}
-				}
-				for (i =3D 0; i < len; ++i) {
-					if (str < end)
-						*str =3D *s;
-					++str; ++s;
-				}
-				while (len < field_width--) {
-					if (str < end)
-						*str =3D ' ';
-					++str;
-				}
+				str =3D string(str, end, va_arg(args, char *), field_width, precis=
ion, flags);
 				continue;
=20
 			case 'p':
@@ -653,9 +702,12 @@ int vsnprintf(char *buf, size_t size, const char *=
fmt, va_list args)
 					field_width =3D 2*sizeof(void *);
 					flags |=3D ZEROPAD;
 				}
-				str =3D number(str, end,
-						(unsigned long) va_arg(args, void *),
+				str =3D 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;
=20
=20
--
To unsubscribe from this list: send the line "unsubscribe linux-ia64" i=
n
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html