Re: [Crash-utility] [PATCH] Also search module init section for symbols
by Dave Anderson
----- "Hu Tao" <hutao(a)cn.fujitsu.com> wrote:
> 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
In addition to the initial suggestions I had re: your patch, I made
several additions so that more functions than value_search() and
symbol_dump() would find the init symbols. With your patch, commands
like these still did not find the init symbols:
sym <symbol-name>
sym -q <string>
sym -n <symbol>
sym -p <symbol>
I'm running a sanity test now, and if all goes well, will issue a new
release shortly.
Thanks,
Dave
14 years, 1 month
Re: [Crash-utility] [PATCH] Also search module init section for symbols
by Dave Anderson
----- "Hu Tao" <hutao(a)cn.fujitsu.com> wrote:
> 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.
This is a pretty adventurous patch, but it looks pretty good.
Given that your new module init code is pretty much segregated based
upon the setting of lm->mod_init_size, it shouldn't break the handling
of normal "post-init" modules.
A few minor issues:
# touch symbols.c
# make warn
cc -c -g -DX86_64 symbols.c -DGDB_7_0 -I./gdb-7.0/bfd -I./gdb-7.0/include -Wall -O2 -Wstrict-prototypes -Wmissing-prototypes -fstack-protector -Wp,-D_FORTIFY_SOURCE=2
symbols.c:3651: warning: no previous prototype for ‘value_search_module’
symbols.c: In function ‘value_search’:
symbols.c:3734: warning: unused variable ‘lm’
symbols.c:3733: warning: unused variable ‘splast’
symbols.c:3733: warning: unused variable ‘sp_end’
symbols.c:3732: warning: unused variable ‘i’
#
Also, I'm wondering why you felt it necessary to make two
calls to the new value_search_module() function here in
value_search():
check_modules:
sp = value_search_module(value, offset, 0);
if (!sp)
sp = value_search_module(value, offset, 1);
What I would suggest is this:
(1) If during initialization it is seen that a module's init symbols are
still in place, then set a new "MOD_INIT" flag in lm->mod_flags.
(2) Then, if value_search_module() cannot find a symbol in the lm->mod_symtable,
it could check lm->mod_flags for the MOD_INIT flag, and then go back and
retry the search in the lm->mod_init_symtable.
If it were done that way, I can envision making value_search_module()
exportable, and it would not require the caller to make the "0/1" argument
decision.
Dave
>
> --
> 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",
14 years, 1 month
Re: [Crash-utility] [PATCH] ARM SMP
by Dave Anderson
----- "Mika Westerberg" <ext-mika.1.westerberg(a)nokia.com> wrote:
> Hi Per,
>
> On Thu, Sep 30, 2010 at 11:19:28AM +0200, ext Per Fransson wrote:
> >
> > This patch is an attempt to get the ball rolling on SMP support for ARM.
>
> I noticed that this patch is line-wrapped so it doesn't apply cleanly (or is it
> our brilliant exchange server which mangled that).
>
> Few questions, see below.
... [ cut ] ...
>
> > @@ -996,20 +1028,20 @@ arm_get_dumpfile_stack_frame(struct bt_info *bt, ulong *nip, ulong *ksp)
> > if (!ms->crash_task_regs)
> > return FALSE;
> >
> > - if (tt->panic_task != bt->task || bt->tc->pid != ms->crash_task_pid)
> > - return FALSE;
> > -
>
> Was there a reason to remove the check above? Is it so that when we have SMP
> machine, there is still only one panic'ing task?
Yes, there is still only one panic task.
> Anyway, if this this check is not needed anymore, I guess you can remove the
> whole variable from machspec structure.
Right -- in fact, in the patched arm_get_crash_notes() function, ms->crash_task_pid
gets set to whatever pid was running on the highest cpu -- whether it was the panic
task or not. But like you say, with the patch, it's become irrelevant anyway.
Dave
14 years, 1 month