On Wed, Jun 14, 2023 at 4:06 PM HAGIO KAZUHITO(萩尾 一仁) <k-hagio-ab(a)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...
 Signed-off-by: Kazuhito Hagio <k-hagio-ab(a)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);
 +                             }
 +                     }
 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