With kernel's kallsyms and btf ready, we can get any kernel types and
symbol addresses. So we can iterate kernel modules' linked list, and
parse & install each one of kernel module's structure to get its kallsyms
data.

Signed-off-by: Tao Liu <[email protected]>
---
 kallsyms.c | 126 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 kallsyms.h |  19 ++++++++
 2 files changed, 145 insertions(+)

diff --git a/kallsyms.c b/kallsyms.c
index 116f857..f5859e9 100644
--- a/kallsyms.c
+++ b/kallsyms.c
@@ -4,6 +4,7 @@
 #include <assert.h>
 #include "makedumpfile.h"
 #include "kallsyms.h"
+#include "btf.h"
 
 static uint32_t *kallsyms_offsets = NULL;
 static uint16_t *kallsyms_token_index = NULL;
@@ -231,6 +232,131 @@ out:
        return ret;
 }
 
+uint64_t next_list(uint64_t list)
+{
+       static int list_head_next_offset = 0;
+       static int list_head_next_size = 0;
+
+       struct member_info mi;
+       uint64_t next = 0;
+
+       if (!list_head_next_size) {
+               get_struct_member_by_name("list_head", "next", &mi);
+               list_head_next_size = mi.size;
+               list_head_next_offset = mi.bit_pos / 8;
+       }
+       readmem(VADDR, list + list_head_next_offset, &next, 
list_head_next_size);
+       return next;
+}
+
+int init_module_kallsyms(void)
+{
+       struct member_info mi;
+       uint64_t modules, list, value = 0, symtab = 0,
+               strtab = 0, typetab = 0;
+       uint32_t st_name = 0;
+       int num_symtab, i, j;
+       struct syment *mod_syment;
+       char symname[512], ch;
+       int ret = -1;
+
+       modules = get_kallsyms_value_by_name("modules");
+       if (!modules) {
+               /* Not a failure if no module enabled */
+               ret = 0;
+               goto out;
+       }
+
+       INIT_MEMBER_OFF_SIZE(module, list);
+       INIT_MEMBER_OFF_SIZE(module, core_kallsyms);
+       INIT_MEMBER_OFF_SIZE(mod_kallsyms, symtab);
+       INIT_MEMBER_OFF_SIZE(mod_kallsyms, num_symtab);
+       INIT_MEMBER_OFF_SIZE(mod_kallsyms, strtab);
+       INIT_MEMBER_OFF_SIZE(mod_kallsyms, typetab);
+       INIT_MEMBER_OFF_SIZE(elf64_sym, st_name);
+       INIT_MEMBER_OFF_SIZE(elf64_sym, st_value);
+
+       for (list = next_list(modules); list != modules; list = 
next_list(list)) {
+               readmem(VADDR, list - GET_MEMBER_OFF(module, list) +
+                               GET_MEMBER_OFF(module, core_kallsyms) +
+                               GET_MEMBER_OFF(mod_kallsyms, num_symtab),
+                       &num_symtab, GET_MEMBER_SIZE(mod_kallsyms, num_symtab));
+               readmem(VADDR, list - GET_MEMBER_OFF(module, list) +
+                               GET_MEMBER_OFF(module, core_kallsyms) +
+                               GET_MEMBER_OFF(mod_kallsyms, symtab),
+                       &symtab, GET_MEMBER_SIZE(mod_kallsyms, symtab));
+               readmem(VADDR, list - GET_MEMBER_OFF(module, list) +
+                               GET_MEMBER_OFF(module, core_kallsyms) +
+                               GET_MEMBER_OFF(mod_kallsyms, strtab),
+                       &strtab, GET_MEMBER_SIZE(mod_kallsyms, strtab));
+               readmem(VADDR, list - GET_MEMBER_OFF(module, list) +
+                               GET_MEMBER_OFF(module, core_kallsyms) +
+                               GET_MEMBER_OFF(mod_kallsyms, typetab),
+                       &typetab, GET_MEMBER_SIZE(mod_kallsyms, typetab));
+               for (i = 0; i < num_symtab; i++) {
+                       j = 0;
+                       readmem(VADDR, symtab + i * GET_STRUCT_SIZE(elf64_sym, 
st_value) +
+                                       GET_MEMBER_OFF(elf64_sym, st_value),
+                               &value, GET_MEMBER_SIZE(elf64_sym, st_value));
+                       readmem(VADDR, symtab + i * GET_STRUCT_SIZE(elf64_sym, 
st_name) +
+                                       GET_MEMBER_OFF(elf64_sym, st_name),
+                               &st_name, GET_MEMBER_SIZE(elf64_sym, st_name));
+                       do {
+                               readmem(VADDR, strtab + st_name + j++, &ch, 1);
+                       } while (ch != '\0');
+                       if (j == 1)
+                               /* Skip empty string */
+                               continue;
+                       assert(j <= sizeof(symname));
+                       mod_syment = (struct syment *)calloc(1, sizeof(struct 
syment));
+                       if (!mod_syment)
+                               goto no_mem;
+                       readmem(VADDR, strtab + st_name, symname, j);
+                       mod_syment->name = strdup(symname);
+                       if (!mod_syment->name) {
+                               free(mod_syment);
+                               goto no_mem;
+                       }
+                       mod_syment->value = value;
+                       readmem(VADDR, typetab + i, &mod_syment->type, 1);
+                       name_hash_install(mod_syment);
+               }
+       }
+       ret = 0;
+       goto out;
+no_mem:
+       /* Hashtable will be cleaned later */
+       fprintf(stderr, "%s: Not enough memory!\n", __func__);
+out:
+       return ret;
+}
+
+void cleanup_kallsyms(void)
+{
+       struct syment *en, *en_tmp;
+       int i;
+
+       /* Free the module's kallsyms first */
+       for (i = 0; i < NAME_HASH; i++) {
+               for (en = name_hash_table[i]; en;) {
+                       en_tmp = en;
+                       en = en->name_hash_next;
+                       if (en_tmp <= &symtable[kallsyms_num_syms - 1] &&
+                               en_tmp >= &symtable[0])
+                               continue;
+                       free(en_tmp->name);
+                       free(en_tmp);
+               }
+       }
+
+       /* Free the kernel ones */
+       for (i = 0; i < kallsyms_num_syms; i++) {
+               if (symtable[i].name)
+                       free(symtable[i].name);
+       }
+       free(symtable);
+}
+
 /* Hash table utils */
 unsigned int hash_index(const char *name, unsigned int hash_size)
 {
diff --git a/kallsyms.h b/kallsyms.h
index 35bf89e..bc8f58b 100644
--- a/kallsyms.h
+++ b/kallsyms.h
@@ -13,7 +13,26 @@ struct syment {
 int init_kernel_kallsyms(void);
 int read_vmcoreinfo_kallsyms(void);
 struct syment *search_kallsyms_by_name(char *);
+uint64_t next_list(uint64_t);
 uint64_t get_kallsyms_value_by_name(char *);
+int init_module_kallsyms(void);
+void cleanup_kallsyms(void);
+int read_vmcoreinfo_kallsyms(void);
+
+struct member_off_size {
+       int m_off;
+       int m_size;
+       int s_size;
+};
+#define QUATE(x) #x
+#define INIT_MEMBER_OFF_SIZE(S, M) \
+       struct member_off_size S##_##M; \
+       S##_##M.s_size = get_struct_member_by_name(QUATE(S), QUATE(M), &mi); \
+       S##_##M.m_off = mi.bit_pos / 8; \
+       S##_##M.m_size = mi.size;
+#define GET_MEMBER_OFF(S, M) (S##_##M.m_off)
+#define GET_MEMBER_SIZE(S, M) (S##_##M.m_size)
+#define GET_STRUCT_SIZE(S, M) (S##_##M.s_size)
 
 unsigned int hash_index(const char *, unsigned int);
 void hash_install(void **, unsigned int, void *, const char *,
-- 
2.47.0


Reply via email to