Support:
- sym -l
- sym -M
- sym -m module

Signed-off-by: Kazuhito Hagio <k-hagio...@nec.com>
---
 symbols.c | 234 +++++++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 225 insertions(+), 9 deletions(-)

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

--
Crash-utility mailing list
Crash-utility@redhat.com
https://listman.redhat.com/mailman/listinfo/crash-utility
Contribution Guidelines: https://github.com/crash-utility/crash/wiki

Reply via email to