Support: - sym -l - sym -M - sym -m module Signed-off-by: Kazuhito Hagio <k-hagio-ab@xxxxxxx> --- symbols.c | 234 +++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 225 insertions(+), 9 deletions(-) diff --git a/symbols.c b/symbols.c index 88849833bada..669fa2e2f3da 100644 --- a/symbols.c +++ b/symbols.c @@ -103,9 +103,16 @@ static void free_structure(struct struct_elem *); static unsigned char is_right_brace(const char *); static struct struct_elem *find_node(struct struct_elem *, char *); static void dump_node(struct struct_elem *, char *, unsigned char, unsigned char); -static int _in_module(ulong, struct load_module *, int); + +static int module_mem_type(ulong, struct load_module *); static ulong module_mem_end(ulong, struct load_module *); +static int _in_module(ulong, struct load_module *, int); +struct syment *value_search_module_v2(ulong, ulong *); +static const char *module_start_tags[]; +static const char *module_start_strs[]; +static const char *module_end_tags[]; +static const char *module_end_strs[]; /* * structure/union printing stuff @@ -1270,10 +1277,14 @@ symname_hash_search(struct syment *table[], char *name) * Output for sym -[lL] command. */ +#define MODULE_PSEUDO_SYMBOL(sp) (STRNEQ((sp)->name, "_MODULE_")) + +/* #define MODULE_PSEUDO_SYMBOL(sp) \ ((STRNEQ((sp)->name, "_MODULE_START_") || STRNEQ((sp)->name, "_MODULE_END_")) || \ (STRNEQ((sp)->name, "_MODULE_INIT_START_") || STRNEQ((sp)->name, "_MODULE_INIT_END_")) || \ (STRNEQ((sp)->name, "_MODULE_SECTION_"))) +*/ #define MODULE_START(sp) (STRNEQ((sp)->name, "_MODULE_START_")) #define MODULE_END(sp) (STRNEQ((sp)->name, "_MODULE_END_")) @@ -1282,6 +1293,93 @@ symname_hash_search(struct syment *table[], char *name) #define MODULE_SECTION_START(sp) (STRNEQ((sp)->name, "_MODULE_SECTION_START")) #define MODULE_SECTION_END(sp) (STRNEQ((sp)->name, "_MODULE_SECTION_END")) +#define MODULE_MEM_START(sp,i) (STRNEQ((sp)->name, module_start_tags[i])) +#define MODULE_MEM_END(sp,i) (STRNEQ((sp)->name, module_end_tags[i])) + +/* For 6.4 and later */ +static void +module_symbol_dump(char *module) +{ + int i, j, start, percpu_syms; + struct syment *sp, *sp_end; + struct load_module *lm; + const char *p1, *p2; + +#define TBD 1 +#define DISPLAYED 2 + + for (i = 0; i < st->mods_installed; i++) { + + lm = &st->load_modules[i]; + if (module && !STREQ(module, lm->mod_name)) + continue; + + if (received_SIGINT() || output_closed()) + return; + + for (j = MOD_TEXT; j < MOD_MEM_NUM_TYPES; j++) { + + if (!lm->symtable[j]) + continue; + + sp = lm->symtable[j]; + sp_end = lm->symend[j]; + percpu_syms = 0; + + for (start = FALSE; sp <= sp_end; sp++) { + /* TODO + if (IN_MODULE_PERCPU(sp->value, lm)) { + if (percpu_syms == DISPLAYED) + continue; + if (!start) { + percpu_syms = TBD; + continue; + } + dump_percpu_symbols(lm); + percpu_syms = DISPLAYED; + } + */ + if (MODULE_PSEUDO_SYMBOL(sp)) { + if (MODULE_SECTION_START(sp)) { + p1 = sp->name + strlen("_MODULE_SECTION_START "); + p2 = "section start"; + } else if (MODULE_SECTION_END(sp)) { + p1 = sp->name + strlen("_MODULE_SECTION_END "); + p2 = "section end"; + } else if (STRNEQ(sp->name, module_start_tags[j])) { + p1 = module_start_strs[j]; + p2 = sp->name + strlen(module_start_tags[j]); + start = TRUE; + } else if (STRNEQ(sp->name, module_end_tags[j])) { + p1 = module_end_strs[j]; + p2 = sp->name + strlen(module_end_tags[j]); + /* TODO + if (MODULE_PERCPU_SYMS_LOADED(lm) && + !percpu_syms) { + dump_percpu_symbols(lm); + percpu_syms = DISPLAYED; + } + */ + } else { + p1 = "unknown tag"; + p2 = sp->name; + } + + fprintf(fp, "%lx %s: %s\n", sp->value, p1, p2); + + /* TODO + if (percpu_syms == TBD) { + dump_percpu_symbols(lm); + percpu_syms = DISPLAYED; + } + */ + } else + show_symbol(sp, 0, SHOW_RADIX()); + } + } + } +} + static void symbol_dump(ulong flags, char *module) { @@ -1304,6 +1402,11 @@ symbol_dump(ulong flags, char *module) if (!(flags & MODULE_SYMS)) return; + if (MODULE_MEMORY()) { /* 6.4 and later */ + module_symbol_dump(module); + return; + } + for (i = 0; i < st->mods_installed; i++) { lm = &st->load_modules[i]; @@ -1808,6 +1911,24 @@ static const char *module_end_tags[] = { "_MODULE_INIT_DATA_END_", "_MODULE_INIT_RODATA_END_" }; +static const char *module_start_strs[] = { + "MODULE TEXT START", + "MODULE DATA START", + "MODULE RODATA START", + "MODULE RO_AFTER_INIT START", + "MODULE INIT_TEXT START", + "MODULE INIT_DATA START", + "MODULE INIT_RODATA START" +}; +static const char *module_end_strs[] = { + "MODULE TEXT END", + "MODULE DATA END", + "MODULE RODATA END", + "MODULE RO_AFTER_INIT END", + "MODULE INIT_TEXT END", + "MODULE INIT_DATA END", + "MODULE INIT_RODATA END" +}; /* * Linux 6.4 introduced module.mem memory layout @@ -5278,6 +5399,85 @@ module_symbol(ulong value, return FALSE; } +/* Linux 6.4 and later */ +struct syment * +value_search_module_v2(ulong value, ulong *offset) +{ + int i, j; + struct syment *sp, *sp_end, *spnext, *splast; + struct load_module *lm; + + for (i = 0; i < st->mods_installed; i++) { + lm = &st->load_modules[i]; + + if (!IN_MODULE(value, lm) && !IN_MODULE_INIT(value, lm)) + continue; + + for (j = MOD_TEXT; j < MOD_MEM_NUM_TYPES; j++) { + sp = lm->symtable[j]; + sp_end = lm->symend[j]; + + if (value < sp->value) + continue; + + splast = NULL; + for ( ; sp <= sp_end; sp++) { + /* TODO + if (machine_type("ARM64") && + IN_MODULE_PERCPU(sp->value, lm) && + !IN_MODULE_PERCPU(value, lm)) + continue; + */ + + if (value == sp->value) { + if (MODULE_MEM_END(sp, j)) + break; + + if (MODULE_PSEUDO_SYMBOL(sp)) { + spnext = sp + 1; + if (MODULE_PSEUDO_SYMBOL(spnext)) + continue; + if (spnext->value == value) + sp = spnext; + } + /* TODO: probably not needed anymore? */ + if (is_insmod_builtin(lm, sp)) { + spnext = sp+1; + if ((spnext < sp_end) && + (value == spnext->value)) + sp = spnext; + } + if (sp->name[0] == '.') { + spnext = sp+1; + if (spnext->value == value) + sp = spnext; + } + if (offset) + *offset = 0; + return sp; + } + + if (sp->value > value) { + sp = splast ? splast : sp - 1; + if (offset) + *offset = value - sp->value; + return sp; + } + + if (!MODULE_PSEUDO_SYMBOL(sp)) { + if (is_insmod_builtin(lm, sp)) { + if (!splast || (sp->value > splast->value)) + splast = sp; + } else + splast = sp; + } + } + } + } + + return NULL; +} + struct syment * value_search_module(ulong value, ulong *offset) { @@ -5286,6 +5486,9 @@ value_search_module(ulong value, ulong *offset) struct load_module *lm; int search_init_sections, search_init; + if (MODULE_MEMORY()) /* Linux 6.4 and later */ + return value_search_module_v2(value, offset); + search_init = FALSE; search_init_sections = 0; @@ -13958,19 +14161,32 @@ _in_module(ulong addr, struct load_module *lm, int type) return ((addr >= base) && (addr < (base + size))); } -/* Returns the end address of the module memory region. */ -static ulong -module_mem_end(ulong addr, struct load_module *lm) +/* Returns module memory type, otherwise MOD_INVALID(-1) */ +static int +module_mem_type(ulong addr, struct load_module *lm) { - ulong base, end; + ulong base; int i; + for (i = MOD_TEXT; i < MOD_MEM_NUM_TYPES; i++) { base = lm->mem[i].base; if (!base) continue; - end = base + lm->mem[i].size; - if ((addr >= base) && (addr < end)) - return end; + if ((addr >= base) && (addr < base + lm->mem[i].size)) + return i; } - return 0; + + return MOD_INVALID; +} + +/* Returns the end address of the module memory region. */ +static ulong +module_mem_end(ulong addr, struct load_module *lm) +{ + int type = module_mem_type(addr, lm); + + if (type == MOD_INVALID || type >= MOD_MEM_NUM_TYPES) + return 0; + + return lm->mem[type].base + lm->mem[type].size; } -- 2.31.1 -- Crash-utility mailing list Crash-utility@xxxxxxxxxx https://listman.redhat.com/mailman/listinfo/crash-utility Contribution Guidelines: https://github.com/crash-utility/crash/wiki