print module information when KALLSYMS is disabled.
No change for %pB, as it needs to know symbol name to adjust address
value which can't be done without KALLSYMS.
(A) original output with KALLSYMS:
[8.842129] ps function_1 [crash]
[8.842735] pS function_1+0x4/0x2c [crash]
[8.842890] pSb function_1+0x4/0x2c [crash b367e79021b9f3b0172f9a36d4261c1f528ca1b3]
[8.843175] pB function_1+0x4/0x2c [crash]
[8.843362] pBb function_1+0x4/0x2c [crash b367e79021b9f3b0172f9a36d4261c1f528ca1b3]
(B) original output without KALLSYMS:
[12.487424] ps 0xffff800000eb008c
[12.487598] pS 0xffff800000eb008c
[12.487723] pSb 0xffff800000eb008c
[12.487850] pB 0xffff800000eb008c
[12.487967] pBb 0xffff800000eb008c
(C) With patched kernel
with KALLYSMS:
[41.974576] ps function_1 [crash]
[41.975173] pS function_1+0x4/0x2c [crash]
[41.975386] pSb function_1+0x4/0x2c [crash a8b20caaec9635b316cf4812f6b55598fe2b7cee]
[41.975879] pB function_1+0x4/0x2c [crash]
[41.976076] pBb function_1+0x4/0x2c [crash a8b20caaec9635b316cf4812f6b55598fe2b7cee]
without KALLSYMS:
[9.624152] ps 0xffff800001bd008c [crash] // similar to original, no changes
[9.624548] pS 0x(____ptrval____)+0x8c [crash] // base address hashed and offset is without hash
[9.624847] pSb 0x(____ptrval____)+0x8c [crash a8b20caaec9635b316cf4812f6b55598fe2b7cee]
[9.625388] pB 0x(____ptrval____)+0x8c [crash]
[9.625594] pBb 0x(____ptrval____)+0x8c [crash a8b20caaec9635b316cf4812f6b55598fe2b7cee]
with disable hashing:
[8.563916] ps 0xffff800000f2008c [crash]
[8.564574] pS 0xffff800000f20000+0x8c [crash]
[8.564749] pSb 0xffff800000f20000+0x8c [crash 3423a8993a7033fb79e5add14bf9d8d6b56330ca]
[8.565008] pB 0xffff800000f20000+0x8c [crash]
[8.565154] pBb 0xffff800000f20000+0x8c [crash 3423a8993a7033fb79e5add14bf9d8d6b56330ca]
Suggested-by: Petr Mladek <[email protected]>
Co-developed-by: Vaneet Narang <[email protected]>
Signed-off-by: Vaneet Narang <[email protected]>
Signed-off-by: Maninder Singh <[email protected]>
---
include/linux/kallsyms.h | 2 +
include/linux/module.h | 20 ++++++++++
kernel/kallsyms.c | 27 +++++++------
kernel/module.c | 4 +-
lib/vsprintf.c | 85 ++++++++++++++++++++++++++++++++++------
5 files changed, 109 insertions(+), 29 deletions(-)
diff --git a/include/linux/kallsyms.h b/include/linux/kallsyms.h
index 4176c7eca7b5..1813ba9854f9 100644
--- a/include/linux/kallsyms.h
+++ b/include/linux/kallsyms.h
@@ -89,6 +89,8 @@ extern int sprint_symbol_build_id(char *buffer, unsigned long address);
extern int sprint_symbol_no_offset(char *buffer, unsigned long address);
extern int sprint_backtrace(char *buffer, unsigned long address);
extern int sprint_backtrace_build_id(char *buffer, unsigned long address);
+extern int sprint_kallsym_common(char *buffer, unsigned long address, int build_id,
+ int backtrace, int symbol);
int lookup_symbol_name(unsigned long addr, char *symname);
int lookup_symbol_attrs(unsigned long addr, unsigned long *size, unsigned long *offset, char *modname, char *name);
diff --git a/include/linux/module.h b/include/linux/module.h
index 1e135fd5c076..b154fa822f77 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -678,6 +678,20 @@ static inline bool is_livepatch_module(struct module *mod)
bool is_module_sig_enforced(void);
void set_module_sig_enforced(void);
+static inline int fill_name_build_id(char *buffer, char *modname,
+ int add_buildid, const unsigned char *buildid,
+ int len)
+{
+ len += sprintf(buffer + len, " [%s", modname);
+#if IS_ENABLED(CONFIG_STACKTRACE_BUILD_ID)
+ if (add_buildid && buildid) {
+ /* build ID should match length of sprintf */
+ static_assert(sizeof(typeof_member(struct module, build_id)) == 20);
+ len += sprintf(buffer + len, " %20phN", buildid);
+ }
+#endif
+ return len + sprintf(buffer + len, "]");
+}
#else /* !CONFIG_MODULES... */
static inline struct module *__module_address(unsigned long addr)
@@ -818,6 +832,12 @@ void *dereference_module_function_descriptor(struct module *mod, void *ptr)
return ptr;
}
+static inline int fill_name_build_id(char *buffer, char *modname,
+ int add_buildid, const unsigned char *buildid,
+ int len)
+{
+ return 0;
+}
#endif /* CONFIG_MODULES */
#ifdef CONFIG_SYSFS
diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c
index 951c93216fc4..bd014504771d 100644
--- a/kernel/kallsyms.c
+++ b/kernel/kallsyms.c
@@ -461,19 +461,8 @@ static int __sprint_symbol(char *buffer, unsigned long address,
if (add_offset)
len += sprintf(buffer + len, "+%#lx/%#lx", offset, size);
- if (modname) {
- len += sprintf(buffer + len, " [%s", modname);
-#if IS_ENABLED(CONFIG_STACKTRACE_BUILD_ID)
- if (add_buildid && buildid) {
- /* build ID should match length of sprintf */
-#if IS_ENABLED(CONFIG_MODULES)
- static_assert(sizeof(typeof_member(struct module, build_id)) == 20);
-#endif
- len += sprintf(buffer + len, " %20phN", buildid);
- }
-#endif
- len += sprintf(buffer + len, "]");
- }
+ if (modname)
+ len += fill_name_build_id(buffer, modname, add_buildid, buildid, len);
return len;
}
@@ -568,6 +557,18 @@ int sprint_backtrace_build_id(char *buffer, unsigned long address)
return __sprint_symbol(buffer, address, -1, 1, 1);
}
+int sprint_kallsym_common(char *buffer, unsigned long address, int build_id,
+ int backtrace, int symbol)
+{
+ if (backtrace)
+ return __sprint_symbol(buffer, address, -1, 1, build_id);
+
+ if (symbol)
+ return __sprint_symbol(buffer, address, 0, 1, build_id);
+
+ return __sprint_symbol(buffer, address, 0, 0, 0);
+}
+
/* To avoid using get_symbol_offset for every symbol, we carry prefix along. */
struct kallsym_iter {
loff_t pos;
diff --git a/kernel/module.c b/kernel/module.c
index 46a5c2ed1928..ccccb135c7fe 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -1465,12 +1465,10 @@ resolve_symbol_wait(struct module *mod,
return ksym;
}
-#ifdef CONFIG_KALLSYMS
static inline bool sect_empty(const Elf_Shdr *sect)
{
return !(sect->sh_flags & SHF_ALLOC) || sect->sh_size == 0;
}
-#endif
/*
* /sys/module/foo/sections stuff
@@ -2799,7 +2797,7 @@ static void add_kallsyms(struct module *mod, const struct load_info *info)
}
#endif /* CONFIG_KALLSYMS */
-#if IS_ENABLED(CONFIG_KALLSYMS) && IS_ENABLED(CONFIG_STACKTRACE_BUILD_ID)
+#if IS_ENABLED(CONFIG_STACKTRACE_BUILD_ID)
static void init_build_id(struct module *mod, const struct load_info *info)
{
const Elf_Shdr *sechdr;
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index 3b8129dd374c..6f661f5a6814 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -979,33 +979,92 @@ char *bdev_name(char *buf, char *end, struct block_device *bdev,
}
#endif
+#if !defined(CONFIG_KALLSYMS) && defined(CONFIG_MODULES)
+static int sprint_module_info(char *buf, unsigned long value,
+ int modbuildid, int backtrace, int symbol)
+{
+ struct module *mod;
+ unsigned long offset;
+ void *base;
+ char *modname;
+ int len;
+ const unsigned char *buildid = NULL;
+ bool add_offset;
+
+ if (is_ksym_addr(value))
+ return 0;
+
+ if (backtrace || symbol)
+ add_offset = true;
+ else
+ add_offset = false;
+
+ preempt_disable();
+ mod = __module_address(value);
+ if (mod) {
+ modname = mod->name;
+#if IS_ENABLED(CONFIG_STACKTRACE_BUILD_ID)
+ if (modbuildid)
+ buildid = mod->build_id;
+#endif
+ if (add_offset) {
+ base = mod->core_layout.base;
+ offset = value - (unsigned long)base;
+ }
+ }
+ preempt_enable();
+ if (!mod)
+ return 0;
+
+ /* address belongs to module */
+ if (add_offset)
+ len = sprintf(buf, "0x%p+0x%lx", base, offset);
+ else
+ len = sprintf(buf, "0x%lx", value);
+
+ return len + fill_name_build_id(buf, modname, modbuildid, buildid, len);
+}
+#else
+static inline int sprint_module_info(char *buf, unsigned long value,
+ int modbuildid, int backtrace, int symbol)
+{
+ return 0;
+}
+#endif
+
static noinline_for_stack
char *symbol_string(char *buf, char *end, void *ptr,
struct printf_spec spec, const char *fmt)
{
unsigned long value;
-#ifdef CONFIG_KALLSYMS
char sym[KSYM_SYMBOL_LEN];
-#endif
+ int backtrace = 0, symbol = 0, build_id = 0;
if (fmt[1] == 'R')
ptr = __builtin_extract_return_addr(ptr);
value = (unsigned long)ptr;
-#ifdef CONFIG_KALLSYMS
- if (*fmt == 'B' && fmt[1] == 'b')
- sprint_backtrace_build_id(sym, value);
- else if (*fmt == 'B')
- sprint_backtrace(sym, value);
- else if (*fmt == 'S' && (fmt[1] == 'b' || (fmt[1] == 'R' && fmt[2] == 'b')))
- sprint_symbol_build_id(sym, value);
- else if (*fmt != 's')
- sprint_symbol(sym, value);
- else
- sprint_symbol_no_offset(sym, value);
+ if (fmt[0] == 'B' && fmt[1] == 'b') {
+ backtrace = 1;
+ build_id = 1;
+ } else if (fmt[0] == 'B')
+ backtrace = 1;
+ else if (fmt[0] == 'S' && (fmt[1] == 'b' || (fmt[1] == 'R' && fmt[2] == 'b'))) {
+ symbol = 1;
+ build_id = 1;
+ } else if (fmt[0] != 's')
+ symbol = 1;
+ else {
+ /* Do Nothing, no offset */
+ }
+#ifdef CONFIG_KALLSYMS
+ sprint_kallsym_common(sym, value, build_id, backtrace, symbol);
return string_nocheck(buf, end, sym, spec);
#else
+ if (sprint_module_info(sym, value, build_id, backtrace, symbol))
+ return string_nocheck(buf, end, sym, spec);
+
return special_hex_number(buf, end, value, sizeof(void *));
#endif
}
--
2.17.1
On Wed 2022-03-16 10:05:40, Maninder Singh wrote:
> print module information when KALLSYMS is disabled.
>
> No change for %pB, as it needs to know symbol name to adjust address
> value which can't be done without KALLSYMS.
>
> (A) original output with KALLSYMS:
> [8.842129] ps function_1 [crash]
> [8.842735] pS function_1+0x4/0x2c [crash]
> [8.842890] pSb function_1+0x4/0x2c [crash b367e79021b9f3b0172f9a36d4261c1f528ca1b3]
> [8.843175] pB function_1+0x4/0x2c [crash]
> [8.843362] pBb function_1+0x4/0x2c [crash b367e79021b9f3b0172f9a36d4261c1f528ca1b3]
>
> (B) original output without KALLSYMS:
> [12.487424] ps 0xffff800000eb008c
> [12.487598] pS 0xffff800000eb008c
> [12.487723] pSb 0xffff800000eb008c
> [12.487850] pB 0xffff800000eb008c
> [12.487967] pBb 0xffff800000eb008c
>
> (C) With patched kernel
> with KALLYSMS:
> [41.974576] ps function_1 [crash]
> [41.975173] pS function_1+0x4/0x2c [crash]
> [41.975386] pSb function_1+0x4/0x2c [crash a8b20caaec9635b316cf4812f6b55598fe2b7cee]
> [41.975879] pB function_1+0x4/0x2c [crash]
> [41.976076] pBb function_1+0x4/0x2c [crash a8b20caaec9635b316cf4812f6b55598fe2b7cee]
>
> without KALLSYMS:
> [9.624152] ps 0xffff800001bd008c [crash] // similar to original, no changes
> [9.624548] pS 0x(____ptrval____)+0x8c [crash] // base address hashed and offset is without hash
> [9.624847] pSb 0x(____ptrval____)+0x8c [crash a8b20caaec9635b316cf4812f6b55598fe2b7cee]
> [9.625388] pB 0x(____ptrval____)+0x8c [crash]
> [9.625594] pBb 0x(____ptrval____)+0x8c [crash a8b20caaec9635b316cf4812f6b55598fe2b7cee]
>
> with disable hashing:
> [8.563916] ps 0xffff800000f2008c [crash]
> [8.564574] pS 0xffff800000f20000+0x8c [crash]
> [8.564749] pSb 0xffff800000f20000+0x8c [crash 3423a8993a7033fb79e5add14bf9d8d6b56330ca]
> [8.565008] pB 0xffff800000f20000+0x8c [crash]
> [8.565154] pBb 0xffff800000f20000+0x8c [crash 3423a8993a7033fb79e5add14bf9d8d6b56330ca]
>
> --- a/lib/vsprintf.c
> +++ b/lib/vsprintf.c
> @@ -979,33 +979,92 @@ char *bdev_name(char *buf, char *end, struct block_device *bdev,
> }
> #endif
>
> +#if !defined(CONFIG_KALLSYMS) && defined(CONFIG_MODULES)
> +static int sprint_module_info(char *buf, unsigned long value,
> + int modbuildid, int backtrace, int symbol)
> +{
> + struct module *mod;
> + unsigned long offset;
> + void *base;
> + char *modname;
> + int len;
> + const unsigned char *buildid = NULL;
> + bool add_offset;
> +
> + if (is_ksym_addr(value))
> + return 0;
> +
> + if (backtrace || symbol)
> + add_offset = true;
> + else
> + add_offset = false;
> +
> + preempt_disable();
> + mod = __module_address(value);
> + if (mod) {
> + modname = mod->name;
> +#if IS_ENABLED(CONFIG_STACKTRACE_BUILD_ID)
> + if (modbuildid)
> + buildid = mod->build_id;
> +#endif
> + if (add_offset) {
> + base = mod->core_layout.base;
> + offset = value - (unsigned long)base;
> + }
> + }
> + preempt_enable();
> + if (!mod)
> + return 0;
I think that some earlier version of the patch allowed to print
also the address from vmlinux with the offset. My concern was
that it would show non-hashed base pointer. IMHO, it is fine
to show it hashed.
> +
> + /* address belongs to module */
> + if (add_offset)
> + len = sprintf(buf, "0x%p+0x%lx", base, offset);
> + else
> + len = sprintf(buf, "0x%lx", value);
> +
> + return len + fill_name_build_id(buf, modname, modbuildid, buildid, len);
> +}
Otherwise, it looks good to me. I did also some basic testing.
The vmlinux address with offset can be added by a followup patch.
Feel free to use:
Reviewed-by: Petr Mladek <[email protected]>
Tested-by: Petr Mladek <[email protected]>
Best Regards,
Petr
On (22/03/16 10:05), Maninder Singh wrote:
[..]
> +static int sprint_module_info(char *buf, unsigned long value,
> + int modbuildid, int backtrace, int symbol)
> +{
> + struct module *mod;
> + unsigned long offset;
> + void *base;
> + char *modname;
> + int len;
> + const unsigned char *buildid = NULL;
> + bool add_offset;
> +
> + if (is_ksym_addr(value))
> + return 0;
> +
> + if (backtrace || symbol)
> + add_offset = true;
> + else
> + add_offset = false;
> +
> + preempt_disable();
> + mod = __module_address(value);
> + if (mod) {
> + modname = mod->name;
> +#if IS_ENABLED(CONFIG_STACKTRACE_BUILD_ID)
> + if (modbuildid)
> + buildid = mod->build_id;
> +#endif
> + if (add_offset) {
> + base = mod->core_layout.base;
> + offset = value - (unsigned long)base;
> + }
What if address is in module init? Shouldn't this be something like
if (within_module_init(value, mod))
offset = value - (unsigned long)mod->init_layout.base;
else
offset = value - (unsigned long)mod->core_layout.base;
Hi Sergey,
> > + if (add_offset) {
> > + base = mod->core_layout.base;
> > + offset = value - (unsigned long)base;
> > + }
>
> What if address is in module init? Shouldn't this be something like
>
> if (within_module_init(value, mod))
> offset = value - (unsigned long)mod->init_layout.base;
> else
> offset = value - (unsigned long)mod->core_layout.base;
Yes, this can be done, but I think then we need to handle it with some more info.
In module allocation first we load core_layout and then init_layout w.r.t address range
as below (ARM64):
ffff800000eb0000 -> core_layout
ffff800000eb4000 -> init_layout
So if we write only offset(w.r.t core_layout), then user can get a hint if it going beyond normal text
then it means it is init text.
But if we take offset from init and core separately, and we only print the offset (not function name),
we need to write alongwith offset that it is init or core area.
Otherwise user will get confused which offset it is, whether to check init or core text area.
And also while printing modules, kernel also uses core_layout as base address only:
static int m_show(struct seq_file *m, void *p)
{
..
/* Used by oprofile and other similar tools. */
value = m->private ? NULL : mod->core_layout.base;
seq_printf(m, " 0x%px", value);
..
}
and also normal %ps prints like below:
ps 0xffff800000eb4004
load address of module is 0xffff800000eb0000
so normal offset is 4004 for init text section.
and same thing is printed with current patch:
pS 0xffff800000eb0000+0x4004 [crash]
Still if we need to handle separately, then please suggest only offset is ok or we need to
add string for init or core also like below:
init_text start + offset
pS 0xffff800000eb4000+0x4 [crash init_text]
And also then there will be discrepancy for rodata or other sections, which offset to take.
If we are taking it from core_layout then init section can also be taken with same.
As of now it is unique offset calculation for all sections.
Thanks,
Maninder Singh
On Wed, Mar 16, 2022 at 10:05:40AM +0530, Maninder Singh wrote:
> print module information when KALLSYMS is disabled.
>
> No change for %pB, as it needs to know symbol name to adjust address
> value which can't be done without KALLSYMS.
>
> (A) original output with KALLSYMS:
> [8.842129] ps function_1 [crash]
> [8.842735] pS function_1+0x4/0x2c [crash]
> [8.842890] pSb function_1+0x4/0x2c [crash b367e79021b9f3b0172f9a36d4261c1f528ca1b3]
> [8.843175] pB function_1+0x4/0x2c [crash]
> [8.843362] pBb function_1+0x4/0x2c [crash b367e79021b9f3b0172f9a36d4261c1f528ca1b3]
>
> (B) original output without KALLSYMS:
> [12.487424] ps 0xffff800000eb008c
> [12.487598] pS 0xffff800000eb008c
> [12.487723] pSb 0xffff800000eb008c
> [12.487850] pB 0xffff800000eb008c
> [12.487967] pBb 0xffff800000eb008c
>
> (C) With patched kernel
> with KALLYSMS:
> [41.974576] ps function_1 [crash]
> [41.975173] pS function_1+0x4/0x2c [crash]
> [41.975386] pSb function_1+0x4/0x2c [crash a8b20caaec9635b316cf4812f6b55598fe2b7cee]
> [41.975879] pB function_1+0x4/0x2c [crash]
> [41.976076] pBb function_1+0x4/0x2c [crash a8b20caaec9635b316cf4812f6b55598fe2b7cee]
>
> without KALLSYMS:
> [9.624152] ps 0xffff800001bd008c [crash] // similar to original, no changes
> [9.624548] pS 0x(____ptrval____)+0x8c [crash] // base address hashed and offset is without hash
> [9.624847] pSb 0x(____ptrval____)+0x8c [crash a8b20caaec9635b316cf4812f6b55598fe2b7cee]
> [9.625388] pB 0x(____ptrval____)+0x8c [crash]
> [9.625594] pBb 0x(____ptrval____)+0x8c [crash a8b20caaec9635b316cf4812f6b55598fe2b7cee]
>
> with disable hashing:
> [8.563916] ps 0xffff800000f2008c [crash]
> [8.564574] pS 0xffff800000f20000+0x8c [crash]
> [8.564749] pSb 0xffff800000f20000+0x8c [crash 3423a8993a7033fb79e5add14bf9d8d6b56330ca]
> [8.565008] pB 0xffff800000f20000+0x8c [crash]
> [8.565154] pBb 0xffff800000f20000+0x8c [crash 3423a8993a7033fb79e5add14bf9d8d6b56330ca]
>
> Suggested-by: Petr Mladek <[email protected]>
> Co-developed-by: Vaneet Narang <[email protected]>
> Signed-off-by: Vaneet Narang <[email protected]>
> Signed-off-by: Maninder Singh <[email protected]>
I've pushed a lot of queued code into modules-testing (not modules-next
yet) [0] please base your changes on that in a new iteration as that is what
things look like now.
Vimal might be interested in your work too and you might be interested
in his patch too [1].
[0] https://git.kernel.org/pub/scm/linux/kernel/git/mcgrof/linux.git/log/?h=modules-testing
[1] https://lkml.kernel.org/r/CALkUMdRO+JAF_Dw3Q-mHOxvt7uM6gVDNGAA3OMeCUpnSvi7_Pg@mail.gmail.com
Luis