[Crash-utility] [PATCH] Support module memory layout change on Linux 6.4
lijiang
lijiang at redhat.com
Tue Jun 20 01:46:30 UTC 2023
On Tue, Jun 20, 2023 at 9:36 AM lijiang <lijiang at redhat.com> wrote:
> On Wed, Jun 14, 2023 at 4:06 PM HAGIO KAZUHITO(萩尾 一仁) <k-hagio-ab at nec.com>
> wrote:
>
>> 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 at nec.com>
>> ---
>> RFC -> v1
>> - Applied a lot of Lianbo's comments and discussions
>> - Rewrote {next,prev}_symbol() and splitted functions to skip regions
>> that have only pseudo symbols
>> - Squashed the patchset into one patch, after all
>> (Please let me know if there are changes that should be splitted.)
>>
>> defs.h | 46 +-
>> gdb-10.2.patch | 16 +
>> kernel.c | 54 +-
>> memory.c | 36 +-
>> symbols.c | 1588 ++++++++++++++++++++++++++++++++++++++++++++----
>> 5 files changed, 1607 insertions(+), 133 deletions(-)
>>
>>
> Good job, Kazu.
>
> The other changes look good, and I don't see any regression issues on my
> side. But I still have two comments below:
>
> diff --git a/defs.h b/defs.h
>> index bfda0c48d37b..96ea7630123f 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())
>> @@ -2220,6 +2222,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 */
>> @@ -2393,6 +2398,7 @@ struct size_table { /* stash of
>> commonly-used sizes */
>> long percpu_counter;
>> long maple_tree;
>> long maple_node;
>> + long module_memory;
>> };
>>
>> struct array_table {
>> @@ -2925,6 +2931,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 {
>> @@ -2960,19 +2983,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 (int (type) = MOD_TEXT; (type) < MOD_MEM_NUM_TYPES; (type)++)
>> +
>> #ifndef GDB_COMMON
>>
>> #define KVADDR (0x1)
>> @@ -5591,6 +5624,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..b3f6d8b086eb 100644
>> --- a/gdb-10.2.patch
>> +++ b/gdb-10.2.patch
>> @@ -3120,3 +3120,19 @@ exit 0
>> return result;
>> }
>>
>> +--- gdb-10.2/gdb/symtab.c.orig
>> ++++ gdb-10.2/gdb/symtab.c
>> +@@ -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);
>> + }
>> + }
>>
>
BTW: I can still get the following warnings:
...
CXX symtab.o
symtab.c: In function ‘void gdb_command_funnel_1(gnu_request*)’:
symtab.c:7519:64: warning: ‘%lx’ directive writing between 1 and 16 bytes
into a region of size between 10 and 73 [-Wformat-overflow=]
7519 | sprintf(buf, " -s %s
0x%lx", secname, lm->mod_section_data[i].addr);
| ^~~
symtab.c:7519:54: note: directive argument in the range [1,
18446744073709551615]
7519 | sprintf(buf, " -s %s
0x%lx", secname, lm->mod_section_data[i].addr);
| ^~~~~~~~~~~~~~
Thanks.
Lianbo
> diff --git a/kernel.c b/kernel.c
>> index 6e98f5f6f6b1..a4d20f5b122e 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;
>> }
>>
>> @@ -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..f282aee59952 100644
>> --- a/memory.c
>> +++ b/memory.c
>> @@ -15713,9 +15713,43 @@ static int
>> next_module_vaddr(ulong vaddr, ulong *nextvaddr)
>> {
>> int i;
>> - ulong start, end;
>> + 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..41a50ced8abd 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);
>> +struct syment *value_search_module_6_4(ulong, ulong *);
>> +struct syment *next_symbol_by_symname(char *);
>> +struct syment *prev_symbol_by_symname(char *);
>> +struct syment *next_module_symbol_by_value(ulong);
>> +struct syment *prev_module_symbol_by_value(ulong);
>> +struct syment *next_module_symbol_by_syment(struct syment *);
>> +struct syment *prev_module_symbol_by_syment(struct syment *);
>> +
>>
>
> The above functions are only used in the symbols.c, It should be good to
> add a 'static' keyword to them.
>
>
>> +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;
>> + 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;
>> + 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;
>> @@ -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;
>> @@ -2600,9 +3097,20 @@ highest_module_address(void)
>> 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,41 @@ dump_symbol_table(void)
>> (ulong)lm->mod_section_data,
>> lm->mod_section_data ? "" : "(not allocated)");
>>
>> + if (MODULE_MEMORY()) {
>> + 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 +4992,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)) {
>> @@ -4534,6 +5071,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++) {
>> @@ -4653,6 +5244,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;
>>
>> @@ -4722,6 +5344,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 (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 +5485,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 +5543,71 @@ module_symbol(ulong value,
>> return FALSE;
>> }
>>
>> +struct syment *
>> +value_search_module_6_4(ulong value, ulong *offset)
>> +{
>> + int i;
>> + 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 +5616,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 +5937,99 @@ closest_symbol_value(ulong value)
>> return(0);
>> }
>>
>> +/* Only for 6.4 and later */
>> +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. */
>> +struct syment *
>> +next_module_symbol_by_value(ulong val_in)
>> +{
>> + struct load_module *lm;
>> + struct syment *sp, *sp_end;
>> + ulong start, min;
>> + int i;
>> +
>> +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;
>>
>
> Is it possible for 'retry' to become an infinite loop? And there is also a
> similar 'retry' in the prev_module_symbol_by_value().
>
> Thanks.
> Lianbo
>
> +}
>> +
>> +/* Only for 6.4 and later */
>> +struct syment *
>> +next_module_symbol_by_syment(struct syment *sp_in)
>> +{
>> + struct load_module *lm;
>> + struct syment *sp;
>> + int i;
>> +
>> + 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 +6057,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 +6100,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 */
>> +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. */
>> +struct syment *
>> +prev_module_symbol_by_value(ulong val_in)
>> +{
>> + struct load_module *lm;
>> + struct syment *sp, *sp_end;
>> + ulong end, max;
>> + int i;
>> +
>> +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 */
>> +struct syment *
>> +prev_module_symbol_by_syment(struct syment *sp_in)
>> +{
>> + struct load_module *lm;
>> + struct syment *sp;
>> + int i;
>>
>> - 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 +6267,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 +6313,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]);
>> @@ -5625,6 +6563,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 +10192,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 +11818,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 +12434,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 +12448,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 +12691,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;
>> +
>> + 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 +13014,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);
>> }
>> }
>> @@ -12276,17 +13366,36 @@ kallsyms_module_symbol(struct load_module *lm,
>> symbol_info *syminfo)
>>
>> 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)) {
>> @@ -12323,7 +13432,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 +13489,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 +13510,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 +13620,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 +13658,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 +13747,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 +13757,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 +13772,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 +13794,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;
>> @@ -12657,7 +13874,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 +13893,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 +13938,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 +13957,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;
>> @@ -13475,6 +14742,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 +14816,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
>>
>>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://listman.redhat.com/archives/crash-utility/attachments/20230620/661ad713/attachment-0001.htm>
More information about the Crash-utility
mailing list