lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <1334957394-12086-7-git-send-email-jason.wessel@windriver.com>
Date:	Fri, 20 Apr 2012 16:29:52 -0500
From:	Jason Wessel <jason.wessel@...driver.com>
To:	<linux-kernel@...r.kernel.org>
CC:	<mingo@...hat.com>, <masami.hiramatsu.pt@...achi.com>,
	<rusty@...tcorp.com.au>
Subject: [RFC PATCH 6/8] kallsyms: Add kallsyms kallsyms_line_loc_lookup and print function

This patch adds a new kallsyms symbol type called a line location.  A
line location will get encoded as a symbol with the type '0xff'.  Line
locations will be excluded from the /proc/kallsyms such that the user
space interface will remain unchanged.

The line locations come from:
   scripts/readelf -q --debug-dump=line vmlinux

The output is processed by scripts/kallsyms in a similar manner to the
output from nm -n vmlinux in order to construct the assembly file
which has all original kallsyms data.

In order to make all the original kallsyms functions return the same
expected values while allowing extra data in the kallsyms tables, the
get_symbol_pos() was modified to take an additional argument.  The new
4th argument is called "is_line_loc". That argument controls if
get_symbol_pos() should return a symbol or a line location.

kallsyms_line_loc_lookup() was added for the purpose of looking up a
line location and will call get_symbol_pos() with the 4th argument
being true.  This function was introduced in order to call it from
__sprint_symbol() so that the kernel can emit a file and line number
when providing a backtrace / oops output to an end user.

Signed-off-by: Jason Wessel <jason.wessel@...driver.com>
---
 Makefile                 |    9 +++-
 include/linux/kallsyms.h |   12 +++++
 init/Kconfig             |   11 +++++
 kernel/kallsyms.c        |  112 +++++++++++++++++++++++++++++++++++++++++-----
 4 files changed, 131 insertions(+), 13 deletions(-)

diff --git a/Makefile b/Makefile
index f6578f4..ea87304 100644
--- a/Makefile
+++ b/Makefile
@@ -342,6 +342,7 @@ GENKSYMS	= scripts/genksyms/genksyms
 INSTALLKERNEL  := installkernel
 DEPMOD		= /sbin/depmod
 KALLSYMS	= scripts/kallsyms
+READELF		= scripts/readelf
 PERL		= perl
 CHECK		= sparse
 
@@ -857,10 +858,14 @@ define rule_ksym_ld
 	$(Q)echo 'cmd_$@ := $(cmd_vmlinux__)' > $(@D)/.$(@F).cmd
 endef
 
+KALLSYMS_INPUT_CMD = ($(NM) -n $<; \
+	$(if $(CONFIG_KALLSYMS_LINE_LOCATIONS), \
+	 $(READELF) --debug-dump=line -q $<))
 # Generate .S file with all kernel symbols
 quiet_cmd_kallsyms = KSYM    $@
-      cmd_kallsyms = $(NM) -n $< | $(KALLSYMS) \
-                     $(if $(CONFIG_KALLSYMS_ALL),--all-symbols) > $@
+      cmd_kallsyms = $(KALLSYMS_INPUT_CMD) | $(KALLSYMS) \
+                     $(if $(CONFIG_KALLSYMS_ALL),--all-symbols) \
+		     $(if $(CONFIG_KALLSYMS_LINE_LOCATIONS), --ll-symbols) > $@
 
 .tmp_kallsyms1.o .tmp_kallsyms2.o .tmp_kallsyms3.o: %.o: %.S scripts FORCE
 	$(call if_changed_dep,as_o_S)
diff --git a/include/linux/kallsyms.h b/include/linux/kallsyms.h
index 3875719..39125d0 100644
--- a/include/linux/kallsyms.h
+++ b/include/linux/kallsyms.h
@@ -33,6 +33,10 @@ const char *kallsyms_lookup(unsigned long addr,
 			    unsigned long *symbolsize,
 			    unsigned long *offset,
 			    char **modname, char *namebuf);
+const char *kallsyms_line_loc_lookup(unsigned long addr,
+			    unsigned long *symbolsize,
+			    unsigned long *offset,
+			    char **modname, char *namebuf);
 
 /* Look up a kernel symbol and return it in a text buffer. */
 extern int sprint_symbol(char *buffer, unsigned long address);
@@ -73,6 +77,14 @@ static inline const char *kallsyms_lookup(unsigned long addr,
 {
 	return NULL;
 }
+static inline const char *kallsyms_line_loc_lookup(unsigned long addr,
+					  unsigned long *symbolsize,
+					  unsigned long *offset,
+					  char **modname, char *namebuf)
+{
+	return NULL;
+}
+
 
 static inline int sprint_symbol(char *buffer, unsigned long addr)
 {
diff --git a/init/Kconfig b/init/Kconfig
index 6cfd71d..20f537a 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -1012,6 +1012,17 @@ config KALLSYMS_ALL
 
 	   Say N unless you really need all symbols.
 
+config KALLSYMS_LINE_LOCATIONS
+	bool "Load source line information debugging kernel with kallsyms"
+	depends on DEBUG_KERNEL && KALLSYMS
+	default n
+	help
+	   Say Y here to let the kernel print out symbolic crash
+	   information which also contains source line information.
+	   This increases the size of the kernel somewhat, as all the
+	   lines for locations tables have to be loaded into the
+	   kernel image to allow address to line lookups.
+
 config HOTPLUG
 	bool "Support for hot-pluggable devices" if EXPERT
 	default y
diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c
index 550f273..921f2b3 100644
--- a/kernel/kallsyms.c
+++ b/kernel/kallsyms.c
@@ -32,6 +32,9 @@
 #define all_var 0
 #endif
 
+/* Is this a line location type? */
+#define IS_LLOC(pos) (kallsyms_type_table[pos] == 0xff)
+
 /*
  * These will be re-linked against their real values
  * during the second link stage.
@@ -188,9 +191,39 @@ int kallsyms_on_each_symbol(int (*fn)(void *, const char *, struct module *,
 }
 EXPORT_SYMBOL_GPL(kallsyms_on_each_symbol);
 
+static void first_aliased_symbol(unsigned long *low)
+{
+find_alias:
+	while (*low && kallsyms_addresses[*low-1] == kallsyms_addresses[*low])
+		--*low;
+
+	if (*low) {
+		if (*low < kallsyms_num_syms && IS_LLOC(*low) &&
+		    kallsyms_addresses[*low+1] == kallsyms_addresses[*low]) {
+			++*low;
+		} else if (IS_LLOC(*low)) {
+			while (*low && IS_LLOC(*low))
+				--*low;
+			goto find_alias;
+		}
+	}
+}
+
+static void first_aliased_line_loc(unsigned long *low)
+{
+	while (*low && kallsyms_addresses[*low-1] == kallsyms_addresses[*low])
+		--*low;
+	while (*low < kallsyms_num_syms && !IS_LLOC(*low) &&
+	       kallsyms_addresses[*low] == kallsyms_addresses[*low+1])
+		++*low;
+	while (*low && !(IS_LLOC(*low)))
+		--*low;
+}
+
 static unsigned long get_symbol_pos(unsigned long addr,
 				    unsigned long *symbolsize,
-				    unsigned long *offset)
+				    unsigned long *offset,
+				    bool is_line_loc)
 {
 	unsigned long symbol_start = 0, symbol_end = 0;
 	unsigned long i, low, high, mid;
@@ -214,14 +247,16 @@ static unsigned long get_symbol_pos(unsigned long addr,
 	 * Search for the first aliased symbol. Aliased
 	 * symbols are symbols with the same address.
 	 */
-	while (low && kallsyms_addresses[low-1] == kallsyms_addresses[low])
-		--low;
+	if (is_line_loc)
+		first_aliased_line_loc(&low);
+	else
+		first_aliased_symbol(&low);
 
 	symbol_start = kallsyms_addresses[low];
 
 	/* Search for next non-aliased symbol. */
 	for (i = low + 1; i < kallsyms_num_syms; i++) {
-		if (kallsyms_addresses[i] > symbol_start) {
+		if (kallsyms_addresses[i] > symbol_start && !IS_LLOC(low)) {
 			symbol_end = kallsyms_addresses[i];
 			break;
 		}
@@ -253,11 +288,52 @@ int kallsyms_lookup_size_offset(unsigned long addr, unsigned long *symbolsize,
 {
 	char namebuf[KSYM_NAME_LEN];
 	if (is_ksym_addr(addr))
-		return !!get_symbol_pos(addr, symbolsize, offset);
+		return !!get_symbol_pos(addr, symbolsize, offset, false);
 
 	return !!module_address_lookup(addr, symbolsize, offset, NULL, namebuf);
 }
 
+#ifdef CONFIG_KALLSYMS_LINE_LOCATIONS
+/*
+ * Lookup an address
+ * - modname is set to NULL if it's in the kernel.
+ * - We guarantee that the returned name is valid until we reschedule even if.
+ *   It resides in a module.
+ * - We also guarantee that modname will be valid until rescheduled.
+ */
+const char *kallsyms_line_loc_lookup(unsigned long addr,
+			    unsigned long *symbolsize,
+			    unsigned long *offset,
+			    char **modname, char *namebuf)
+{
+	namebuf[KSYM_NAME_LEN - 1] = 0;
+	namebuf[0] = 0;
+
+	if (modname)
+		*modname = NULL;
+	if (is_ksym_addr(addr)) {
+		unsigned long pos;
+
+		pos = get_symbol_pos(addr, symbolsize, offset, true);
+		if (!IS_LLOC(pos))
+			return NULL;
+		/* Grab name */
+		kallsyms_expand_symbol(get_symbol_offset(pos), namebuf);
+		return namebuf;
+	}
+
+	return NULL;
+}
+#else /* !CONFIG_KALLSYMS_LINE_LOCATIONS */
+const char *kallsyms_line_loc_lookup(unsigned long addr,
+			    unsigned long *symbolsize,
+			    unsigned long *offset,
+			    char **modname, char *namebuf)
+{
+	return NULL;
+}
+#endif /* CONFIG_KALLSYMS_LINE_LOCATIONS */
+
 /*
  * Lookup an address
  * - modname is set to NULL if it's in the kernel.
@@ -276,7 +352,7 @@ const char *kallsyms_lookup(unsigned long addr,
 	if (is_ksym_addr(addr)) {
 		unsigned long pos;
 
-		pos = get_symbol_pos(addr, symbolsize, offset);
+		pos = get_symbol_pos(addr, symbolsize, offset, false);
 		/* Grab name */
 		kallsyms_expand_symbol(get_symbol_offset(pos), namebuf);
 		if (modname)
@@ -297,7 +373,7 @@ int lookup_symbol_name(unsigned long addr, char *symname)
 	if (is_ksym_addr(addr)) {
 		unsigned long pos;
 
-		pos = get_symbol_pos(addr, NULL, NULL);
+		pos = get_symbol_pos(addr, NULL, NULL, false);
 		/* Grab name */
 		kallsyms_expand_symbol(get_symbol_offset(pos), symname);
 		return 0;
@@ -315,7 +391,7 @@ int lookup_symbol_attrs(unsigned long addr, unsigned long *size,
 	if (is_ksym_addr(addr)) {
 		unsigned long pos;
 
-		pos = get_symbol_pos(addr, size, offset);
+		pos = get_symbol_pos(addr, size, offset, false);
 		/* Grab name */
 		kallsyms_expand_symbol(get_symbol_offset(pos), name);
 		modname[0] = '\0';
@@ -332,7 +408,7 @@ static int __sprint_symbol(char *buffer, unsigned long address,
 	char *modname;
 	const char *name;
 	unsigned long offset, size;
-	int len;
+	int len, extra;
 
 	address += symbol_offset;
 	name = kallsyms_lookup(address, &size, &offset, &modname, buffer);
@@ -346,9 +422,19 @@ static int __sprint_symbol(char *buffer, unsigned long address,
 	offset -= symbol_offset;
 
 	if (modname)
-		len += sprintf(buffer, "+%#lx/%#lx [%s]", offset, size, modname);
+		extra = sprintf(buffer, "+%#lx/%#lx [%s]", offset,
+				size, modname);
 	else
-		len += sprintf(buffer, "+%#lx/%#lx", offset, size);
+		extra = sprintf(buffer, "+%#lx/%#lx", offset, size);
+	buffer += extra;
+	len += extra;
+	name = kallsyms_line_loc_lookup(address - symbol_offset, &size,
+					&offset, &modname, buffer + 1);
+
+	if (name) {
+		*buffer = ' ';
+		len = strlen(buffer);
+	}
 
 	return len;
 }
@@ -490,6 +576,10 @@ static int s_show(struct seq_file *m, void *p)
 	if (!iter->name[0])
 		return 0;
 
+	/* Ignore any src/line information */
+	if (iter->type == (char)0xff)
+		return 0;
+
 	if (iter->module_name[0]) {
 		char type;
 
-- 
1.7.10

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ