Hi Dave,
When I was investigating the backtrace problem(crash doesn't show
some functions from backtrace output), I found the reason was that
there was a dead-looping(or anything that would block module init
function) in module init function, in which case kernel had no chance
to update mod->symtab from mod->core_symtab, and mod->symtab was
still referring into the module init section which was not freed
until the end of module init function.
Since crash never searches module init function for symbols, in the
case we can't see any symbol from module from the backtrace output.
Following patch makes crash search the module init section for
symbols too if the section is not null.
--
Thanks,
Hu Tao
diff --git a/defs.h b/defs.h
index d431d6e..0fe9d48 100755
--- a/defs.h
+++ b/defs.h
@@ -1515,6 +1515,7 @@ struct offset_table { /* stash of commonly-used
offsets */
long mm_struct_rss_stat;
long mm_rss_stat_count;
long module_module_init;
+ long module_init_size;
long module_init_text_size;
long cpu_context_save_fp;
long cpu_context_save_sp;
@@ -2038,6 +2039,8 @@ struct load_module {
ulong mod_flags;
struct syment *mod_symtable;
struct syment *mod_symend;
+ struct syment *mod_init_symtable;
+ struct syment *mod_init_symend;
long mod_ext_symcnt;
struct syment *mod_ext_symtable;
struct syment *mod_ext_symend;
@@ -2054,6 +2057,7 @@ struct load_module {
ulong mod_bss_start;
int mod_sections;
struct mod_section_data *mod_section_data;
+ ulong mod_init_size;
ulong mod_init_text_size;
ulong mod_init_module_ptr;
};
@@ -2061,6 +2065,9 @@ struct load_module {
#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)))
+
#ifndef GDB_COMMON
#define KVADDR (0x1)
diff --git a/kernel.c b/kernel.c
index 5dc2c45..a50882a 100755
--- a/kernel.c
+++ b/kernel.c
@@ -2691,6 +2691,7 @@ module_init(void)
MEMBER_OFFSET_INIT(module_core_text_size, "module",
"core_text_size");
MEMBER_OFFSET_INIT(module_module_init, "module", "module_init");
+ MEMBER_OFFSET_INIT(module_init_size, "module", "init_size");
MEMBER_OFFSET_INIT(module_init_text_size, "module",
"init_text_size");
diff --git a/symbols.c b/symbols.c
index c373668..f1c308e 100755
--- a/symbols.c
+++ b/symbols.c
@@ -884,10 +884,13 @@ symname_hash_search(char *name)
*/
#define MODULE_PSEUDO_SYMBOL(sp) \
- (STRNEQ((sp)->name, "_MODULE_START_") || STRNEQ((sp)->name,
"_MODULE_END_"))
+ ((STRNEQ((sp)->name, "_MODULE_START_") || STRNEQ((sp)->name,
"_MODULE_END_")) || \
+ (STRNEQ((sp)->name, "_MODULE_INIT_START_") || STRNEQ((sp)->name,
"_MODULE_INIT_END_")))
#define MODULE_START(sp) (STRNEQ((sp)->name, "_MODULE_START_"))
#define MODULE_END(sp) (STRNEQ((sp)->name, "_MODULE_END_"))
+#define MODULE_INIT_START(sp) (STRNEQ((sp)->name, "_MODULE_INIT_START_"))
+#define MODULE_INIT_END(sp) (STRNEQ((sp)->name, "_MODULE_INIT_END_"))
static void
symbol_dump(ulong flags, char *module)
@@ -927,6 +930,26 @@ symbol_dump(ulong flags, char *module)
} else
show_symbol(sp, 0, SHOW_RADIX());
}
+
+ if (lm->mod_init_symtable) {
+ sp = lm->mod_init_symtable;
+ sp_end = lm->mod_init_symend;
+
+ for ( ; sp <= sp_end; sp++) {
+ if (MODULE_PSEUDO_SYMBOL(sp)) {
+ if (MODULE_INIT_START(sp)) {
+ p1 = "MODULE INIT START";
+ p2 = sp->name+strlen("_MODULE_INIT_START_");
+ } else {
+ p1 = "MODULE INIT END";
+ p2 = sp->name+strlen("_MODULE_INIT_END_");
+ }
+ fprintf(fp, "%lx %s: %s\n", sp->value, p1, p2);
+ } else
+ show_symbol(sp, 0, SHOW_RADIX());
+ }
+ }
+
}
}
@@ -1244,6 +1267,8 @@ store_module_symbols_v2(ulong total, int mods_installed)
struct load_module *lm;
char buf1[BUFSIZE];
char buf2[BUFSIZE];
+ char buf3[BUFSIZE];
+ char buf4[BUFSIZE];
char *strbuf, *modbuf, *modsymbuf;
struct syment *sp;
ulong first, last;
@@ -1326,11 +1351,15 @@ store_module_symbols_v2(ulong total, int mods_installed)
if (THIS_KERNEL_VERSION >= LINUX(2,6,27)) {
lm->mod_etext_guess = lm->mod_base +
UINT(modbuf + OFFSET(module_core_text_size));
+ lm->mod_init_size =
+ UINT(modbuf + OFFSET(module_init_size));
lm->mod_init_text_size =
UINT(modbuf + OFFSET(module_init_text_size));
} else {
lm->mod_etext_guess = lm->mod_base +
ULONG(modbuf + OFFSET(module_core_text_size));
+ lm->mod_init_size =
+ ULONG(modbuf + OFFSET(module_init_size));
lm->mod_init_text_size =
ULONG(modbuf + OFFSET(module_init_text_size));
}
@@ -1344,6 +1373,18 @@ store_module_symbols_v2(ulong total, int mods_installed)
lm_mcnt = mcnt;
mcnt++;
+ if (lm->mod_init_size > 0) {
+ st->ext_module_symtable[mcnt].value = lm->mod_init_module_ptr;
+ st->ext_module_symtable[mcnt].type = 'm';
+ sprintf(buf3, "%s%s", "_MODULE_INIT_START_", mod_name);
+ namespace_ctl(NAMESPACE_INSTALL,
+ &st->ext_module_namespace,
+ &st->ext_module_symtable[mcnt], buf3);
+ lm_mcnt = mcnt;
+ mcnt++;
+ }
+
+
if (nsyms && !IN_MODULE(syms, lm)) {
error(WARNING,
"[%s] module.syms outside of module "
@@ -1520,6 +1561,16 @@ store_module_symbols_v2(ulong total, int mods_installed)
&st->ext_module_symtable[mcnt], buf2);
mcnt++;
+ if (lm->mod_init_size > 0) {
+ st->ext_module_symtable[mcnt].value = lm->mod_init_module_ptr +
lm->mod_init_size;
+ st->ext_module_symtable[mcnt].type = 'm';
+ sprintf(buf4, "%s%s", "_MODULE_INIT_END_", mod_name);
+ namespace_ctl(NAMESPACE_INSTALL,
+ &st->ext_module_namespace,
+ &st->ext_module_symtable[mcnt], buf4);
+ mcnt++;
+ }
+
lm->mod_ext_symcnt = mcnt - lm->mod_ext_symcnt;
if (!lm->mod_etext_guess)
@@ -1545,6 +1596,8 @@ store_module_symbols_v2(ulong total, int mods_installed)
lm = &st->load_modules[m];
sprintf(buf1, "_MODULE_START_%s", lm->mod_name);
sprintf(buf2, "_MODULE_END_%s", lm->mod_name);
+ sprintf(buf3, "_MODULE_INIT_START_%s", lm->mod_name);
+ sprintf(buf4, "_MODULE_INIT_END_%s", lm->mod_name);
for (sp = st->ext_module_symtable;
sp < st->ext_module_symend; sp++) {
@@ -1556,6 +1609,12 @@ store_module_symbols_v2(ulong total, int mods_installed)
lm->mod_ext_symend = sp;
lm->mod_symend = sp;
}
+ if (STREQ(sp->name, buf3)) {
+ lm->mod_init_symtable = sp;
+ }
+ if (STREQ(sp->name, buf4)) {
+ lm->mod_init_symend = sp;
+ }
}
}
@@ -1750,6 +1809,7 @@ store_module_kallsyms_v2(struct load_module *lm, int start, int
curr,
struct namespace *ns;
int mcnt;
int mcnt_idx;
+ char *module_buf_init = NULL;
if (!(kt->flags & KALLSYMS_V2))
return 0;
@@ -1772,30 +1832,50 @@ store_module_kallsyms_v2(struct load_module *lm, int start, int
curr,
return 0;
}
+ if (lm->mod_init_size > 0) {
+ module_buf_init = GETBUF(lm->mod_init_size);
+
+ if (!readmem(lm->mod_init_module_ptr, KVADDR, module_buf_init,
lm->mod_init_size,
+ "module init (kallsyms)", RETURN_ON_ERROR|QUIET)) {
+ error(WARNING,"cannot access module init kallsyms\n");
+ FREEBUF(module_buf_init);
+ }
+ }
+
if (THIS_KERNEL_VERSION >= LINUX(2,6,27))
nksyms = UINT(modbuf + OFFSET(module_num_symtab));
else
nksyms = ULONG(modbuf + OFFSET(module_num_symtab));
ksymtab = ULONG(modbuf + OFFSET(module_symtab));
- if (!IN_MODULE(ksymtab, lm)) {
+ if (!IN_MODULE(ksymtab, lm) && !IN_MODULE_INIT(ksymtab, lm)) {
error(WARNING,
"%s: module.symtab outside of module address space\n",
lm->mod_name);
FREEBUF(module_buf);
+ if (module_buf_init)
+ FREEBUF(module_buf_init);
return 0;
}
- locsymtab = module_buf + (ksymtab - lm->mod_base);
+ if (IN_MODULE(ksymtab, lm))
+ locsymtab = module_buf + (ksymtab - lm->mod_base);
+ else
+ locsymtab = module_buf_init + (ksymtab - lm->mod_init_module_ptr);
kstrtab = ULONG(modbuf + OFFSET(module_strtab));
- if (!IN_MODULE(kstrtab, lm)) {
+ if (!IN_MODULE(kstrtab, lm) && !IN_MODULE_INIT(kstrtab, lm)) {
error(WARNING,
"%s: module.strtab outside of module address space\n",
lm->mod_name);
FREEBUF(module_buf);
+ if (module_buf_init)
+ FREEBUF(module_buf_init);
return 0;
}
- locstrtab = module_buf + (kstrtab - lm->mod_base);
+ if (IN_MODULE(kstrtab, lm))
+ locstrtab = module_buf + (kstrtab - lm->mod_base);
+ else
+ locstrtab = module_buf_init + (kstrtab - lm->mod_init_module_ptr);
for (i = 1; i < nksyms; i++) { /* ELF starts real symbols at 1 */
switch (BITS())
@@ -1810,14 +1890,16 @@ 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)))
+ 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 (ec->st_shndx == SHN_UNDEF)
continue;
- if (!IN_MODULE(kstrtab + ec->st_name, lm)) {
+ if (!IN_MODULE(kstrtab + ec->st_name, lm) && !IN_MODULE_INIT(kstrtab +
ec->st_name, lm)) {
if (CRASHDEBUG(3)) {
error(WARNING,
"%s: bad st_name index: %lx -> %lx\n "
@@ -1869,6 +1951,8 @@ store_module_kallsyms_v2(struct load_module *lm, int start, int
curr,
lm->mod_flags |= MOD_KALLSYMS;
FREEBUF(module_buf);
+ if (module_buf_init)
+ FREEBUF(module_buf_init);
return mcnt;
}
@@ -2211,7 +2295,7 @@ is_kernel_text(ulong value)
for (i = 0; i < st->mods_installed; i++) {
lm = &st->load_modules[i];
- if (!IN_MODULE(value, lm))
+ if (!IN_MODULE(value, lm) && !IN_MODULE_INIT(value, lm))
continue;
if (lm->mod_flags & MOD_LOAD_SYMS) {
@@ -2233,10 +2317,15 @@ is_kernel_text(ulong value)
start = lm->mod_base + lm->mod_size_of_struct;
break;
case KMOD_V2:
- start = lm->mod_base;
+ if (IN_MODULE(value, lm))
+ start = lm->mod_base;
+ else
+ start = lm->mod_init_module_ptr;
break;
}
end = lm->mod_etext_guess;
+ if (IN_MODULE_INIT(value, lm) && end < lm->mod_init_module_ptr +
lm->mod_init_size)
+ end = lm->mod_init_module_ptr + lm->mod_init_size;
if ((value >= start) && (value < end))
return TRUE;
@@ -2524,6 +2613,8 @@ dump_symbol_table(void)
lm->mod_bss_start,
lm->mod_bss_start ?
lm->mod_bss_start - lm->mod_base : 0);
+ fprintf(fp, " mod_init_size: %ld\n",
+ lm->mod_init_size);
fprintf(fp, " mod_init_text_size: %ld\n",
lm->mod_init_text_size);
fprintf(fp, " mod_init_module_ptr: %lx\n",
@@ -3493,6 +3584,7 @@ module_symbol(ulong value,
long mcnt;
char buf[BUFSIZE];
ulong offs, offset;
+ ulong base, end;
if (NO_MODULES())
return FALSE;
@@ -3506,13 +3598,20 @@ module_symbol(ulong value,
for (i = 0; i < st->mods_installed; i++) {
lm = &st->load_modules[i];
- if ((value >= lm->mod_base) &&
- (value < (lm->mod_base + lm->mod_size))) {
+ if (IN_MODULE(value, lm)) {
+ base = lm->mod_base;
+ end = lm->mod_base + lm->mod_size;
+ } else {
+ base = lm->mod_init_module_ptr;
+ end = lm->mod_init_module_ptr + lm->mod_init_size;
+ }
+
+ if ((value >= base) && (value < end)) {
if (lmp)
*lmp = lm;
if (name) {
- offs = value - lm->mod_base;
+ offs = value - base;
if ((sp = value_search(value, &offset))) {
if (offset)
sprintf(buf, radix == 16 ?
@@ -3541,54 +3640,26 @@ module_symbol(ulong value,
return FALSE;
}
-/*
- * Return the syment of the symbol closest to the value, along with
- * the offset from the symbol value if requested.
- */
struct syment *
-value_search(ulong value, ulong *offset)
+value_search_module(ulong value, ulong *offset, int search_init_section)
{
int i;
struct syment *sp, *sp_end, *spnext, *splast;
struct load_module *lm;
- if (!in_ksymbol_range(value))
- return((struct syment *)NULL);
-
- if ((sp = machdep->value_to_symbol(value, offset)))
- return sp;
-
- if (IS_VMALLOC_ADDR(value))
- goto check_modules;
-
- if ((sp = symval_hash_search(value)) == NULL)
- sp = st->symtable;
-
- for ( ; sp < st->symend; sp++) {
- if (value == sp->value) {
-#ifdef GDB_7_0
- if (STRNEQ(sp->name, ".text.")) {
- spnext = sp+1;
- if (spnext->value == value)
- sp = spnext;
- }
-#endif
- if (offset)
- *offset = 0;
- return((struct syment *)sp);
- }
- if (sp->value > value) {
- if (offset)
- *offset = value - ((sp-1)->value);
- return((struct syment *)(sp-1));
- }
- }
-
-check_modules:
for (i = 0; i < st->mods_installed; i++) {
lm = &st->load_modules[i];
- sp = lm->mod_symtable;
- sp_end = lm->mod_symend;
+
+ if (!search_init_section) {
+ sp = lm->mod_symtable;
+ sp_end = lm->mod_symend;
+ } else {
+ if (lm->mod_init_symtable) {
+ sp = lm->mod_init_symtable;
+ sp_end = lm->mod_init_symend;
+ } else
+ continue;
+ }
if (sp->value > value) /* invalid -- between modules */
break;
@@ -3599,7 +3670,7 @@ check_modules:
* when they have unique values.
*/
splast = NULL;
- for ( ; sp < sp_end; sp++) {
+ for ( ; sp <= sp_end; sp++) {
if (value == sp->value) {
if (MODULE_START(sp)) {
spnext = sp+1;
@@ -3644,6 +3715,57 @@ check_modules:
return((struct syment *)NULL);
}
+/*
+ * Return the syment of the symbol closest to the value, along with
+ * the offset from the symbol value if requested.
+ */
+struct syment *
+value_search(ulong value, ulong *offset)
+{
+ int i;
+ struct syment *sp, *sp_end, *spnext, *splast;
+ struct load_module *lm;
+
+ if (!in_ksymbol_range(value))
+ return((struct syment *)NULL);
+
+ if ((sp = machdep->value_to_symbol(value, offset)))
+ return sp;
+
+ if (IS_VMALLOC_ADDR(value))
+ goto check_modules;
+
+ if ((sp = symval_hash_search(value)) == NULL)
+ sp = st->symtable;
+
+ for ( ; sp < st->symend; sp++) {
+ if (value == sp->value) {
+#ifdef GDB_7_0
+ if (STRNEQ(sp->name, ".text.")) {
+ spnext = sp+1;
+ if (spnext->value == value)
+ sp = spnext;
+ }
+#endif
+ if (offset)
+ *offset = 0;
+ return((struct syment *)sp);
+ }
+ if (sp->value > value) {
+ if (offset)
+ *offset = value - ((sp-1)->value);
+ return((struct syment *)(sp-1));
+ }
+ }
+
+check_modules:
+ sp = value_search_module(value, offset, 0);
+ if (!sp)
+ sp = value_search_module(value, offset, 1);
+
+ return sp;
+}
+
ulong
highest_bss_symbol(void)
{
@@ -6536,6 +6658,8 @@ dump_offset_table(char *spec, ulong makestruct)
OFFSET(module_core_size));
fprintf(fp, " module_core_text_size: %ld\n",
OFFSET(module_core_text_size));
+ fprintf(fp, " module_init_size: %ld\n",
+ OFFSET(module_init_size));
fprintf(fp, " module_init_text_size: %ld\n",
OFFSET(module_init_text_size));
fprintf(fp, " module_module_init: %ld\n",