Support module memory layout change on Linux 6.4 by kernel commit ac3b43283923 ("module: replace module_layout with module_memory") [1]. Without the patch, crash cannot even start a session with an error message like this: crash: invalid structure member offset: module_core_size FILE: kernel.c LINE: 3787 FUNCTION: module_init() [1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=ac3b43283923 Signed-off-by: Kazuhito Hagio <k-hagio-ab@xxxxxxx> --- v1 -> v2 - Made several functions in symbol.c static - Fixed a compilation warning on gdb-10.2/gdb/symtab.c - Fixed a compilation error with an old gcc like RHEL7 - Fixed a v1 bug, "sym" doesn't show multiple symbols with the same name: crash> sym cleanup_module ffffffffc07fc8c0 (T) cleanup_module [dm_mod] crash> v1: https://listman.redhat.com/archives/crash-utility/2023-June/010806.html RFC: https://listman.redhat.com/archives/crash-utility/2023-May/010647.html defs.h | 46 +- gdb-10.2.patch | 25 + kernel.c | 56 +- memory.c | 38 +- symbols.c | 1609 ++++++++++++++++++++++++++++++++++++++++++++---- 5 files changed, 1629 insertions(+), 145 deletions(-) diff --git a/defs.h b/defs.h index 3e7d6cfbc6a8..414853660dc1 100644 --- a/defs.h +++ b/defs.h @@ -675,6 +675,7 @@ struct new_utsname { #define IRQ_DESC_TREE_RADIX (0x40ULL) #define IRQ_DESC_TREE_XARRAY (0x80ULL) #define KMOD_PAX (0x100ULL) +#define KMOD_MEMORY (0x200ULL) #define XEN() (kt->flags & ARCH_XEN) #define OPENVZ() (kt->flags & ARCH_OPENVZ) @@ -682,6 +683,7 @@ struct new_utsname { #define PVOPS_XEN() (kt->flags & ARCH_PVOPS_XEN) #define PAX_MODULE_SPLIT() (kt->flags2 & KMOD_PAX) +#define MODULE_MEMORY() (kt->flags2 & KMOD_MEMORY) #define XEN_MACHINE_TO_MFN(m) ((ulonglong)(m) >> PAGESHIFT()) #define XEN_PFN_TO_PSEUDO(p) ((ulonglong)(p) << PAGESHIFT()) @@ -2217,6 +2219,9 @@ struct offset_table { /* stash of commonly-used offsets */ long kset_kobj; long subsys_private_subsys; long vmap_area_purge_list; + long module_mem; + long module_memory_base; + long module_memory_size; }; struct size_table { /* stash of commonly-used sizes */ @@ -2390,6 +2395,7 @@ struct size_table { /* stash of commonly-used sizes */ long percpu_counter; long maple_tree; long maple_node; + long module_memory; }; struct array_table { @@ -2922,6 +2928,23 @@ struct mod_section_data { ulong size; int priority; int flags; + ulong addr; +}; + +/* Emulate enum mod_mem_type in include/linux/module.h */ +#define MOD_TEXT (0) +#define MOD_DATA (1) +#define MOD_RODATA (2) +#define MOD_RO_AFTER_INIT (3) +#define MOD_INIT_TEXT (4) +#define MOD_INIT_DATA (5) +#define MOD_INIT_RODATA (6) +#define MOD_MEM_NUM_TYPES (7) +#define MOD_INVALID (-1) + +struct module_memory { + ulong base; + uint size; }; struct load_module { @@ -2957,19 +2980,29 @@ struct load_module { ulong mod_percpu; ulong mod_percpu_size; struct objfile *loaded_objfile; -}; -#define IN_MODULE(A,L) \ - (((ulong)(A) >= (L)->mod_base) && ((ulong)(A) < ((L)->mod_base+(L)->mod_size))) - -#define IN_MODULE_INIT(A,L) \ - (((ulong)(A) >= (L)->mod_init_module_ptr) && ((ulong)(A) < ((L)->mod_init_module_ptr+(L)->mod_init_size))) + /* For 6.4 module_memory */ + struct module_memory mem[MOD_MEM_NUM_TYPES]; + struct syment **symtable; + struct syment **symend; + struct syment *ext_symtable[MOD_MEM_NUM_TYPES]; + struct syment *ext_symend[MOD_MEM_NUM_TYPES]; + struct syment *load_symtable[MOD_MEM_NUM_TYPES]; + struct syment *load_symend[MOD_MEM_NUM_TYPES]; +}; +#define IN_MODULE(A,L) (in_module_range(A, L, MOD_TEXT, MOD_RO_AFTER_INIT) != MOD_INVALID) +#define IN_MODULE_INIT(A,L) (in_module_range(A, L, MOD_INIT_TEXT, MOD_INIT_RODATA) != MOD_INVALID) +#define IN_MODULE_TEXT(A,L) (in_module_range(A, L, MOD_TEXT, MOD_TEXT) == MOD_TEXT || \ + in_module_range(A, L, MOD_INIT_TEXT, MOD_INIT_TEXT) == MOD_INIT_TEXT) #define IN_MODULE_PERCPU(A,L) \ (((ulong)(A) >= (L)->mod_percpu) && ((ulong)(A) < ((L)->mod_percpu+(L)->mod_percpu_size))) #define MODULE_PERCPU_SYMS_LOADED(L) ((L)->mod_percpu && (L)->mod_percpu_size) +#define for_each_mod_mem_type(type) \ + for ((type) = MOD_TEXT; (type) < MOD_MEM_NUM_TYPES; (type)++) + #ifndef GDB_COMMON #define KVADDR (0x1) @@ -5588,6 +5621,7 @@ void dump_struct_member(char *, ulong, unsigned); void dump_union(char *, ulong, unsigned); void store_module_symbols_v1(ulong, int); void store_module_symbols_v2(ulong, int); +void store_module_symbols_6_4(ulong, int); int is_datatype_command(void); int is_typedef(char *); int arg_to_datatype(char *, struct datatype_member *, ulong); diff --git a/gdb-10.2.patch b/gdb-10.2.patch index 835aae9859be..16228b1dbf73 100644 --- a/gdb-10.2.patch +++ b/gdb-10.2.patch @@ -3120,3 +3120,28 @@ exit 0 return result; } +--- gdb-10.2/gdb/symtab.c.orig ++++ gdb-10.2/gdb/symtab.c +@@ -7476,7 +7476,7 @@ gdb_add_symbol_file(struct gnu_request * + int i; + int allsect = 0; + char *secname; +- char buf[80]; ++ char buf[96]; + + gdb_current_load_module = lm = (struct load_module *)req->addr; + +@@ -7515,8 +7515,11 @@ gdb_add_symbol_file(struct gnu_request * + secname = lm->mod_section_data[i].name; + if ((lm->mod_section_data[i].flags & SEC_FOUND) && + !STREQ(secname, ".text")) { +- sprintf(buf, " -s %s 0x%lx", secname, +- lm->mod_section_data[i].offset + lm->mod_base); ++ if (lm->mod_section_data[i].addr) ++ sprintf(buf, " -s %s 0x%lx", secname, lm->mod_section_data[i].addr); ++ else ++ sprintf(buf, " -s %s 0x%lx", secname, ++ lm->mod_section_data[i].offset + lm->mod_base); + strcat(req->buf, buf); + } + } diff --git a/kernel.c b/kernel.c index 6e98f5f6f6b1..639ed64f306a 100644 --- a/kernel.c +++ b/kernel.c @@ -3571,7 +3571,21 @@ module_init(void) MEMBER_OFFSET_INIT(module_num_gpl_syms, "module", "num_gpl_syms"); - if (MEMBER_EXISTS("module", "module_core")) { + if (MEMBER_EXISTS("module", "mem")) { /* 6.4 and later */ + kt->flags2 |= KMOD_MEMORY; /* MODULE_MEMORY() can be used. */ + + MEMBER_OFFSET_INIT(module_mem, "module", "mem"); + MEMBER_OFFSET_INIT(module_memory_base, "module_memory", "base"); + MEMBER_OFFSET_INIT(module_memory_size, "module_memory", "size"); + STRUCT_SIZE_INIT(module_memory, "module_memory"); + + if (CRASHDEBUG(1)) + error(INFO, "struct module_memory detected.\n"); + + if (get_array_length("module.mem", NULL, 0) != MOD_MEM_NUM_TYPES) + error(WARNING, "module memory types have changed!\n"); + + } else if (MEMBER_EXISTS("module", "module_core")) { MEMBER_OFFSET_INIT(module_core_size, "module", "core_size"); MEMBER_OFFSET_INIT(module_init_size, "module", @@ -3757,6 +3771,8 @@ module_init(void) total += nsyms; total += 2; /* store the module's start/ending addresses */ total += 2; /* and the init start/ending addresses */ + if (MODULE_MEMORY()) /* 7 regions at most -> 14, so needs +10 */ + total += 10; /* * If the module has kallsyms, set up to grab them as well. @@ -3784,7 +3800,11 @@ module_init(void) case KALLSYMS_V2: if (THIS_KERNEL_VERSION >= LINUX(2,6,27)) { numksyms = UINT(modbuf + OFFSET(module_num_symtab)); - size = UINT(modbuf + MODULE_OFFSET2(module_core_size, rx)); + if (MODULE_MEMORY()) + /* check mem[MOD_TEXT].size only */ + size = UINT(modbuf + OFFSET(module_mem) + OFFSET(module_memory_size)); + else + size = UINT(modbuf + MODULE_OFFSET2(module_core_size, rx)); } else { numksyms = ULONG(modbuf + OFFSET(module_num_symtab)); size = ULONG(modbuf + MODULE_OFFSET2(module_core_size, rx)); @@ -3822,7 +3842,10 @@ module_init(void) store_module_symbols_v1(total, kt->mods_installed); break; case KMOD_V2: - store_module_symbols_v2(total, kt->mods_installed); + if (MODULE_MEMORY()) + store_module_symbols_6_4(total, kt->mods_installed); + else + store_module_symbols_v2(total, kt->mods_installed); break; } @@ -3836,7 +3859,7 @@ module_init(void) static int verify_modules(void) { - int i; + int i, t; int found, irregularities; ulong mod, mod_next, mod_base; long mod_size; @@ -3893,8 +3916,13 @@ verify_modules(void) mod_base = mod; break; case KMOD_V2: - mod_base = ULONG(modbuf + - MODULE_OFFSET2(module_module_core, rx)); + if (MODULE_MEMORY()) + /* mem[MOD_TEXT].base */ + mod_base = ULONG(modbuf + OFFSET(module_mem) + + OFFSET(module_memory_base)); + else + mod_base = ULONG(modbuf + + MODULE_OFFSET2(module_module_core, rx)); break; } @@ -3916,7 +3944,17 @@ verify_modules(void) case KMOD_V2: module_name = modbuf + OFFSET(module_name); - if (THIS_KERNEL_VERSION >= LINUX(2,6,27)) + if (MODULE_MEMORY()) { + mod_size = 0; + for_each_mod_mem_type(t) { + if (t == MOD_INIT_TEXT) + break; + + mod_size += UINT(modbuf + OFFSET(module_mem) + + SIZE(module_memory) * t + + OFFSET(module_memory_size)); + } + } else if (THIS_KERNEL_VERSION >= LINUX(2,6,27)) mod_size = UINT(modbuf + MODULE_OFFSET2(module_core_size, rx)); else @@ -4536,7 +4574,7 @@ do_module_cmd(ulong flag, char *modref, ulong address, "MODULE"), mkstring(buf2, maxnamelen, LJUST, "NAME"), mkstring(buf4, VADDR_PRLEN, CENTER|LJUST, - "BASE"), + MODULE_MEMORY() ? "TEXT_BASE" : "BASE"), mkstring(buf3, maxsizelen, RJUST, "SIZE")); } @@ -6144,6 +6182,8 @@ dump_kernel_table(int verbose) fprintf(fp, "%sIRQ_DESC_TREE_XARRAY", others++ ? "|" : ""); if (kt->flags2 & KMOD_PAX) fprintf(fp, "%sKMOD_PAX", others++ ? "|" : ""); + if (kt->flags2 & KMOD_MEMORY) + fprintf(fp, "%sKMOD_MEMORY", others++ ? "|" : ""); fprintf(fp, ")\n"); fprintf(fp, " stext: %lx\n", kt->stext); diff --git a/memory.c b/memory.c index ea3005a5c01f..acbee6389472 100644 --- a/memory.c +++ b/memory.c @@ -15712,10 +15712,44 @@ in_vmlist_segment(ulong vaddr) static int next_module_vaddr(ulong vaddr, ulong *nextvaddr) { - int i; - ulong start, end; + int i, t; + ulong start, end, min = (ulong)-1; struct load_module *lm; + if (!MODULE_MEMORY()) + goto old_module; + + for (i = 0; i < st->mods_installed; i++) { + lm = &st->load_modules[i]; + + for_each_mod_mem_type(t) { + if (!lm->mem[t].size) + continue; + + start = lm->mem[t].base; + end = start + lm->mem[t].size; + + if (vaddr >= end) + continue; + + if (vaddr < start) { + if (start < min) /* replace candidate */ + min = start; + continue; + } + + *nextvaddr = vaddr; + return TRUE; + } + } + + if (min != (ulong)-1) { + *nextvaddr = min; + return TRUE; + } + return FALSE; + +old_module: for (i = 0; i < st->mods_installed; i++) { lm = &st->load_modules[i]; start = lm->mod_base; diff --git a/symbols.c b/symbols.c index 7b1d59203b90..f161ee99e90a 100644 --- a/symbols.c +++ b/symbols.c @@ -48,8 +48,8 @@ static int load_module_index(struct syment *); static void section_header_info(bfd *, asection *, void *); static void store_section_data(struct load_module *, bfd *, asection *); static void calculate_load_order_v1(struct load_module *, bfd *); -static void calculate_load_order_v2(struct load_module *, bfd *, int, - void *, long, unsigned int); +static void calculate_load_order_v2(struct load_module *, bfd *, int, void *, long, unsigned int); +static void calculate_load_order_6_4(struct load_module *, bfd *, int, void *, long, unsigned int); static void check_insmod_builtin(struct load_module *, int, ulong *); static int is_insmod_builtin(struct load_module *, struct syment *); struct load_module; @@ -104,6 +104,42 @@ 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 module_mem_type(ulong, struct load_module *); +static ulong module_mem_end(ulong, struct load_module *); +static int in_module_range(ulong, struct load_module *, int, int); +static struct syment *value_search_module_6_4(ulong, ulong *); +static struct syment *next_symbol_by_symname(char *); +static struct syment *prev_symbol_by_symname(char *); +static struct syment *next_module_symbol_by_value(ulong); +static struct syment *prev_module_symbol_by_value(ulong); +static struct syment *next_module_symbol_by_syment(struct syment *); +static struct syment *prev_module_symbol_by_syment(struct syment *); + +struct module_tag { + char *start; + char *end; + char *start_str; + char *end_str; +}; + +#define MODULE_TAG(type, suffix) ("_MODULE_" #type "_" #suffix "_") +#define MODULE_STR(type, suffix) ( "MODULE " #type " " #suffix) +#define MODULE_TAGS(type) { \ + .start = MODULE_TAG(type, START), \ + .end = MODULE_TAG(type, END), \ + .start_str = MODULE_STR(type, START), \ + .end_str = MODULE_STR(type, END) \ +} + +static const struct module_tag module_tag[] = { + MODULE_TAGS(TEXT), + MODULE_TAGS(DATA), + MODULE_TAGS(RODATA), + MODULE_TAGS(RO_AFTER_INIT), + MODULE_TAGS(INIT_TEXT), + MODULE_TAGS(INIT_DATA), + MODULE_TAGS(INIT_RODATA), +}; /* * structure/union printing stuff @@ -1268,10 +1304,7 @@ symname_hash_search(struct syment *table[], char *name) * Output for sym -[lL] command. */ -#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_PSEUDO_SYMBOL(sp) (STRNEQ((sp)->name, "_MODULE_")) #define MODULE_START(sp) (STRNEQ((sp)->name, "_MODULE_START_")) #define MODULE_END(sp) (STRNEQ((sp)->name, "_MODULE_END_")) @@ -1280,6 +1313,76 @@ 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,t) (STRNEQ((sp)->name, module_tag[t].start)) +#define MODULE_MEM_END(sp,t) (STRNEQ((sp)->name, module_tag[t].end)) + +/* For 6.4 and later */ +static void +module_symbol_dump(char *module) +{ + int i, t; + struct syment *sp, *sp_end; + struct load_module *lm; + const char *p1, *p2; + + 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; + + /* + * module percpu symbols are within the .data..percpu section, + * not in any module memory regions. + */ + if (MODULE_PERCPU_SYMS_LOADED(lm)) { + p1 = "MODULE PERCPU START"; + p2 = lm->mod_name; + fprintf(fp, "%lx %s: %s\n", lm->mod_percpu, p1, p2); + + dump_percpu_symbols(lm); + + p1 = "MODULE PERCPU END"; + fprintf(fp, "%lx %s: %s\n", lm->mod_percpu + lm->mod_percpu_size, p1, p2); + } + + for_each_mod_mem_type(t) { + if (!lm->symtable[t]) + continue; + + sp = lm->symtable[t]; + sp_end = lm->symend[t]; + + for ( ; sp <= sp_end; sp++) { + if (MODULE_PSEUDO_SYMBOL(sp)) { + if (MODULE_MEM_START(sp, t)) { + p1 = module_tag[t].start_str; + p2 = sp->name + strlen(module_tag[t].start); + } else if (MODULE_MEM_END(sp, t)) { + p1 = module_tag[t].end_str; + p2 = sp->name + strlen(module_tag[t].end); + } else 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 { + p1 = "unknown tag"; + p2 = sp->name; + } + + fprintf(fp, "%lx %s: %s\n", sp->value, p1, p2); + } else + show_symbol(sp, 0, SHOW_RADIX()); + } + } + } +} + static void symbol_dump(ulong flags, char *module) { @@ -1302,6 +1405,11 @@ symbol_dump(ulong flags, char *module) if (!(flags & MODULE_SYMS)) return; + if (MODULE_MEMORY()) { + module_symbol_dump(module); + return; + } + for (i = 0; i < st->mods_installed; i++) { lm = &st->load_modules[i]; @@ -1389,8 +1497,14 @@ dump_percpu_symbols(struct load_module *lm) struct syment *sp, *sp_end; if (MODULE_PERCPU_SYMS_LOADED(lm)) { - sp = lm->mod_symtable; - sp_end = lm->mod_symend; + if (MODULE_MEMORY()) { + /* The lm should have mod_load_symtable. */ + sp = lm->mod_load_symtable; + sp_end = lm->mod_load_symend; + } else { + sp = lm->mod_symtable; + sp_end = lm->mod_symend; + } for ( ; sp <= sp_end; sp++) { if (IN_MODULE_PERCPU(sp->value, lm)) show_symbol(sp, 0, SHOW_RADIX()); @@ -1425,8 +1539,13 @@ check_for_dups(struct load_module *lm) { struct syment *sp, *sp_end; - sp = lm->mod_symtable; - sp_end = lm->mod_symend; + if (MODULE_MEMORY()) { + sp = lm->mod_load_symtable; + sp_end = lm->mod_load_symend; + } else { + sp = lm->mod_symtable; + sp_end = lm->mod_symend; + } for ( ; sp <= sp_end; sp++) { if (symbol_name_count(sp->name) > 1) @@ -1788,6 +1907,362 @@ modsym_value(ulong syms, union kernel_symbol *modsym, int i) return 0; } +/* + * Linux 6.4 introduced module.mem memory layout + */ +void +store_module_symbols_6_4(ulong total, int mods_installed) +{ + int i, m, t; + ulong mod, mod_next; + char *mod_name; + uint nsyms, ngplsyms; + ulong syms, gpl_syms; + ulong nksyms; + long strbuflen; + ulong size; + int mcnt, lm_mcnt; + union kernel_symbol *modsym; + size_t kernel_symbol_size; + struct load_module *lm; + char buf1[BUFSIZE]; + char buf2[BUFSIZE]; + char *strbuf = NULL, *modbuf, *modsymbuf; + struct syment *sp; + ulong first, last; + + st->mods_installed = mods_installed; + + if (!st->mods_installed) { + st->flags &= ~MODULE_SYMS; + return; + } + + /* + * If we've been here before, free up everything and start over. + */ + if (st->flags & MODULE_SYMS) + error(FATAL, "re-initialization of module symbols not implemented yet!\n"); + + kernel_symbol_size = kernel_symbol_type_init(); + + if ((st->ext_module_symtable = (struct syment *) + calloc(total, sizeof(struct syment))) == NULL) + error(FATAL, "module syment space malloc (%ld symbols): %s\n", + total, strerror(errno)); + + if (!namespace_ctl(NAMESPACE_INIT, &st->ext_module_namespace, + (void *)total, NULL)) + error(FATAL, "module namespace malloc: %s\n", strerror(errno)); + + if ((st->load_modules = (struct load_module *)calloc + (st->mods_installed, sizeof(struct load_module))) == NULL) + error(FATAL, "load_module array malloc: %s\n", strerror(errno)); + + modbuf = GETBUF(SIZE(module)); + modsymbuf = NULL; + m = mcnt = mod_next = 0; + + for (mod = kt->module_list; mod != kt->kernel_module; mod = mod_next) { + + readmem(mod, KVADDR, modbuf, SIZE(module), + "module buffer", FAULT_ON_ERROR); + + syms = ULONG(modbuf + OFFSET(module_syms)); + gpl_syms = ULONG(modbuf + OFFSET(module_gpl_syms)); + nsyms = UINT(modbuf + OFFSET(module_num_syms)); + ngplsyms = UINT(modbuf + OFFSET(module_num_gpl_syms)); + + nksyms = UINT(modbuf + OFFSET(module_num_symtab)); + + mod_name = modbuf + OFFSET(module_name); + + lm = &st->load_modules[m++]; + BZERO(lm, sizeof(struct load_module)); + + size = 0; + for_each_mod_mem_type(t) { + lm->mem[t].base = ULONG(modbuf + OFFSET(module_mem) + + SIZE(module_memory) * t + OFFSET(module_memory_base)); + lm->mem[t].size = UINT(modbuf + OFFSET(module_mem) + + SIZE(module_memory) * t + OFFSET(module_memory_size)); + if (t < MOD_INIT_TEXT) + size += lm->mem[t].size; + } + lm->mod_base = lm->mem[MOD_TEXT].base; + /* module core size, init not included */ + lm->mod_size = size; + lm->module_struct = mod; + + if (strlen(mod_name) < MAX_MOD_NAME) + strcpy(lm->mod_name, mod_name); + else { + error(INFO, "module name greater than MAX_MOD_NAME: %s\n", mod_name); + strncpy(lm->mod_name, mod_name, MAX_MOD_NAME-1); + } + if (CRASHDEBUG(3)) + fprintf(fp, "%lx (%lx): %s syms: %d gplsyms: %d ksyms: %ld\n", + mod, lm->mod_base, lm->mod_name, nsyms, ngplsyms, nksyms); + + lm->mod_flags = MOD_EXT_SYMS; + lm->mod_ext_symcnt = mcnt; + lm->mod_text_start = lm->mod_base; + lm->mod_init_module_ptr = lm->mem[MOD_INIT_TEXT].base; + lm->mod_init_size = lm->mem[MOD_INIT_TEXT].size; + lm->mod_init_text_size = lm->mem[MOD_INIT_TEXT].size; + + if (VALID_MEMBER(module_percpu)) + lm->mod_percpu = ULONG(modbuf + OFFSET(module_percpu)); + + lm_mcnt = mcnt; + for_each_mod_mem_type(t) { + if (!lm->mem[t].size) + continue; + + st->ext_module_symtable[mcnt].value = lm->mem[t].base; + st->ext_module_symtable[mcnt].type = 'm'; + st->ext_module_symtable[mcnt].flags |= MODULE_SYMBOL; + sprintf(buf2, "%s%s", module_tag[t].start, mod_name); + namespace_ctl(NAMESPACE_INSTALL, &st->ext_module_namespace, + &st->ext_module_symtable[mcnt], buf2); + lm_mcnt = mcnt; + mcnt++; + + if (t >= MOD_INIT_TEXT) + lm->mod_flags |= MOD_INIT; + } + + if (nsyms && !IN_MODULE(syms, lm)) { + error(WARNING, + "[%s] module.syms outside of module " "address space (%lx)\n\n", + lm->mod_name, syms); + nsyms = 0; + } + + if (nsyms) { + modsymbuf = GETBUF(kernel_symbol_size*nsyms); + readmem((ulong)syms, KVADDR, modsymbuf, + nsyms * kernel_symbol_size, + "module symbols", FAULT_ON_ERROR); + } + + for (i = first = last = 0; i < nsyms; i++) { + modsym = (union kernel_symbol *) + (modsymbuf + (i * kernel_symbol_size)); + if (!first + || first > modsym_name(syms, modsym, i)) + first = modsym_name(syms, modsym, i); + if (modsym_name(syms, modsym, i) > last) + last = modsym_name(syms, modsym, i); + } + + if (last > first) { + /* The buffer should not go over the block. */ + ulong end = module_mem_end(first, lm); + + strbuflen = (last-first) + BUFSIZE; + if ((first + strbuflen) >= end) { + strbuflen = end - first; + + } + strbuf = GETBUF(strbuflen); + + if (!readmem(first, KVADDR, strbuf, strbuflen, + "module symbol strings", RETURN_ON_ERROR)) { + FREEBUF(strbuf); + strbuf = NULL; + } + } + + + for (i = 0; i < nsyms; i++) { + modsym = (union kernel_symbol *)(modsymbuf + (i * kernel_symbol_size)); + + BZERO(buf1, BUFSIZE); + + if (strbuf) + strcpy(buf1, &strbuf[modsym_name(syms, modsym, i) - first]); + else + read_string(modsym_name(syms, modsym, i), buf1, BUFSIZE-1); + + if (strlen(buf1)) { + st->ext_module_symtable[mcnt].value = + modsym_value(syms, modsym, i); + st->ext_module_symtable[mcnt].type = '?'; + st->ext_module_symtable[mcnt].flags |= MODULE_SYMBOL; + strip_module_symbol_end(buf1); + strip_symbol_end(buf1, NULL); + namespace_ctl(NAMESPACE_INSTALL, + &st->ext_module_namespace, + &st->ext_module_symtable[mcnt], buf1); + + mcnt++; + } + } + + if (modsymbuf) { + FREEBUF(modsymbuf); + modsymbuf = NULL; + } + + if (strbuf) + FREEBUF(strbuf); + + if (ngplsyms) { + modsymbuf = GETBUF(kernel_symbol_size * ngplsyms); + readmem((ulong)gpl_syms, KVADDR, modsymbuf, + ngplsyms * kernel_symbol_size, + "module gpl symbols", FAULT_ON_ERROR); + } + + for (i = first = last = 0; i < ngplsyms; i++) { + modsym = (union kernel_symbol *) + (modsymbuf + (i * kernel_symbol_size)); + if (!first + || first > modsym_name(gpl_syms, modsym, i)) + first = modsym_name(gpl_syms, modsym, i); + if (modsym_name(gpl_syms, modsym, i) > last) + last = modsym_name(gpl_syms, modsym, i); + } + + if (last > first) { + ulong end = module_mem_end(first, lm); + + strbuflen = (last-first) + BUFSIZE; + if ((first + strbuflen) >= end) { + strbuflen = end - first; + + } + strbuf = GETBUF(strbuflen); + + if (!readmem(first, KVADDR, strbuf, strbuflen, + "module gpl symbol strings", RETURN_ON_ERROR)) { + FREEBUF(strbuf); + strbuf = NULL; + } + } else + strbuf = NULL; + + for (i = 0; i < ngplsyms; i++) { + modsym = (union kernel_symbol *) (modsymbuf + (i * kernel_symbol_size)); + + BZERO(buf1, BUFSIZE); + + if (strbuf) + strcpy(buf1, &strbuf[modsym_name(gpl_syms, modsym, i) - first]); + else + read_string(modsym_name(gpl_syms, modsym, i), buf1, BUFSIZE-1); + + if (strlen(buf1)) { + st->ext_module_symtable[mcnt].value = + modsym_value(gpl_syms, modsym, i); + st->ext_module_symtable[mcnt].type = '?'; + st->ext_module_symtable[mcnt].flags |= MODULE_SYMBOL; + strip_module_symbol_end(buf1); + strip_symbol_end(buf1, NULL); + namespace_ctl(NAMESPACE_INSTALL, + &st->ext_module_namespace, + &st->ext_module_symtable[mcnt], buf1); + + mcnt++; + } + } + + if (modsymbuf) { + FREEBUF(modsymbuf); + modsymbuf = NULL; + } + + if (strbuf) + FREEBUF(strbuf); + + /* + * If the module was compiled with kallsyms, add them in. + */ + switch (kt->flags & (KALLSYMS_V1|KALLSYMS_V2)) + { + case KALLSYMS_V1: /* impossible, I hope... */ + mcnt += store_module_kallsyms_v1(lm, lm_mcnt, mcnt, modbuf); + break; + case KALLSYMS_V2: + mcnt += store_module_kallsyms_v2(lm, lm_mcnt, mcnt, modbuf); + break; + } + + for_each_mod_mem_type(t) { + if (!lm->mem[t].size) + continue; + + st->ext_module_symtable[mcnt].value = lm->mem[t].base + lm->mem[t].size; + st->ext_module_symtable[mcnt].type = 'm'; + st->ext_module_symtable[mcnt].flags |= MODULE_SYMBOL; + sprintf(buf2, "%s%s", module_tag[t].end, mod_name); + namespace_ctl(NAMESPACE_INSTALL, + &st->ext_module_namespace, + &st->ext_module_symtable[mcnt], buf2); + mcnt++; + } + + lm->mod_ext_symcnt = mcnt - lm->mod_ext_symcnt; + + NEXT_MODULE(mod_next, modbuf); + } + + FREEBUF(modbuf); + + st->ext_module_symcnt = mcnt; + st->ext_module_symend = &st->ext_module_symtable[mcnt]; + + namespace_ctl(NAMESPACE_COMPLETE, &st->ext_module_namespace, + st->ext_module_symtable, st->ext_module_symend); + + qsort(st->ext_module_symtable, mcnt, sizeof(struct syment), + compare_syms); + + /* sort by text base address */ + qsort(st->load_modules, m, sizeof(struct load_module), compare_mods); + + for (m = 0; m < st->mods_installed; m++) { + lm = &st->load_modules[m]; + + for_each_mod_mem_type(t) { + if (!lm->mem[t].size) + continue; + + sprintf(buf1, "%s%s", module_tag[t].start, lm->mod_name); + sprintf(buf2, "%s%s", module_tag[t].end, lm->mod_name); + + for (sp = st->ext_module_symtable; sp < st->ext_module_symend; sp++) { + if (STREQ(sp->name, buf1)) { + lm->ext_symtable[t] = sp; + break; + } + } + for ( ; sp < st->ext_module_symend; sp++) { + if (STREQ(sp->name, buf2)) { + lm->ext_symend[t] = sp; + break; + } + } + + if (lm->ext_symtable[t] && lm->ext_symend[t]) + mod_symtable_hash_install_range(lm->ext_symtable[t], lm->ext_symend[t]); + } + lm->symtable = lm->ext_symtable; + lm->symend = lm->ext_symend; + } + + st->flags |= MODULE_SYMS; + + if (CRASHDEBUG(2)) { + for (sp = st->ext_module_symtable; sp < st->ext_module_symend; sp++) + fprintf(fp, "%16lx %s\n", sp->value, sp->name); + } + + if (mcnt > total) + error(FATAL, "store_module_symbols_6_4: total: %ld mcnt: %d\n", total, mcnt); +} + void store_module_symbols_v2(ulong total, int mods_installed) { @@ -2384,6 +2859,7 @@ store_module_kallsyms_v2(struct load_module *lm, int start, int curr, int mcnt; int mcnt_idx; char *module_buf_init = NULL; + ulong base, base_init, size, size_init; if (!(kt->flags & KALLSYMS_V2)) return 0; @@ -2394,9 +2870,22 @@ store_module_kallsyms_v2(struct load_module *lm, int start, int curr, ns = &st->ext_module_namespace; ec = &elf_common; - module_buf = GETBUF(lm->mod_size); + /* kallsyms data looks to be in MOD_DATA region. */ + if (MODULE_MEMORY()) { + base = lm->mem[MOD_DATA].base; + size = lm->mem[MOD_DATA].size; + base_init = lm->mem[MOD_INIT_DATA].base; + size_init = lm->mem[MOD_INIT_DATA].size; + } else { + base = lm->mod_base; + size = lm->mod_size; + base_init = lm->mod_init_module_ptr; + size_init = lm->mod_init_size; + } - if (!readmem(lm->mod_base, KVADDR, module_buf, lm->mod_size, + module_buf = GETBUF(size); + + if (!readmem(base, KVADDR, module_buf, size, "module (kallsyms)", RETURN_ON_ERROR|QUIET)) { error(WARNING,"cannot access module kallsyms\n"); FREEBUF(module_buf); @@ -2404,10 +2893,10 @@ store_module_kallsyms_v2(struct load_module *lm, int start, int curr, } if (lm->mod_init_size > 0) { - module_buf_init = GETBUF(lm->mod_init_size); + module_buf_init = GETBUF(size_init); - if (!readmem(lm->mod_init_module_ptr, KVADDR, module_buf_init, lm->mod_init_size, - "module init (kallsyms)", RETURN_ON_ERROR|QUIET)) { + if (!readmem(base_init, KVADDR, module_buf_init, size_init, + "module init (kallsyms)", RETURN_ON_ERROR|QUIET)) { error(WARNING,"cannot access module init kallsyms\n"); FREEBUF(module_buf_init); } @@ -2429,9 +2918,9 @@ store_module_kallsyms_v2(struct load_module *lm, int start, int curr, return 0; } if (IN_MODULE(ksymtab, lm)) - locsymtab = module_buf + (ksymtab - lm->mod_base); + locsymtab = module_buf + (ksymtab - base); else - locsymtab = module_buf_init + (ksymtab - lm->mod_init_module_ptr); + locsymtab = module_buf_init + (ksymtab - base_init); kstrtab = ULONG(modbuf + OFFSET(module_strtab)); if (!IN_MODULE(kstrtab, lm) && !IN_MODULE_INIT(kstrtab, lm)) { @@ -2444,9 +2933,9 @@ store_module_kallsyms_v2(struct load_module *lm, int start, int curr, return 0; } if (IN_MODULE(kstrtab, lm)) - locstrtab = module_buf + (kstrtab - lm->mod_base); + locstrtab = module_buf + (kstrtab - base); else - locstrtab = module_buf_init + (kstrtab - lm->mod_init_module_ptr); + locstrtab = module_buf_init + (kstrtab - base_init); for (i = 1; i < nksyms; i++) { /* ELF starts real symbols at 1 */ switch (BITS()) @@ -2461,11 +2950,8 @@ store_module_kallsyms_v2(struct load_module *lm, int start, int curr, break; } - if (((ec->st_value < lm->mod_base) || - (ec->st_value > (lm->mod_base + lm->mod_size))) && - ((ec->st_value < lm->mod_init_module_ptr) || - (ec->st_value > (lm->mod_init_module_ptr + lm->mod_init_size)))) - continue; + if (!IN_MODULE(ec->st_value, lm) && !IN_MODULE_INIT(ec->st_value, lm)) + continue; if (ec->st_shndx == SHN_UNDEF) continue; @@ -2572,7 +3058,7 @@ strip_module_symbol_end(char *buf) ulong lowest_module_address(void) { - int i; + int i, t; struct load_module *lm; ulong low, lowest; @@ -2582,9 +3068,20 @@ lowest_module_address(void) lowest = (ulong)(-1); for (i = 0; i < st->mods_installed; i++) { lm = &st->load_modules[i]; - low = lm->mod_base; - if (low < lowest) - lowest = low; + if (MODULE_MEMORY()) + for_each_mod_mem_type(t) { + if (!lm->mem[t].size) + continue; + + low = lm->mem[t].base; + if (low < lowest) + lowest = low; + } + else { + low = lm->mod_base; + if (low < lowest) + lowest = low; + } } return lowest; @@ -2593,16 +3090,27 @@ lowest_module_address(void) ulong highest_module_address(void) { - int i; + int i, t; struct load_module *lm; ulong high, highest; highest = 0; for (i = 0; i < st->mods_installed; i++) { lm = &st->load_modules[i]; - high = lm->mod_base + lm->mod_size; - if (high > highest) - highest = high; + if (MODULE_MEMORY()) { + for_each_mod_mem_type(t) { + if (!lm->mem[t].size) + continue; + + high = lm->mem[t].base + lm->mem[t].size; + if (high > highest) + highest = high; + } + } else { + high = lm->mod_base + lm->mod_size; + if (high > highest) + highest = high; + } } return highest; @@ -2853,7 +3361,8 @@ compare_syms(const void *v1, const void *v2) return -1; if (STRNEQ(s2->name, "__insmod")) return 1; - if (STRNEQ(s2->name, "_MODULE_START_")) + if (MODULE_MEM_START(s2, MOD_TEXT) || + STRNEQ(s2->name, "_MODULE_START_")) return 1; /* Get pseudo section name. */ if (MODULE_SECTION_START(s1)) @@ -2986,13 +3495,19 @@ is_kernel_text(ulong value) if (!(lm->mod_section_data[s].flags & SEC_CODE)) continue; - start = lm->mod_base + - lm->mod_section_data[s].offset; + if (MODULE_MEMORY()) + start = lm->mod_section_data[s].addr; + else + start = lm->mod_base + lm->mod_section_data[s].offset; + end = start + lm->mod_section_data[s].size; if ((value >= start) && (value < end)) return TRUE; } + } else if (MODULE_MEMORY()) { + if (IN_MODULE_TEXT(value, lm)) + return TRUE; } else { switch (kt->flags & (KMOD_V1|KMOD_V2)) { @@ -3531,22 +4046,42 @@ dump_symbol_table(void) (ulong)lm->mod_section_data, lm->mod_section_data ? "" : "(not allocated)"); + if (MODULE_MEMORY()) { + int t; + for_each_mod_mem_type(t) { + fprintf(fp, " mem[%d]: %lx (%x)\n", + t, lm->mem[t].base, lm->mem[t].size); + } + fprintf(fp, " symtable: %lx\n", (ulong)lm->symtable); + fprintf(fp, " ext_symtable: %lx\n", (ulong)lm->ext_symtable); + for_each_mod_mem_type(t) { + fprintf(fp, " ext_symtable[%d]: %lx - %lx\n", + t, (ulong)lm->ext_symtable[t], (ulong)lm->ext_symend[t]); + } + fprintf(fp, " load_symtable: %lx\n", (ulong)lm->load_symtable); + for_each_mod_mem_type(t) { + fprintf(fp, " load_symtable[%d]: %lx - %lx\n", + t, (ulong)lm->load_symtable[t], (ulong)lm->load_symend[t]); + } + } for (s = 0; s < lm->mod_sections; s++) { fprintf(fp, - " %12s prio: %x flags: %05x offset: %-8lx size: %lx\n", + " %20s prio: %x flags: %08x %s: %-16lx size: %lx\n", lm->mod_section_data[s].name, lm->mod_section_data[s].priority, lm->mod_section_data[s].flags, - lm->mod_section_data[s].offset, + MODULE_MEMORY() ? "addr" : "offset", + MODULE_MEMORY() ? lm->mod_section_data[s].addr : + lm->mod_section_data[s].offset, lm->mod_section_data[s].size); } fprintf(fp, " loaded_objfile: %lx\n", (ulong)lm->loaded_objfile); - if (CRASHDEBUG(1)) { + if (CRASHDEBUG(1) && lm->mod_load_symtable) { for (sp = lm->mod_load_symtable; - sp < lm->mod_load_symend; sp++) { + sp <= lm->mod_load_symend; sp++) { fprintf(fp, " %lx %s\n", sp->value, sp->name); } @@ -4458,8 +4993,11 @@ get_section(ulong vaddr, char *buf) if (module_symbol(vaddr, NULL, &lm, NULL, *gdb_output_radix)) { if (lm->mod_flags & MOD_LOAD_SYMS) { for (i = (lm->mod_sections-1); i >= 0; i--) { - start = lm->mod_base + - lm->mod_section_data[i].offset; + if (MODULE_MEMORY()) + start = lm->mod_section_data[i].addr; + else + start = lm->mod_base + + lm->mod_section_data[i].offset; end = start + lm->mod_section_data[i].size; if ((vaddr >= start) && (vaddr < end)) { @@ -4514,7 +5052,7 @@ get_build_directory(char *buf) int symbol_query(char *s, char *print_pad, struct syment **spp) { - int i; + int i, t; struct syment *sp, *sp_end; struct load_module *lm; int cnt, search_init; @@ -4534,6 +5072,60 @@ symbol_query(char *s, char *print_pad, struct syment **spp) } } + if (!MODULE_MEMORY()) + goto old_module; + + for (i = 0; i < st->mods_installed; i++) { + lm = &st->load_modules[i]; + + if (lm->mod_flags & MOD_LOAD_SYMS) { + sp = lm->mod_load_symtable; + sp_end = lm->mod_load_symend; + + for (; sp < sp_end; sp++) { + if (MODULE_PSEUDO_SYMBOL(sp)) + continue; + + if (strstr(sp->name, s)) { + if (print_pad) { + if (strlen(print_pad)) + fprintf(fp, "%s", print_pad); + show_symbol(sp, 0, SHOW_RADIX()|SHOW_MODULE); + } + if (spp) + *spp = sp; + cnt++; + } + } + } else { + for_each_mod_mem_type(t) { + if (!lm->symtable[t]) + continue; + + sp = lm->symtable[t]; + sp_end = lm->symend[t]; + + for (; sp < sp_end; sp++) { + if (MODULE_PSEUDO_SYMBOL(sp)) + continue; + + if (strstr(sp->name, s)) { + if (print_pad) { + if (strlen(print_pad)) + fprintf(fp, "%s", print_pad); + show_symbol(sp, 0, SHOW_RADIX()|SHOW_MODULE); + } + if (spp) + *spp = sp; + cnt++; + } + } + } + } + } + return cnt; + +old_module: search_init = FALSE; for (i = 0; i < st->mods_installed; i++) { @@ -4639,7 +5231,7 @@ symbol_search(char *s) int symbol_name_count(char *s) { - int i; + int i, t; struct syment *sp, *sp_end; struct load_module *lm; int count, pseudos, search_init; @@ -4653,6 +5245,37 @@ symbol_name_count(char *s) } } + if (!MODULE_MEMORY()) + goto old_module; + + for (i = 0; i < st->mods_installed; i++) { + lm = &st->load_modules[i]; + + if (lm->mod_flags & MOD_LOAD_SYMS) { + sp = lm->mod_load_symtable; + sp_end = lm->mod_load_symend; + + for (; sp < sp_end; sp++) { + if (STREQ(s, sp->name)) + count++; + } + } else { + for_each_mod_mem_type(t) { + if (!lm->symtable[t]) + continue; + + sp = lm->symtable[t]; + sp_end = lm->symend[t]; + for (; sp < sp_end; sp++) { + if (STREQ(s, sp->name)) + count++; + } + } + } + } + return count++; + +old_module: pseudos = (strstr(s, "_MODULE_START_") || strstr(s, "_MODULE_END_")); search_init = FALSE; @@ -4702,7 +5325,7 @@ symbol_name_count(char *s) struct syment * symbol_search_next(char *s, struct syment *spstart) { - int i; + int i, t; struct syment *sp, *sp_end; struct load_module *lm; int found_start; @@ -4722,6 +5345,38 @@ symbol_search_next(char *s, struct syment *spstart) } } + if (!MODULE_MEMORY()) + goto old_module; + + for (i = 0; i < st->mods_installed; i++) { + lm = &st->load_modules[i]; + + for_each_mod_mem_type(t) { + if (!lm->symtable[t]) + continue; + + sp = lm->symtable[t]; + sp_end = lm->symend[t]; + + if (!found_start && (spstart < sp || spstart > sp_end)) + continue; + + for ( ; sp < sp_end; sp++) { + if (sp == spstart) { + found_start = TRUE; + continue; + } else if (!found_start) + continue; + + if (STREQ(s, sp->name)) + return sp; + } + } + } + + return NULL; + +old_module: pseudos = (strstr(s, "_MODULE_START_") || strstr(s, "_MODULE_END_")); search_init = FALSE; @@ -4831,17 +5486,29 @@ module_symbol(ulong value, for (i = 0; i < st->mods_installed; i++) { lm = &st->load_modules[i]; - if (IN_MODULE(value, lm)) { - base = lm->mod_base; - end = lm->mod_base + lm->mod_size; - } else if (IN_MODULE_INIT(value, lm)) { - base = lm->mod_init_module_ptr; - end = lm->mod_init_module_ptr + lm->mod_init_size; - } else if (IN_MODULE_PERCPU(value, lm)) { - base = lm->mod_percpu; - end = lm->mod_percpu + lm->mod_percpu_size; - } else - continue; + if (MODULE_MEMORY()) { + if (IN_MODULE(value, lm) || IN_MODULE_INIT(value, lm)) { + int type = module_mem_type(value, lm); + base = lm->mem[type].base; + end = base + lm->mem[type].size; + } else if (IN_MODULE_PERCPU(value, lm)) { + base = lm->mod_percpu; + end = lm->mod_percpu + lm->mod_percpu_size; + } else + continue; + } else { + if (IN_MODULE(value, lm)) { + base = lm->mod_base; + end = lm->mod_base + lm->mod_size; + } else if (IN_MODULE_INIT(value, lm)) { + base = lm->mod_init_module_ptr; + end = lm->mod_init_module_ptr + lm->mod_init_size; + } else if (IN_MODULE_PERCPU(value, lm)) { + base = lm->mod_percpu; + end = lm->mod_percpu + lm->mod_percpu_size; + } else + continue; + } if ((value >= base) && (value < end)) { if (lmp) @@ -4877,6 +5544,71 @@ module_symbol(ulong value, return FALSE; } +static struct syment * +value_search_module_6_4(ulong value, ulong *offset) +{ + int i, t; + 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_each_mod_mem_type(t) { + sp = lm->symtable[t]; + sp_end = lm->symend[t]; + + if (value < sp->value) + continue; + + splast = NULL; + for ( ; sp <= sp_end; sp++) { + 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, t)) + break; + + if (MODULE_PSEUDO_SYMBOL(sp)) { + spnext = sp + 1; + if (MODULE_PSEUDO_SYMBOL(spnext)) + continue; + if (spnext->value == 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)) { + splast = sp; + } + } + } + } + + return NULL; +} + struct syment * value_search_module(ulong value, ulong *offset) { @@ -4885,6 +5617,9 @@ value_search_module(ulong value, ulong *offset) struct load_module *lm; int search_init_sections, search_init; + if (MODULE_MEMORY()) + return value_search_module_6_4(value, offset); + search_init = FALSE; search_init_sections = 0; @@ -5203,6 +5938,99 @@ closest_symbol_value(ulong value) return(0); } +/* Only for 6.4 and later */ +static struct syment * +next_symbol_by_symname(char *symbol) +{ + struct syment *sp; + + if ((sp = symbol_search(symbol))) { + sp++; + if (MODULE_PSEUDO_SYMBOL(sp) && strstr(sp->name, "_END")) + return next_module_symbol_by_value(sp->value); + + return sp; + } + + return NULL; +} + +/* val_in should be a pseudo module end symbol. */ +static struct syment * +next_module_symbol_by_value(ulong val_in) +{ + struct load_module *lm; + struct syment *sp, *sp_end; + ulong start, min; + int i, t; + +retry: + sp = sp_end = NULL; + min = (ulong)-1; + for (i = 0; i < st->mods_installed; i++) { + lm = &st->load_modules[i]; + + /* Search for the next lowest symtable. */ + for_each_mod_mem_type(t) { + if (!lm->symtable[t]) + continue; + + start = lm->symtable[t]->value; + if (start > val_in && start < min) { + min = start; + sp = lm->symtable[t]; + sp_end = lm->symend[t]; + } + } + } + + if (!sp) + return NULL; + + for ( ; sp < sp_end; sp++) { + if (MODULE_PSEUDO_SYMBOL(sp)) + continue; + if (sp->value > val_in) + return sp; + } + + /* Found a table that has only pseudo symbols. */ + val_in = sp_end->value; + goto retry; +} + +/* Only for 6.4 and later */ +static struct syment * +next_module_symbol_by_syment(struct syment *sp_in) +{ + struct load_module *lm; + struct syment *sp; + int i, t; + + for (i = 0; i < st->mods_installed; i++) { + lm = &st->load_modules[i]; + + for_each_mod_mem_type(t) { + if (!lm->symtable[t]) + continue; + + if (sp_in < lm->symtable[t] || sp_in > lm->symend[t]) + continue; + + if (sp_in == lm->symend[t]) + return next_module_symbol_by_value(sp_in->value); + + sp = sp_in + 1; + if (MODULE_PSEUDO_SYMBOL(sp)) + return next_module_symbol_by_value(sp->value); + + return sp; + } + } + + return NULL; +} + /* * For a given symbol, return a pointer to the next (higher) symbol's syment. * Either a symbol name or syment pointer may be passed as an argument. @@ -5230,6 +6058,9 @@ next_symbol(char *symbol, struct syment *sp_in) } } + if (MODULE_MEMORY()) + return next_module_symbol_by_syment(sp_in); + search_init = FALSE; for (i = 0; i < st->mods_installed; i++) { @@ -5270,46 +6101,148 @@ next_symbol(char *symbol, struct syment *sp_in) } } - return NULL; + return NULL; + } + + if (MODULE_MEMORY()) + return next_symbol_by_symname(symbol); + + /* + * Deal with a few special cases... + */ + if (strstr(symbol, " module)")) { + sprintf(buf, "_MODULE_START_"); + strcat(buf, &symbol[1]); + p1 = strstr(buf, " module)"); + *p1 = NULLCHAR; + symbol = buf; + } + + if (STREQ(symbol, "_end")) { + if (!st->mods_installed) + return NULL; + + lm = &st->load_modules[0]; + + return lm->mod_symtable; + } + + if ((sp = symbol_search(symbol))) { + sp++; + if (MODULE_END(sp)) { + sp--; + i = load_module_index(sp); + if ((i+1) == st->mods_installed) + return NULL; + + lm = &st->load_modules[i+1]; + + sp = lm->mod_symtable; + } + return sp; + } + + return NULL; +} + +/* Only for 6.4 and later */ +static struct syment * +prev_symbol_by_symname(char *symbol) +{ + struct syment *sp; + + if ((sp = symbol_search(symbol))) { + if (sp == st->symtable) + return NULL; + + if (module_symbol(sp->value, NULL, NULL, NULL, 0)) { + if (MODULE_PSEUDO_SYMBOL(sp) && strstr(sp->name, "_START")) + return prev_module_symbol_by_value(sp->value); + else + sp--; + } else + sp--; + + return sp; + } + + return NULL; +} + +/* val_in should be a pseudo module start symbol. */ +static struct syment * +prev_module_symbol_by_value(ulong val_in) +{ + struct load_module *lm; + struct syment *sp, *sp_end; + ulong end, max; + int i, t; + +retry: + sp = sp_end = NULL; + max = 0; + for (i = 0; i < st->mods_installed; i++) { + lm = &st->load_modules[i]; + + /* Search for the previous highest table. */ + for_each_mod_mem_type(t) { + if (!lm->symtable[t]) + continue; + + end = lm->symend[t]->value; + if (end < val_in && end > max) { + max = end; + sp = lm->symtable[t]; + sp_end = lm->symend[t]; + } + } } + if (!sp) + return NULL; - /* - * Deal with a few special cases... - */ - if (strstr(symbol, " module)")) { - sprintf(buf, "_MODULE_START_"); - strcat(buf, &symbol[1]); - p1 = strstr(buf, " module)"); - *p1 = NULLCHAR; - symbol = buf; + for ( ; sp_end > sp; sp_end--) { + if (MODULE_PSEUDO_SYMBOL(sp_end)) + continue; + if (sp_end->value < val_in) + return sp_end; } - if (STREQ(symbol, "_end")) { - if (!st->mods_installed) - return NULL; + /* Found a table that has only pseudo symbols. */ + val_in = sp->value; + goto retry; +} - lm = &st->load_modules[0]; +/* Only for 6.4 and later */ +static struct syment * +prev_module_symbol_by_syment(struct syment *sp_in) +{ + struct load_module *lm; + struct syment *sp; + int i, t; - return lm->mod_symtable; - } + for (i = 0; i < st->mods_installed; i++) { + lm = &st->load_modules[i]; - if ((sp = symbol_search(symbol))) { - sp++; - if (MODULE_END(sp)) { - sp--; - i = load_module_index(sp); - if ((i+1) == st->mods_installed) - return NULL; + for_each_mod_mem_type(t) { + if (!lm->symtable[t]) + continue; - lm = &st->load_modules[i+1]; + if (sp_in < lm->symtable[t] || sp_in > lm->symend[t]) + continue; - sp = lm->mod_symtable; + if (sp_in == lm->symtable[t]) + return prev_module_symbol_by_value(sp_in->value); + + sp = sp_in - 1; + if (MODULE_PSEUDO_SYMBOL(sp)) + return prev_module_symbol_by_value(sp->value); + + return sp; } - return sp; } - return NULL; + return NULL; } /* @@ -5335,6 +6268,9 @@ prev_symbol(char *symbol, struct syment *sp_in) sp_prev = sp; } + if (MODULE_MEMORY()) + return prev_module_symbol_by_syment(sp_in); + search_init = FALSE; for (i = 0; i < st->mods_installed; i++) { @@ -5378,6 +6314,9 @@ prev_symbol(char *symbol, struct syment *sp_in) return NULL; } + if (MODULE_MEMORY()) + return prev_symbol_by_symname(symbol); + if (strstr(symbol, " module)")) { sprintf(buf, "_MODULE_START_"); strcat(buf, &symbol[1]); @@ -5600,7 +6539,7 @@ kernel_symbol_search(char *symbol) int get_syment_array(char *symbol, struct syment **sp_array, int max) { - int i, cnt; + int i, cnt, t; struct syment *sp, *sp_end; struct load_module *lm; @@ -5625,6 +6564,31 @@ get_syment_array(char *symbol, struct syment **sp_array, int max) } } + if (!MODULE_MEMORY()) + goto old_module; + + for (i = 0; i < st->mods_installed; i++) { + lm = &st->load_modules[i]; + + for_each_mod_mem_type(t) { + if (!lm->symtable[t]) + continue; + + sp = lm->symtable[t]; + sp_end = lm->symend[t]; + for (; sp < sp_end; sp++) { + if (STREQ(symbol, sp->name)) { + if (max && (cnt < max)) + sp_array[cnt] = sp; + cnt++; + } + } + } + } + + return cnt; + +old_module: for (i = 0; i < st->mods_installed; i++) { lm = &st->load_modules[i]; sp = lm->mod_symtable; @@ -9229,6 +10193,9 @@ dump_offset_table(char *spec, ulong makestruct) OFFSET(module_strtab)); fprintf(fp, " module_percpu: %ld\n", OFFSET(module_percpu)); + fprintf(fp, " module_mem: %ld\n", OFFSET(module_mem)); + fprintf(fp, " module_memory_base: %ld\n", OFFSET(module_memory_base)); + fprintf(fp, " module_memory_size: %ld\n", OFFSET(module_memory_size)); fprintf(fp, " module_sect_attrs: %ld\n", OFFSET(module_sect_attrs)); @@ -10852,6 +11819,7 @@ dump_offset_table(char *spec, ulong makestruct) SIZE(super_block)); fprintf(fp, " irqdesc: %ld\n", SIZE(irqdesc)); fprintf(fp, " module: %ld\n", SIZE(module)); + fprintf(fp, " module_memory: %ld\n", SIZE(module_memory)); fprintf(fp, " module_sect_attr: %ld\n", SIZE(module_sect_attr)); fprintf(fp, " list_head: %ld\n", SIZE(list_head)); fprintf(fp, " hlist_head: %ld\n", SIZE(hlist_head)); @@ -11467,6 +12435,13 @@ store_section_data(struct load_module *lm, bfd *bfd, asection *section) lm->mod_section_data[i].section = section; lm->mod_section_data[i].priority = prio; lm->mod_section_data[i].flags = section->flags & ~SEC_FOUND; + lm->mod_section_data[i].size = bfd_section_size(section); + lm->mod_section_data[i].offset = 0; + lm->mod_section_data[i].addr = 0; + if (strlen(name) < MAX_MOD_SEC_NAME) + strcpy(lm->mod_section_data[i].name, name); + else + strncpy(lm->mod_section_data[i].name, name, MAX_MOD_SEC_NAME-1); /* * The percpu section isn't included in kallsyms or module_core area. */ @@ -11474,13 +12449,8 @@ store_section_data(struct load_module *lm, bfd *bfd, asection *section) (STREQ(name,".data.percpu") || STREQ(name, ".data..percpu"))) { lm->mod_percpu_size = bfd_section_size(section); lm->mod_section_data[i].flags |= SEC_FOUND; + lm->mod_section_data[i].addr = lm->mod_percpu; } - lm->mod_section_data[i].size = bfd_section_size(section); - lm->mod_section_data[i].offset = 0; - if (strlen(name) < MAX_MOD_SEC_NAME) - strcpy(lm->mod_section_data[i].name, name); - else - strncpy(lm->mod_section_data[i].name, name, MAX_MOD_SEC_NAME-1); lm->mod_sections += 1; } @@ -11722,6 +12692,124 @@ calculate_load_order_v2(struct load_module *lm, bfd *bfd, int dynamic, } } +/* Linux 6.4 and later */ +static void +calculate_load_order_6_4(struct load_module *lm, bfd *bfd, int dynamic, + void *minisyms, long symcount, unsigned int size) +{ + struct syment *s1, *s2; + ulong sec_start; + bfd_byte *from, *fromend; + asymbol *store; + asymbol *sym; + symbol_info syminfo; + char *secname; + int i, t; + + if ((store = bfd_make_empty_symbol(bfd)) == NULL) + error(FATAL, "bfd_make_empty_symbol() failed\n"); + + for_each_mod_mem_type(t) { + s1 = lm->symtable[t]; + s2 = lm->symend[t]; + while (s1 < s2) { + + if (MODULE_PSEUDO_SYMBOL(s1)) { + s1++; + continue; + } + + /* Skip over symbols whose sections have been identified. */ + for (i = 0; i < lm->mod_sections; i++) { + if ((lm->mod_section_data[i].flags & SEC_FOUND) == 0) + continue; + + if (s1->value >= lm->mod_section_data[i].addr && + s1->value < lm->mod_section_data[i].addr + + lm->mod_section_data[i].size) + break; + } + + /* Matched one of the sections. Skip symbol. */ + if (i < lm->mod_sections) { + if (CRASHDEBUG(2)) + fprintf(fp, "skip %lx %s %s\n", s1->value, s1->name, + lm->mod_section_data[i].name); + s1++; + continue; + } + + /* Find the symbol in the object file. */ + from = (bfd_byte *) minisyms; + fromend = from + symcount * size; + secname = NULL; + for (; from < fromend; from += size) { + if (!(sym = bfd_minisymbol_to_symbol(bfd, dynamic, from, store))) + error(FATAL, "bfd_minisymbol_to_symbol() failed\n"); + + bfd_get_symbol_info(bfd, sym, &syminfo); + if (CRASHDEBUG(3)) { + fprintf(fp,"matching sym %s %lx against bfd %s %lx\n", + s1->name, (long) s1->value, syminfo.name, + (long) syminfo.value); + } + if (strcmp(syminfo.name, s1->name) == 0) { + secname = (char *)bfd_section_name(sym->section); + break; + } + + } + if (secname == NULL) { + if (CRASHDEBUG(1)) + fprintf(fp, "symbol %s not found in module\n", s1->name); + s1++; + continue; + } + + /* Match the section it came in. */ + for (i = 0; i < lm->mod_sections; i++) { + if (STREQ(lm->mod_section_data[i].name, secname)) + break; + } + + if (i == lm->mod_sections) { + fprintf(fp, "?? Section %s not found for symbol %s\n", + secname, s1->name); + s1++; + continue; + } + + if (lm->mod_section_data[i].flags & SEC_FOUND) { + s1++; + continue; + } + + /* Update the offset information for the section */ + sec_start = s1->value - syminfo.value; + /* keep the address instead of offset */ + lm->mod_section_data[i].addr = sec_start; + lm->mod_section_data[i].flags |= SEC_FOUND; + + if (CRASHDEBUG(2)) + fprintf(fp, "update sec offset sym %s @ %lx val %lx section %s\n", + s1->name, s1->value, (ulong)syminfo.value, secname); + + if (strcmp(secname, ".text") == 0) + lm->mod_text_start = sec_start; + + if (strcmp(secname, ".bss") == 0) + lm->mod_bss_start = sec_start; + + if (strcmp(secname, ".data") == 0) + lm->mod_data_start = sec_start; + + if (strcmp(secname, ".rodata") == 0) + lm->mod_rodata_start = sec_start; + s1++; + } + } +} + /* * Later versons of insmod store basic address information of each * module in a format that looks like the following example of the @@ -11927,8 +13015,11 @@ add_symbol_file(struct load_module *lm) (!STREQ(secname, ".text") && !STREQ(secname, ".data.percpu") && !STREQ(secname, ".data..percpu"))) { - sprintf(buf, " -s %s 0x%lx", secname, - lm->mod_section_data[i].offset + lm->mod_base); + if (MODULE_MEMORY()) + sprintf(buf, " -s %s 0x%lx", secname, lm->mod_section_data[i].addr); + else + sprintf(buf, " -s %s 0x%lx", secname, + lm->mod_section_data[i].offset + lm->mod_base); len += strlen(buf); } } @@ -12269,24 +13360,43 @@ static struct syment * kallsyms_module_symbol(struct load_module *lm, symbol_info *syminfo) { struct syment *sp, *spx; - int cnt; + int cnt, t; if (!(lm->mod_flags & MOD_KALLSYMS)) return NULL; sp = NULL; cnt = 0; - for (spx = lm->mod_ext_symtable; spx <= lm->mod_ext_symend; spx++) { - if (!STREQ(spx->name, syminfo->name)) - continue; - if (spx->cnt) { - cnt++; - continue; - } + if (MODULE_MEMORY()) { + for_each_mod_mem_type(t) { + if (!lm->ext_symtable[t]) + continue; + for (spx = lm->ext_symtable[t]; spx <= lm->ext_symend[t]; spx++) { + if (!STREQ(spx->name, syminfo->name)) + continue; + if (spx->cnt) { + cnt++; + continue; + } - spx->cnt++; - sp = spx; - break; + spx->cnt++; + sp = spx; + break; + } + } + } else { + for (spx = lm->mod_ext_symtable; spx <= lm->mod_ext_symend; spx++) { + if (!STREQ(spx->name, syminfo->name)) + continue; + if (spx->cnt) { + cnt++; + continue; + } + + spx->cnt++; + sp = spx; + break; + } } if (CRASHDEBUG(2)) { @@ -12312,7 +13422,7 @@ static void store_load_module_symbols(bfd *bfd, int dynamic, void *minisyms, long symcount, unsigned int size, ulong base_addr, char *namelist) { - int i; + int i, t; asymbol *store; asymbol *sym; bfd_byte *from, *fromend; @@ -12323,7 +13433,7 @@ store_load_module_symbols(bfd *bfd, int dynamic, void *minisyms, char *nameptr, *secname; long index; long symalloc; - int found; + int found = FALSE; if ((store = bfd_make_empty_symbol(bfd)) == NULL) error(FATAL, "bfd_make_empty_symbol() failed\n"); @@ -12380,8 +13490,17 @@ store_load_module_symbols(bfd *bfd, int dynamic, void *minisyms, lm->mod_rodata_start = lm->mod_bss_start = 0; lm->mod_load_symcnt = 0; lm->mod_sections = 0; - for (spx = lm->mod_ext_symtable; spx <= lm->mod_ext_symend; spx++) - spx->cnt = 0; + if (MODULE_MEMORY()) { + for_each_mod_mem_type(t) { + if (!lm->ext_symtable[t]) + continue; + for (spx = lm->ext_symtable[t]; spx <= lm->ext_symend[t]; spx++) + spx->cnt = 0; + } + } else { + for (spx = lm->mod_ext_symtable; spx <= lm->mod_ext_symend; spx++) + spx->cnt = 0; + } sp = lm->mod_load_symtable; if (!(lm->mod_section_data = (struct mod_section_data *) @@ -12392,13 +13511,14 @@ store_load_module_symbols(bfd *bfd, int dynamic, void *minisyms, bfd_map_over_sections(bfd, section_header_info, MODULE_SECTIONS); - if (kt->flags & KMOD_V1) + if (MODULE_MEMORY()) + calculate_load_order_6_4(lm, bfd, dynamic, minisyms, symcount, size); + else if (kt->flags & KMOD_V1) calculate_load_order_v1(lm, bfd); else calculate_load_order_v2(lm, bfd, dynamic, minisyms, symcount, size); - from = (bfd_byte *) minisyms; fromend = from + symcount * size; for (; from < fromend; from += size) @@ -12501,7 +13621,10 @@ store_load_module_symbols(bfd *bfd, int dynamic, void *minisyms, syminfo.value += lm->mod_percpu; found = TRUE; } else { - syminfo.value += lm->mod_section_data[i].offset + lm->mod_base; + if (MODULE_MEMORY()) + syminfo.value += lm->mod_section_data[i].addr; + else + syminfo.value += lm->mod_section_data[i].offset + lm->mod_base; found = TRUE; } } @@ -12536,6 +13659,53 @@ store_load_module_symbols(bfd *bfd, int dynamic, void *minisyms, * syminfo data types accepted above, plus the two pseudo symbols. * Note that the new syment name pointers haven't been resolved yet. */ + if (!MODULE_MEMORY()) + goto old_module; + + for_each_mod_mem_type(t) { + if (!lm->ext_symtable[t]) + continue; + for (spx = lm->ext_symtable[t]; spx <= lm->ext_symend[t]; spx++) { + found = FALSE; + for (sp = lm->mod_load_symtable; sp < lm->mod_load_symend; sp++) { + index = (long)sp->name; + nameptr = &lm->mod_load_namespace.address[index]; + if (STREQ(spx->name, nameptr)) { + found = TRUE; + if (spx->value == sp->value) { + if (CRASHDEBUG(2)) + fprintf(fp, "%s: %s matches!\n", + lm->mod_name, nameptr); + } else { + if (CRASHDEBUG(2)) + fprintf(fp, + "[%s] %s: %lx != extern'd value: %lx\n", + lm->mod_name, + nameptr, sp->value, + spx->value); + } + break; + } + } + if (!found) { + if (CRASHDEBUG(2)) + fprintf(fp, "append ext %s (%lx)\n", spx->name, spx->value); + /* append it here... */ + namespace_ctl(NAMESPACE_INSTALL, + &lm->mod_load_namespace, + lm->mod_load_symend, spx->name); + + lm->mod_load_symend->value = spx->value; + lm->mod_load_symend->type = spx->type; + lm->mod_load_symend->flags |= MODULE_SYMBOL; + lm->mod_load_symend++; + lm->mod_load_symcnt++; + } + } + } + goto append_section_symbols; + +old_module: for (spx = lm->mod_ext_symtable; spx <= lm->mod_ext_symend; spx++) { found = FALSE; for (sp = lm->mod_load_symtable; @@ -12578,6 +13748,7 @@ store_load_module_symbols(bfd *bfd, int dynamic, void *minisyms, } } +append_section_symbols: /* * Append helpful pseudo symbols about found out sections. * Use 'S' as its type which is never seen in existing symbols. @@ -12587,8 +13758,11 @@ store_load_module_symbols(bfd *bfd, int dynamic, void *minisyms, if (!(lm->mod_section_data[i].flags & SEC_FOUND)) continue; /* Section start */ - lm->mod_load_symend->value = lm->mod_base + - lm->mod_section_data[i].offset; + if (MODULE_MEMORY()) + lm->mod_load_symend->value = lm->mod_section_data[i].addr; + else + lm->mod_load_symend->value = lm->mod_base + + lm->mod_section_data[i].offset; lm->mod_load_symend->type = 'S'; lm->mod_load_symend->flags |= MODULE_SYMBOL; sprintf(name, "_MODULE_SECTION_START [%s]", @@ -12599,9 +13773,12 @@ store_load_module_symbols(bfd *bfd, int dynamic, void *minisyms, lm->mod_load_symcnt++; /* Section end */ - lm->mod_load_symend->value = lm->mod_base + - lm->mod_section_data[i].offset + - lm->mod_section_data[i].size; + if (MODULE_MEMORY()) + lm->mod_load_symend->value = lm->mod_section_data[i].addr; + else + lm->mod_load_symend->value = lm->mod_base + + lm->mod_section_data[i].offset; + lm->mod_load_symend->value += lm->mod_section_data[i].size; lm->mod_load_symend->type = 'S'; lm->mod_load_symend->flags |= MODULE_SYMBOL; sprintf(name, "_MODULE_SECTION_END [%s]", @@ -12618,16 +13795,57 @@ store_load_module_symbols(bfd *bfd, int dynamic, void *minisyms, qsort(lm->mod_load_symtable, lm->mod_load_symcnt, sizeof(struct syment), compare_syms); + if (MODULE_MEMORY()) { + /* keep load symtable addresses to lm->load_symtable[] */ + /* TODO: make more efficient */ + for (sp = lm->mod_load_symtable; sp < lm->mod_load_symend; sp++) { + char buf1[BUFSIZE], buf2[BUFSIZE]; + + if (CRASHDEBUG(2)) + fprintf(fp, "DEBUG: value %16lx name %s\n", sp->value, sp->name); + + if (!MODULE_PSEUDO_SYMBOL(sp)) + continue; + + for_each_mod_mem_type(t) { + if (!lm->mem[t].size) + continue; + + sprintf(buf1, "%s%s", module_tag[t].start, lm->mod_name); + sprintf(buf2, "%s%s", module_tag[t].end, lm->mod_name); + + if (STREQ(sp->name, buf1)) { + lm->load_symtable[t] = sp; + break; + } else if (STREQ(sp->name, buf2)) { + lm->load_symend[t] = sp; + break; + } + } + } + } + lm->mod_load_symend--; - if (!MODULE_END(lm->mod_load_symend) && + if (!MODULE_MEMORY() && !MODULE_END(lm->mod_load_symend) && !IN_MODULE_PERCPU(lm->mod_load_symend->value, lm)) error(INFO, "%s: last symbol: %s is not _MODULE_END_%s?\n", lm->mod_name, lm->mod_load_symend->name, lm->mod_name); - mod_symtable_hash_remove_range(lm->mod_symtable, lm->mod_symend); - lm->mod_symtable = lm->mod_load_symtable; - lm->mod_symend = lm->mod_load_symend; - mod_symtable_hash_install_range(lm->mod_symtable, lm->mod_symend); + if (MODULE_MEMORY()) { + for_each_mod_mem_type(t) { + if (!lm->symtable[t]) + continue; + mod_symtable_hash_remove_range(lm->symtable[t], lm->symend[t]); + } + lm->symtable = lm->load_symtable; + lm->symend = lm->load_symend; + mod_symtable_hash_install_range(lm->mod_load_symtable, lm->mod_load_symend); + } else { + mod_symtable_hash_remove_range(lm->mod_symtable, lm->mod_symend); + lm->mod_symtable = lm->mod_load_symtable; + lm->mod_symend = lm->mod_load_symend; + mod_symtable_hash_install_range(lm->mod_symtable, lm->mod_symend); + } lm->mod_flags &= ~MOD_EXT_SYMS; lm->mod_flags |= MOD_LOAD_SYMS; @@ -12642,7 +13860,7 @@ store_load_module_symbols(bfd *bfd, int dynamic, void *minisyms, void delete_load_module(ulong base_addr) { - int i; + int i, t; struct load_module *lm; struct gnu_request request, *req; @@ -12657,7 +13875,18 @@ delete_load_module(ulong base_addr) req->name = lm->mod_namelist; gdb_interface(req); } - mod_symtable_hash_remove_range(lm->mod_symtable, lm->mod_symend); + if (MODULE_MEMORY()) { + if (lm->mod_load_symtable) { + mod_symtable_hash_remove_range(lm->mod_load_symtable, + lm->mod_load_symend); + for_each_mod_mem_type(t) { + lm->load_symtable[t] = NULL; + lm->load_symend[t] = NULL; + } + } + } else + mod_symtable_hash_remove_range(lm->mod_symtable, lm->mod_symend); + if (lm->mod_load_symtable) { free(lm->mod_load_symtable); namespace_ctl(NAMESPACE_FREE, @@ -12665,9 +13894,23 @@ delete_load_module(ulong base_addr) } if (lm->mod_flags & MOD_REMOTE) unlink_module(lm); - lm->mod_symtable = lm->mod_ext_symtable; - lm->mod_symend = lm->mod_ext_symend; - mod_symtable_hash_install_range(lm->mod_symtable, lm->mod_symend); + + if (MODULE_MEMORY()) { + if (lm->mod_load_symtable) { /* still non-NULL */ + lm->symtable = lm->ext_symtable; + lm->symend = lm->ext_symend; + for_each_mod_mem_type(t) { + if (!lm->symtable[t]) + continue; + mod_symtable_hash_install_range(lm->symtable[t], + lm->symend[t]); + } + } + } else { + lm->mod_symtable = lm->mod_ext_symtable; + lm->mod_symend = lm->mod_ext_symend; + mod_symtable_hash_install_range(lm->mod_symtable, lm->mod_symend); + } lm->mod_flags &= ~(MOD_LOAD_SYMS|MOD_REMOTE|MOD_NOPATCH); lm->mod_flags |= MOD_EXT_SYMS; lm->mod_load_symtable = NULL; @@ -12696,7 +13939,18 @@ delete_load_module(ulong base_addr) req->name = lm->mod_namelist; gdb_interface(req); } - mod_symtable_hash_remove_range(lm->mod_symtable, lm->mod_symend); + if (MODULE_MEMORY()) { + if (lm->mod_load_symtable) { + mod_symtable_hash_remove_range(lm->mod_load_symtable, + lm->mod_load_symend); + for_each_mod_mem_type(t) { + lm->load_symtable[t] = NULL; + lm->load_symend[t] = NULL; + } + } + } else + mod_symtable_hash_remove_range(lm->mod_symtable, lm->mod_symend); + if (lm->mod_load_symtable) { free(lm->mod_load_symtable); namespace_ctl(NAMESPACE_FREE, @@ -12704,9 +13958,23 @@ delete_load_module(ulong base_addr) } if (lm->mod_flags & MOD_REMOTE) unlink_module(lm); - lm->mod_symtable = lm->mod_ext_symtable; - lm->mod_symend = lm->mod_ext_symend; - mod_symtable_hash_install_range(lm->mod_symtable, lm->mod_symend); + + if (MODULE_MEMORY()) { + if (lm->mod_load_symtable) { + lm->symtable = lm->ext_symtable; + lm->symend = lm->ext_symend; + for_each_mod_mem_type(t) { + if (!lm->symtable[t]) + continue; + mod_symtable_hash_install_range(lm->symtable[t], + lm->symend[t]); + } + } + } else { + lm->mod_symtable = lm->mod_ext_symtable; + lm->mod_symend = lm->mod_ext_symend; + mod_symtable_hash_install_range(lm->mod_symtable, lm->mod_symend); + } lm->mod_flags &= ~(MOD_LOAD_SYMS|MOD_REMOTE|MOD_NOPATCH); lm->mod_flags |= MOD_EXT_SYMS; lm->mod_load_symtable = NULL; @@ -13455,7 +14723,7 @@ is_downsized(char *name) struct syment * symbol_complete_match(const char *match, struct syment *sp_last) { - int i; + int i, t; struct syment *sp, *sp_end, *sp_start; struct load_module *lm; int search_init; @@ -13475,6 +14743,34 @@ symbol_complete_match(const char *match, struct syment *sp_last) sp_start = NULL; } + if (!MODULE_MEMORY()) + goto old_module; + + for (i = 0; i < st->mods_installed; i++) { + lm = &st->load_modules[i]; + + for_each_mod_mem_type(t) { + sp_end = lm->symend[t]; + if (!sp_start) + sp_start = lm->symtable[t]; + + if (sp_start < lm->symtable[t] || sp_start > sp_end) + continue; + + for (sp = sp_start; sp < sp_end; sp++) { + if (MODULE_PSEUDO_SYMBOL(sp)) + continue; + + if (STRNEQ(sp->name, match)) + return sp; + } + sp_start = NULL; + } + } + + return NULL; + +old_module: search_init = FALSE; for (i = 0; i < st->mods_installed; i++) { @@ -13521,3 +14817,58 @@ symbol_complete_match(const char *match, struct syment *sp_last) return NULL; } + +/* Returns module memory type if addr is in range, otherwise MOD_INVALID(-1) */ +static int +in_module_range(ulong addr, struct load_module *lm, int start, int end) +{ + ulong base = 0, size = 0; + int i; + + if (!MODULE_MEMORY()) + goto old_module; + + for (i = start ; i <= end; i++) { + base = lm->mem[i].base; + size = lm->mem[i].size; + if (!size) + continue; + if ((addr >= base) && (addr < (base + size))) + return i; + } + return MOD_INVALID; + +old_module: + if (start == MOD_TEXT) { + base = lm->mod_base; + size = lm->mod_size; + } else if (start == MOD_INIT_TEXT) { + base = lm->mod_init_module_ptr; + size = lm->mod_init_size; + } else + error(FATAL, "invalid module memory type!"); + + if ((addr >= base) && (addr < (base + size))) + return start; + + return MOD_INVALID; +} + +/* Returns module memory type, otherwise MOD_INVALID(-1) */ +static int +module_mem_type(ulong addr, struct load_module *lm) +{ + return in_module_range(addr, lm, MOD_TEXT, MOD_INIT_RODATA); +} + +/* 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) + 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