[PATCH] crash/ppc64: Remove redundant PTE checks.
by Likhitha Korrapati
Patch removes redundant checks for PTE (Page Table Entry) because those
conditions are already covered.
if (!(pte & _PAGE_PRESENT)) {
...
return FALSE;
}
if (!pte)
return FALSE;
The second pte check is redundant because it holds true only when pte is
0. if pte is 0 then (!(pte & _PAGE_PRESENT)) is true and it will return
false. so there is no need for one more pte check.
Signed-off-by: Likhitha Korrapati <likhitha(a)linux.ibm.com>
---
ppc64.c | 6 ------
1 file changed, 6 deletions(-)
diff --git a/ppc64.c b/ppc64.c
index b95a621..fc34006 100644
--- a/ppc64.c
+++ b/ppc64.c
@@ -968,9 +968,6 @@ ppc64_vtop(ulong vaddr, ulong *pgd, physaddr_t *paddr, int verbose)
return FALSE;
}
- if (!pte)
- return FALSE;
-
*paddr = PAGEBASE(PTOB(pte >> PTE_RPN_SHIFT_DEFAULT)) + PAGEOFFSET(vaddr);
if (verbose) {
@@ -1077,9 +1074,6 @@ ppc64_vtop_level4(ulong vaddr, ulong *level4, physaddr_t *paddr, int verbose)
return FALSE;
}
- if (!pte)
- return FALSE;
-
out:
if (hugepage_type) {
if (hugepage_type == 2) {
--
2.31.1
1 year, 5 months
[PATCH] Support module memory layout change on Linux 6.4
by HAGIO KAZUHITO(萩尾 一仁)
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(-)
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 *);
+
+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;
+}
+
+/* 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
1 year, 5 months
Re: [Crash-utility] [PATCH] crash/ppc64: Remove redundant PTE checks
by lijiang
Hi, Likhitha
Thank you for the patch.
On Mon, Jun 19, 2023 at 8:00 PM <crash-utility-request(a)redhat.com> wrote:
> Date: Fri, 16 Jun 2023 17:25:19 +0530
> From: Likhitha Korrapati <likhitha(a)linux.ibm.com>
> To: sourabhjain(a)linux.ibm.com, crash-utility(a)redhat.com
> Subject: [Crash-utility] [PATCH] crash/ppc64: Remove redundant PTE
> checks.
> Message-ID: <20230616115519.79791-1-likhitha(a)linux.ibm.com>
> Content-Type: text/plain; charset="US-ASCII"; x-default=true
>
> Patch removes redundant checks for PTE (Page Table Entry) because those
> conditions are already covered.
>
> if (!(pte & _PAGE_PRESENT)) {
> ...
> return FALSE;
> }
>
> if (!pte)
> return FALSE;
>
> The second pte check is redundant because it holds true only when pte is
> 0. if pte is 0 then (!(pte & _PAGE_PRESENT)) is true and it will return
> false. so there is no need for one more pte check.
>
>
Looks good to me. So: Ack.
Thanks.
Lianbo
> Signed-off-by: Likhitha Korrapati <likhitha(a)linux.ibm.com>
> ---
> ppc64.c | 6 ------
> 1 file changed, 6 deletions(-)
>
> diff --git a/ppc64.c b/ppc64.c
> index b95a621..fc34006 100644
> --- a/ppc64.c
> +++ b/ppc64.c
> @@ -968,9 +968,6 @@ ppc64_vtop(ulong vaddr, ulong *pgd, physaddr_t *paddr,
> int verbose)
> return FALSE;
> }
>
> - if (!pte)
> - return FALSE;
> -
> *paddr = PAGEBASE(PTOB(pte >> PTE_RPN_SHIFT_DEFAULT)) +
> PAGEOFFSET(vaddr);
>
> if (verbose) {
> @@ -1077,9 +1074,6 @@ ppc64_vtop_level4(ulong vaddr, ulong *level4,
> physaddr_t *paddr, int verbose)
> return FALSE;
> }
>
> - if (!pte)
> - return FALSE;
> -
> out:
> if (hugepage_type) {
> if (hugepage_type == 2) {
> --
> 2.31.1
>
1 year, 5 months
crash failed to debug upstream kernel
by Sourabh Jain
Hello All,
Reporting a crash failure while debugging kernel 6.4.0-rc4 dump.
crash failed with the below error:
crash: invalid structure member offset: module_core_size
FILE: kernel.c LINE: 3781 FUNCTION: module_init()
[/usr/bin/crash] error trace: 130ba0654 => 130752a44 => 13080c980 =>
1308b1ad0
I believe the reason for this is the modification made to the module
structure
through the following patch.
commit ac3b43283923440900b4f36ca5f9f0b1ca43b70e
Author: Song Liu <song(a)kernel.org>
Date: Mon Feb 6 16:28:02 2023 -0800
module: replace module_layout with module_memory
module_layout manages different types of memory (text, data,
rodata, etc.)
in one allocation, which is problematic for some reasons:
Crash searches for module_layout within the struct module, but it has
been replaced
with module_memory in kernel.
Thanks,
Sourabh Jain
1 year, 5 months
Re: [Crash-utility] [PATCH 2/2] Fix again segfault in arm64_is_kernel_exception_frame() when corrupt stack pointer address is given
by lijiang
On Wed, Jun 7, 2023 at 8:00 PM <crash-utility-request(a)redhat.com> wrote:
> Date: Wed, 7 Jun 2023 18:37:34 +0900
> From: HATAYAMA Daisuke <d.hatayama(a)fujitsu.com>
> To: crash-utility(a)redhat.com
> Cc: d.hatayama(a)fujitsu.com
> Subject: [Crash-utility] [PATCH 2/2] Fix again segfault in
> arm64_is_kernel_exception_frame() when corrupt stack pointer
> address
> is given
> Message-ID: <20230607093734.247-2-d.hatayama(a)fujitsu.com>
> Content-Type: text/plain; charset="US-ASCII"; x-default=true
>
> This is the second trial from the commit
> 9868ebc8e648e5791764a51567a23efae7170d9b that was reverted at the
> previous commit.
>
> As described in the previous commit, result of STACK_OFFSET_TYPE() can
> be an address out of bt->stackbuf and hence the address needs to be
> checked prior to being referred to as an pt_regs object.
>
> So, to fix the issue, let's check if stkptr points to within the range
> of the kernel stack first.
>
> Signed-off-by: HATAYAMA Daisuke <d.hatayama(a)fujitsu.com>
> ---
> arm64.c | 3 +++
> 1 file changed, 3 insertions(+)
>
> diff --git a/arm64.c b/arm64.c
> index efbdccb..ca63fb5 100644
> --- a/arm64.c
> +++ b/arm64.c
> @@ -2381,6 +2381,9 @@ arm64_is_kernel_exception_frame(struct bt_info *bt,
> ulong stkptr)
> struct arm64_pt_regs *regs;
> struct machine_specific *ms = machdep->machspec;
>
> + if (stkptr > STACKSIZE() && !INSTACK(stkptr, bt))
> + return FALSE;
> +
>
I still have one question: Why does this one only need to be fixed, but the
others are not needed(it won't be out of range)? The STACK_OFFSET_TYPE() is
invoked multiple times in arm64.c, and similar calls can be seen on other
arches(grep -nr "GET_STACK_ULONG" *.c or grep -nr "GET_STACK_DATA" *.c).
# grep -nr "STACK_OFFSET_TYPE" *.c
arm64.c:2384: regs = (struct arm64_pt_regs
*)&bt->stackbuf[(ulong)(STACK_OFFSET_TYPE(stkptr))];
arm64.c:2821: ptregs = (struct arm64_pt_regs
*)&bt->stackbuf[(ulong)(STACK_OFFSET_TYPE(orig_sp))];
arm64.c:3476: base = (ulong
*)&bt->stackbuf[(ulong)(STACK_OFFSET_TYPE(bt->stackbase))];
arm64.c:3478: start = (ulong
*)&bt->stackbuf[(ulong)(STACK_OFFSET_TYPE(bt->stacktop))];
arm64.c:3481: start = (ulong
*)&bt->stackbuf[(ulong)(STACK_OFFSET_TYPE(frame->fp))];
arm64.c:3483: start = (ulong
*)&bt->stackbuf[(ulong)(STACK_OFFSET_TYPE(bt->stacktop))];
arm64.c:3801: &bt->stackbuf[(ulong)(STACK_OFFSET_TYPE(sp))];
arm64.c:3822: &bt->stackbuf[(ulong)(STACK_OFFSET_TYPE(pt_regs))];
x86.c:1075: if (STACK_OFFSET_TYPE(ep->eframe_addr) > STACKSIZE())
[root@hpe-apollo-cn99xx-13-vm-01 crash]# grep -nr "STACK_OFFSET_TYPE" *.h
defs.h:977:#define STACK_OFFSET_TYPE(OFF) \
defs.h:985: *((ulong *)((char
*)(&bt->stackbuf[(ulong)(STACK_OFFSET_TYPE(OFF))])))
defs.h:988: (void *)(&bt->stackbuf[(ulong)STACK_OFFSET_TYPE(OFF)]),
(size_t)(SZ))
Thanks.
Lianbo
regs = (struct arm64_pt_regs
> *)&bt->stackbuf[(ulong)(STACK_OFFSET_TYPE(stkptr))];
>
> if (INSTACK(regs->sp, bt) && INSTACK(regs->regs[29], bt) &&
> --
> 2.25.1
>
1 year, 5 months
Re: [Crash-utility] [PATCH 1/2] Revert "Fix segfault in arm64_is_kernel_exception_frame() when corrupt stack pointer address is given"
by lijiang
On Wed, Jun 7, 2023 at 8:00 PM <crash-utility-request(a)redhat.com> wrote:
> Date: Wed, 7 Jun 2023 18:37:33 +0900
> From: HATAYAMA Daisuke <d.hatayama(a)fujitsu.com>
> To: crash-utility(a)redhat.com
> Cc: d.hatayama(a)fujitsu.com
> Subject: [Crash-utility] [PATCH 1/2] Revert "Fix segfault in
> arm64_is_kernel_exception_frame() when corrupt stack pointer
> address
> is given"
> Message-ID: <20230607093734.247-1-d.hatayama(a)fujitsu.com>
> Content-Type: text/plain; charset="US-ASCII"; x-default=true
>
> This reverts commit 9868ebc8e648e5791764a51567a23efae7170d9b.
>
> The commit 9868ebc8e648e5791764a51567a23efae7170d9b causes the issue
> that bt command fails to show backtraces for the tasks that is running
> in the user mode at the moment of the kernel panic as follows:
>
> crash> bt 1734
> PID: 1734 TASK: ffff000000392200 CPU: 4 COMMAND: "insmod"
> bt: invalid stack pointer is given
>
>
Thank you for pointing out this issue, HATAYAMA.
Anyway, I did not reproduce the above issue. Seems it can not always be
reproduced.
# ./crash /home/vmlinux /var/crash/127.0.0.1-2023-06-09-05\:20\:38/vmcore -s
WARNING: cpu 2: invalid NT_PRSTATUS note (n_type != NT_PRSTATUS)
WARNING: cpu 1: cannot find NT_PRSTATUS note
WARNING: cpu 2: cannot find NT_PRSTATUS note
crash> ps insmod
PID PPID CPU TASK ST %MEM VSZ RSS COMM
1684 1683 0 ffff06738f1cdd00 ZO 0.0 0 0 insmod
crash> bt 1684
PID: 1684 TASK: ffff06738f1cdd00 CPU: 0 COMMAND: "insmod"
(no stack)
crash>
Thanks.
Lianbo
> The root cause is that while the commit added a sanity check into
> STACK_OFFSET_TYPE() to validate if a given candidate address of any
> interrupt or exception frame is contained within the range of the
> corresponding kernel stack, the premise that the STACK_OFFSET_TYPE()
> should not return out-of-the-buffer address, is wrong.
>
> Reexamining the relevant surrounding part of the backtracing code, it
> looks to me now that the STACK_OFFSET_TYPE() is originally expected to
> return an out-of-the-buffer address, like the address of the top of
> the corresponding kernel stack, e.g. at here:
>
> static int
> arm64_in_kdump_text(struct bt_info *bt, struct arm64_stackframe *frame)
> {
> ...
> if (bt->flags & BT_USER_SPACE)
> start = (ulong
> *)&bt->stackbuf[(ulong)(STACK_OFFSET_TYPE(bt->stacktop))];
> else {
>
> Note that the above bt 1734 aborts here.
>
> Hence, the current implementation policy around STACK_OFFSET_TYPE()
> looks that the caller side is responsible for understanding the fact
> in advance and for avoiding making buffer overrun carefully.
>
> To fix this issue, revert the commit.
>
> Signed-off-by: HATAYAMA Daisuke <d.hatayama(a)fujitsu.com>
> ---
> defs.h | 5 +----
> 1 file changed, 1 insertion(+), 4 deletions(-)
>
> diff --git a/defs.h b/defs.h
> index bfda0c4..3e7d6cf 100644
> --- a/defs.h
> +++ b/defs.h
> @@ -976,10 +976,7 @@ struct bt_info {
>
> #define STACK_OFFSET_TYPE(OFF) \
> (((ulong)(OFF) > STACKSIZE()) ? \
> - (((ulong)(OFF) < (ulong)(bt->stackbase) || (ulong)(OFF) >=
> (ulong)(bt->stackbase) + STACKSIZE()) ? \
> - error(FATAL, "invalid stack pointer is given\n") : \
> - (ulong)((ulong)(OFF) - (ulong)(bt->stackbase))) : \
> - (ulong)(OFF))
> + (ulong)((ulong)(OFF) - (ulong)(bt->stackbase)) : (ulong)(OFF))
>
> #define GET_STACK_ULONG(OFF) \
> *((ulong *)((char *)(&bt->stackbuf[(ulong)(STACK_OFFSET_TYPE(OFF))])))
> --
> 2.25.1
>
1 year, 5 months
[PATCH 1/2] Revert "Fix segfault in arm64_is_kernel_exception_frame() when corrupt stack pointer address is given"
by HATAYAMA Daisuke
This reverts commit 9868ebc8e648e5791764a51567a23efae7170d9b.
The commit 9868ebc8e648e5791764a51567a23efae7170d9b causes the issue
that bt command fails to show backtraces for the tasks that is running
in the user mode at the moment of the kernel panic as follows:
crash> bt 1734
PID: 1734 TASK: ffff000000392200 CPU: 4 COMMAND: "insmod"
bt: invalid stack pointer is given
The root cause is that while the commit added a sanity check into
STACK_OFFSET_TYPE() to validate if a given candidate address of any
interrupt or exception frame is contained within the range of the
corresponding kernel stack, the premise that the STACK_OFFSET_TYPE()
should not return out-of-the-buffer address, is wrong.
Reexamining the relevant surrounding part of the backtracing code, it
looks to me now that the STACK_OFFSET_TYPE() is originally expected to
return an out-of-the-buffer address, like the address of the top of
the corresponding kernel stack, e.g. at here:
static int
arm64_in_kdump_text(struct bt_info *bt, struct arm64_stackframe *frame)
{
...
if (bt->flags & BT_USER_SPACE)
start = (ulong *)&bt->stackbuf[(ulong)(STACK_OFFSET_TYPE(bt->stacktop))];
else {
Note that the above bt 1734 aborts here.
Hence, the current implementation policy around STACK_OFFSET_TYPE()
looks that the caller side is responsible for understanding the fact
in advance and for avoiding making buffer overrun carefully.
To fix this issue, revert the commit.
Signed-off-by: HATAYAMA Daisuke <d.hatayama(a)fujitsu.com>
---
defs.h | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/defs.h b/defs.h
index bfda0c4..3e7d6cf 100644
--- a/defs.h
+++ b/defs.h
@@ -976,10 +976,7 @@ struct bt_info {
#define STACK_OFFSET_TYPE(OFF) \
(((ulong)(OFF) > STACKSIZE()) ? \
- (((ulong)(OFF) < (ulong)(bt->stackbase) || (ulong)(OFF) >= (ulong)(bt->stackbase) + STACKSIZE()) ? \
- error(FATAL, "invalid stack pointer is given\n") : \
- (ulong)((ulong)(OFF) - (ulong)(bt->stackbase))) : \
- (ulong)(OFF))
+ (ulong)((ulong)(OFF) - (ulong)(bt->stackbase)) : (ulong)(OFF))
#define GET_STACK_ULONG(OFF) \
*((ulong *)((char *)(&bt->stackbuf[(ulong)(STACK_OFFSET_TYPE(OFF))])))
--
2.25.1
1 year, 5 months
[PATCH] ppc64: fix crash load failure
by Lianbo Jiang
Crash tool will fail to load vmcore with the following error:
#crash vmlinux /var/crash/127.0.0.1-2023-06-07-22\:03\:24/vmcore -s
crash: invalid structure size: note_buf
FILE: diskdump.c LINE: 121 FUNCTION: have_crash_notes()
[./crash] error trace: 101859ac => 10291798 => 10291450 => 10266038
10266038: SIZE_verify+156
10291450: have_crash_notes+308
10291798: map_cpus_to_prstatus_kdump_cmprs+448
101859ac: task_init+11980
The reason is that the note_buf is not intialized before using the
SIZE(note_buf) in the have_crash_notes(). Let's initialize the variable
note_buf in the ppc64_init() to fix this issue.
Fixes: db8c030857b4 ("diskdump/netdump: fix segmentation fault caused by failure of stopping CPUs")
Signed-off-by: Lianbo Jiang <lijiang(a)redhat.com>
---
ppc64.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/ppc64.c b/ppc64.c
index b95a621d8fe4..ff7f0fca3a95 100644
--- a/ppc64.c
+++ b/ppc64.c
@@ -695,6 +695,7 @@ ppc64_init(int when)
}
ppc64_init_paca_info();
+ STRUCT_SIZE_INIT(note_buf, "note_buf_t");
if (!machdep->hz) {
machdep->hz = HZ;
--
2.37.1
1 year, 5 months
[PATCH v2] Fix crash load failure in ppc64
by Lianbo Jiang
Crash tool will fail to load vmcore with the following error:
#crash vmlinux /var/crash/127.0.0.1-2023-06-07-22\:03\:24/vmcore -s
crash: invalid structure size: note_buf
FILE: diskdump.c LINE: 121 FUNCTION: have_crash_notes()
[./crash] error trace: 101859ac => 10291798 => 10291450 => 10266038
10266038: SIZE_verify+156
10291450: have_crash_notes+308
10291798: map_cpus_to_prstatus_kdump_cmprs+448
101859ac: task_init+11980
The reason is that the note_buf is not intialized before using the
SIZE(note_buf) in the have_crash_notes(). Let's initialize the variable
note_buf in the task_init() to fix this issue.
Fixes: db8c030857b4 ("diskdump/netdump: fix segmentation fault caused by failure of stopping CPUs")
Signed-off-by: Lianbo Jiang <lijiang(a)redhat.com>
---
task.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/task.c b/task.c
index 88941c7b0e4d..2b7467b4193d 100644
--- a/task.c
+++ b/task.c
@@ -675,6 +675,9 @@ task_init(void)
tt->this_task = pid_to_task(active_pid);
}
else {
+ if (INVALID_SIZE(note_buf))
+ STRUCT_SIZE_INIT(note_buf, "note_buf_t");
+
if (KDUMP_DUMPFILE())
map_cpus_to_prstatus();
else if (ELF_NOTES_VALID() && DISKDUMP_DUMPFILE())
--
2.37.1
1 year, 5 months
[PATCH crash-trace] Fix handling of Thumb-2 kernels
by Vincent Whitchurch
The function pointer to symbol comparison for checking get_fields fails
with ARM kernels built with the Thumb-2 instruction set. Ignore the
least significant bit for the comparison since it stores information
about the ARM/Thumb state. Do this unconditionally since it shouldn't
cause any problems for other architectures.
crash-arm> extend trace.so
...
<readmem: 80d57cbc, KVADDR, "read ftrace_event_call get_fields", 4, (ROE), ff87ffa4>
<read_kdump: addr: 80d57cbc paddr: d57cbc cnt: 4>
Unkown get_fields function
extend: /usr/lib/crash-arm/extensions/trace.so: no commands registered: shared object unloaded
crash-arm> rd 80d57cbc
80d57cbc: 801db565 e...
crash-arm> sym syscall_get_enter_fields
801db564 (t) syscall_get_enter_fields
Signed-off-by: Vincent Whitchurch <vincent.whitchurch(a)axis.com>
---
trace.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/trace.c b/trace.c
index c33907f..bdb086a 100644
--- a/trace.c
+++ b/trace.c
@@ -1029,9 +1029,9 @@ int ftrace_get_event_type_fields(ulong call, ulong *fields)
get_fields_offset = MAX(MEMBER_OFFSET("ftrace_event_class", "get_fields"),
MEMBER_OFFSET("trace_event_class", "get_fields"));
if ((sp = symbol_search("syscall_get_enter_fields")) != NULL)
- syscall_get_enter_fields_value = sp->value;
+ syscall_get_enter_fields_value = sp->value & ~1;
if ((sp = symbol_search("syscall_get_exit_fields")) != NULL)
- syscall_get_exit_fields_value = sp->value;
+ syscall_get_exit_fields_value = sp->value & ~1;
work:
if (fields_offset < 0)
@@ -1056,6 +1056,8 @@ work:
return 0;
}
+ get_fields &= ~1;
+
if (get_fields == syscall_get_enter_fields_value)
return syscall_get_enter_fields(call, fields);
---
base-commit: 153629a96b07a8ae96b0b28cce100fde9ea1398d
change-id: 20230612-thumb2-2431fd10df56
Best regards,
--
Vincent Whitchurch <vincent.whitchurch(a)axis.com>
1 year, 5 months