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).
No, I ran into the same problem...
Also, I now note that this piece below is incorrect. GETBUF() buffers are
transitory, because they all get freed as soon as free_all_bufs() is called
next: (such as in restore_sanity() prior to each command)
> + panic_task_regs = GETBUF(kt->cpus*sizeof(*panic_task_regs));
> - ms->crash_task_regs = &panic_task_regs;
> + ms->crash_task_regs = panic_task_regs;
You'd have to use malloc() for the panic_task_regs assignment.
It looks like the other GETBUF() calls are for temporary buffers.
Dave
14 years, 2 months
[PATCH] ARM SMP
by Per Fransson
Hi Dave,
This patch is an attempt to get the ball rolling on SMP support for ARM.
Regards,
Per
diff --git a/arm.c b/arm.c
index 06b2f1c..bf346df 100644
--- a/arm.c
+++ b/arm.c
@@ -73,7 +73,7 @@ struct arm_cpu_context_save {
/*
* Holds registers during the crash.
*/
-static struct arm_pt_regs panic_task_regs;
+static struct arm_pt_regs *panic_task_regs;
#define PGDIR_SIZE() (4 * PAGESIZE())
#define PGDIR_OFFSET(X) (((ulong)(X)) & (PGDIR_SIZE() - 1))
@@ -484,71 +484,103 @@ arm_get_crash_notes(void)
Elf32_Nhdr *note;
ulong ptr, offset;
char *buf, *p;
+ ulong *notes_ptrs;
+ ulong per_cpu_offsets_addr;
+ ulong *per_cpu_offsets;
+ ulong i;
if (!symbol_exists("crash_notes"))
return FALSE;
crash_notes = symbol_value("crash_notes");
- if (kt->cpus > 1)
- error(WARNING, "only one CPU is currently supported\n");
+ notes_ptrs = GETBUF(kt->cpus*sizeof(notes_ptrs[0]));
/*
* Read crash_notes for the first CPU. crash_notes are in standard ELF
* note format.
*/
- if (!readmem(crash_notes, KVADDR, &ptr, sizeof(ptr), "crash_notes",
+ if (!readmem(crash_notes, KVADDR, ¬es_ptrs[kt->cpus-1],
sizeof(notes_ptrs[kt->cpus-1]), "crash_notes",
RETURN_ON_ERROR)) {
- error(WARNING, "cannot read crash_notes\n");
+ error(WARNING, "cannot read crash_notes\n");
+ return FALSE;
+ }
+
+
+ if (symbol_exists("__per_cpu_offset")) {
+
+ /* Get the __per_cpu_offset array */
+ per_cpu_offsets_addr = symbol_value("__per_cpu_offset");
+
+ per_cpu_offsets = GETBUF(kt->cpus*sizeof(*per_cpu_offsets));
+
+ if (!readmem(per_cpu_offsets_addr, KVADDR, per_cpu_offsets,
kt->cpus*sizeof(*per_cpu_offsets), "per_cpu_offsets",
+ RETURN_ON_ERROR)) {
+ error(WARNING, "cannot read per_cpu_offsets\n");
return FALSE;
+ }
+
+ /* Add __per_cpu_offset for each cpu to form the pointer to the notes */
+ for (i = 0; i<kt->cpus; i++) {
+ notes_ptrs[i] = notes_ptrs[kt->cpus-1] + per_cpu_offsets[i];
+ }
+ FREEBUF(per_cpu_offsets);
}
buf = GETBUF(SIZE(note_buf));
+ panic_task_regs = GETBUF(kt->cpus*sizeof(*panic_task_regs));
+
+ for (i=0;i<kt->cpus;i++) {
- if (!readmem(ptr, KVADDR, buf, SIZE(note_buf), "note_buf_t",
- RETURN_ON_ERROR)) {
+ if (!readmem(notes_ptrs[i], KVADDR, buf, SIZE(note_buf), "note_buf_t",
+ RETURN_ON_ERROR)) {
error(WARNING, "failed to read note_buf_t\n");
goto fail;
- }
+ }
- /*
- * Do some sanity checks for this note before reading registers from it.
- */
- note = (Elf32_Nhdr *)buf;
- p = buf + sizeof(Elf32_Nhdr);
+ /*
+ * Do some sanity checks for this note before reading registers from it.
+ */
+ note = (Elf32_Nhdr *)buf;
+ p = buf + sizeof(Elf32_Nhdr);
- if (note->n_type != NT_PRSTATUS) {
+ if (note->n_type != NT_PRSTATUS) {
error(WARNING, "invalid note (n_type != NT_PRSTATUS)\n");
goto fail;
- }
- if (p[0] != 'C' || p[1] != 'O' || p[2] != 'R' || p[3] != 'E') {
+ }
+ if (p[0] != 'C' || p[1] != 'O' || p[2] != 'R' || p[3] != 'E') {
error(WARNING, "invalid note (name != \"CORE\"\n");
goto fail;
- }
+ }
- /*
- * Find correct location of note data. This contains elf_prstatus
- * structure which has registers etc. for the crashed task.
- */
- offset = sizeof(Elf32_Nhdr);
- offset = roundup(offset + note->n_namesz, 4);
- p = buf + offset; /* start of elf_prstatus */
+ /*
+ * Find correct location of note data. This contains elf_prstatus
+ * structure which has registers etc. for the crashed task.
+ */
+ offset = sizeof(Elf32_Nhdr);
+ offset = roundup(offset + note->n_namesz, 4);
+ p = buf + offset; /* start of elf_prstatus */
- BCOPY(p + OFFSET(elf_prstatus_pr_reg), &panic_task_regs,
- sizeof(panic_task_regs));
+ BCOPY(p + OFFSET(elf_prstatus_pr_reg), &panic_task_regs[i],
+ sizeof(panic_task_regs[i]));
+
+ }
/*
* And finally we have pid and registers for the crashed task. This is
* used later on when dumping backtrace.
*/
ms->crash_task_pid = *(ulong *)(p + OFFSET(elf_prstatus_pr_pid));
- ms->crash_task_regs = &panic_task_regs;
+ ms->crash_task_regs = panic_task_regs;
FREEBUF(buf);
+ FREEBUF(notes_ptrs);
return TRUE;
fail:
FREEBUF(buf);
+ FREEBUF(notes_ptrs);
+ FREEBUF(panic_task_regs);
return FALSE;
}
@@ -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;
-
+ if (!is_task_active(bt->task))
+ return FALSE;
+
/*
* We got registers for panic task from crash_notes. Just return them.
*/
- *nip = ms->crash_task_regs->ARM_pc;
- *ksp = ms->crash_task_regs->ARM_sp;
+ *nip = ms->crash_task_regs[bt->tc->processor].ARM_pc;
+ *ksp = ms->crash_task_regs[bt->tc->processor].ARM_sp;
/*
* Also store pointer to all registers in case unwinding code needs
* to access LR.
*/
- bt->machdep = ms->crash_task_regs;
+ bt->machdep = &(ms->crash_task_regs[bt->tc->processor]);
return TRUE;
}
diff --git a/defs.h b/defs.h
index d431d6e..8a2291a 100755
--- a/defs.h
+++ b/defs.h
@@ -85,7 +85,7 @@
#define NR_CPUS (64)
#endif
#ifdef ARM
-#define NR_CPUS (1)
+#define NR_CPUS (4)
#endif
#define BUFSIZE (1500)
14 years, 2 months
[PATCH] Also search module init section for symbols
by Hu Tao
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",
14 years, 2 months
Re: [Crash-utility] minor bug in get_text_init_space
by Dave Anderson
----- "Per Fransson" <perr.fransson.ml(a)gmail.com> wrote:
> Hi,
>
> I believe the ARM support introduced a minor issue in the function
> get_text_init_space(). As it stands, the error "cannot determine text
> init space" can only occur when machine_type("ARM") is true. Here a
> suggested fix.
>
> Regards,
> Per
Definitely a bug -- thanks for catching that.
I remember looking at that ARM-support patch submission and thinking
that for maintainability/sanity purposes it should probably just be
separated out entirely for ARM.
Thanks again,
Dave
>
> --- a/symbols.c
> +++ b/symbols.c
> @@ -491,9 +491,9 @@ get_text_init_space(void)
>
> if (((section = get_kernel_section(".text.init")) == NULL) &&
> ((section = get_kernel_section(".init.text")) == NULL) &&
> - (machine_type("ARM") && (section = get_kernel_section(".init")) == NULL)) {
> - error(WARNING, "cannot determine text init space\n");
> - return;
> + !(machine_type("ARM") && (section = get_kernel_section(".init")) != NULL)) {
> + error(WARNING, "cannot determine text init space\n");
> + return;
> }
>
> kt->stext_init = (ulong)bfd_get_section_vma(st->bfd, section);
>
> --
> Crash-utility mailing list
> Crash-utility(a)redhat.com
> https://www.redhat.com/mailman/listinfo/crash-utility
14 years, 2 months
minor bug in get_text_init_space
by Per Fransson
Hi,
I believe the ARM support introduced a minor issue in the function
get_text_init_space(). As it stands, the error "cannot determine text
init space" can only occur when machine_type("ARM") is true. Here a
suggested fix.
Regards,
Per
--- a/symbols.c
+++ b/symbols.c
@@ -491,9 +491,9 @@ get_text_init_space(void)
if (((section = get_kernel_section(".text.init")) == NULL) &&
((section = get_kernel_section(".init.text")) == NULL) &&
- (machine_type("ARM") && (section =
get_kernel_section(".init")) == NULL)) {
- error(WARNING, "cannot determine text init space\n");
- return;
+ !(machine_type("ARM") && (section =
get_kernel_section(".init")) != NULL)) {
+ error(WARNING, "cannot determine text init space\n");
+ return;
}
kt->stext_init = (ulong)bfd_get_section_vma(st->bfd, section);
14 years, 2 months
[PATCH] s390dbf: Fix reading of 64 bit pointers
by Michael Holzheu
Hello Dave,
Currently the s390dbf command uses KL_UINT() for reading pointers. This
works only if the pointers are below 4 GiB. To fix this issue I now use
a new KL_ULONG() function for reading pointers correctly.
Michael
---
s390dbf.c | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
--- a/s390dbf.c
+++ b/s390dbf.c
@@ -139,9 +139,10 @@ static inline void* K_PTR(void* addr, ch
return addr+MEMBER_OFFSET(struct_name,member_name);
}
-static inline uint32_t KL_UINT(void* ptr, char* struct_name, char* member_name)
+static inline unsigned long KL_ULONG(void* ptr, char* struct_name, char*
+ member_name)
{
- return (uint32_t) ULONG(ptr+MEMBER_OFFSET(struct_name,member_name));
+ return ULONG(ptr+MEMBER_OFFSET(struct_name,member_name));
}
static inline uint32_t KL_VREAD_UINT32(kaddr_t addr)
@@ -900,7 +901,7 @@ debug_get_areas_v1(debug_info_t* db_info
area_size = PAGE_SIZE << db_info->page_order;
db_info->areas = (void**)malloc(db_info->nr_areas * sizeof(void *));
memset(db_info->areas, 0, db_info->nr_areas * sizeof(void *));
- mem_pos = (kaddr_t) KL_UINT(k_dbi,"debug_info","areas");
+ mem_pos = KL_ULONG(k_dbi,"debug_info","areas");
for (i = 0; i < db_info->nr_areas; i++) {
dbe_addr = KL_VREAD_PTR(mem_pos);
db_info->areas[i] = (debug_entry_t *) malloc(area_size);
@@ -918,7 +919,7 @@ debug_get_areas_v2(debug_info_t* db_info
kaddr_t page_ptr;
int i,j;
db_info->areas_v2=(void***)malloc(db_info->nr_areas * sizeof(void **));
- area_ptr = (kaddr_t) KL_UINT(k_dbi,"debug_info","areas");
+ area_ptr = KL_ULONG(k_dbi,"debug_info","areas");
for (i = 0; i < db_info->nr_areas; i++) {
db_info->areas_v2[i] = (void**)malloc(db_info->pages_per_area_v2
* sizeof(void*));
@@ -970,8 +971,8 @@ get_debug_info(kaddr_t addr,int get_area
db_info->page_order = KL_INT(k_dbi,"debug_info","page_order");
db_info->buf_size = KL_INT(k_dbi,"debug_info","buf_size");
db_info->entry_size = KL_INT(k_dbi,"debug_info","entry_size");
- db_info->next_dbi = KL_UINT(k_dbi,"debug_info","next");
- db_info->prev_dbi = KL_UINT(k_dbi,"debug_info","prev");
+ db_info->next_dbi = KL_ULONG(k_dbi,"debug_info","next");
+ db_info->prev_dbi = KL_ULONG(k_dbi,"debug_info","prev");
db_info->addr = addr;
strncpy(db_info->name,K_PTR(k_dbi,"debug_info","name"),
DEBUG_MAX_PROCF_LEN);
14 years, 2 months
Re: [Crash-utility] Question on online/present/possible CPUS
by Dave Anderson
----- "Dave Anderson" <anderson(a)redhat.com> wrote:
> ----- "Jeffrey Hagen" <Jeffrey.Hagen(a)teradata.com> wrote:
>
> > Paranoia is usually a good thing in this industry and you know this code
> > far better that I do...
> >
> > For the older kernels that don't have cpu_present_map, if they still
> > have the x8664_pda structure, the code my patch changes shouldn't get
> > executed. It's the deprecation of the x8664_pda structure (between
> > SLES10 and SLES11 in our case) that exposes this issue.
>
> True...
>
> >
> > The setting of the other CPU's to offline (IPI REBOOT_VECTOR) is done in
> > native_smp_send_stop [arch/x86/kernel/smp.c] called by panic(). Note
> > that the SLES11 version of the 2.6.32 kernel allows calling
> > crash_kexec() after calling atomic_notifer_call_chain() in panic().
>
> Ah-ha! That makes sense -- I was under the impression that all of the
> other distros would follow upstream with crash_kexec() being called
> before, and therefore preventing, the subsequent smp_send_stop() call.
>
> So given that this would happen whenever panic() gets called directly
> in a SLES kernel, is the SLES version of the crash utility patched to do
> something similar to your patch?
>
> Petr?
>
> > The flow during an oops or keyboard induced crash does not use this same
> > code. In this case crash_kexec() is called by oops_end() which is
> > called by die().
>
> OK, I'm going to give your patch a run-through with ~150 or so x86_64
> dumpfiles I've kept as examples over the years, and see if anything
> interesting happens.
Hi Jeff,
Nothing interest happened -- so unless I hear anything to the contrary
from the SUSE maintainers, I'm queueing your patch for the next release.
Thanks,
Dave
14 years, 2 months
Re: [Crash-utility] Question on online/present/possible CPUS
by Dave Anderson
----- "Jeffrey Hagen" <Jeffrey.Hagen(a)teradata.com> wrote:
> Paranoia is usually a good thing in this industry and you know this code
> far better that I do...
>
> For the older kernels that don't have cpu_present_map, if they still
> have the x8664_pda structure, the code my patch changes shouldn't get
> executed. It's the deprecation of the x8664_pda structure (between
> SLES10 and SLES11 in our case) that exposes this issue.
True...
>
> The setting of the other CPU's to offline (IPI REBOOT_VECTOR) is done in
> native_smp_send_stop [arch/x86/kernel/smp.c] called by panic(). Note
> that the SLES11 version of the 2.6.32 kernel allows calling
> crash_kexec() after calling atomic_notifer_call_chain() in panic().
Ah-ha! That makes sense -- I was under the impression that all of the
other distros would follow upstream with crash_kexec() being called
before, and therefore preventing, the subsequent smp_send_stop() call.
So given that this would happen whenever panic() gets called directly
in a SLES kernel, is the SLES version of the crash utility patched to do
something similar to your patch?
Petr?
> The flow during an oops or keyboard induced crash does not use this same
> code. In this case crash_kexec() is called by oops_end() which is
> called by die().
OK, I'm going to give your patch a run-through with ~150 or so x86_64
dumpfiles I've kept as examples over the years, and see if anything
interesting happens.
Thanks Jeff,
Dave
14 years, 2 months
Re: [Crash-utility] Question on online/present/possible CPUS
by Dave Anderson
----- "Jeffrey Hagen" <Jeffrey.Hagen(a)teradata.com> wrote:
> Hi Dave,
>
> Attached is our suggested patch for the issue with CPU count in
> an NMI switch induced coredump. Basically the change uses the
> cpu_present_mask instead of the cpu_online_mask in x86_64_per_cpu_init
> and x86_64_get_smp_cpus.
I understand why you need to do it that way, but to make a change like
this makes me a little nervous because nobody's ever reported this
situation before, and I'm somewhat paranoid it may lead to unexpected
behavior. Plus there are old kernels that don't even have a cpu_present_map.
> In answer to your question below: "Are you saying that the NMI
> switch shutdown handler takes the other cpus offline?" --- Yes!!
Where exactly? Can you point me to the kernel code that does that?
Dave
>
> Thanks,
>
> Jeff
>
>
> -----Original Message-----
> From: crash-utility-bounces(a)redhat.com
> [mailto:crash-utility-bounces@redhat.com] On Behalf Of Dave Anderson
> Sent: Thursday, August 12, 2010 6:22 AM
> To: Discussion list for crash utility usage,maintenance and
> development
> Subject: Re: [Crash-utility] Question on online/present/possible CPUS
>
>
> ----- "Jeffrey Hagen" <Jeffrey.Hagen(a)teradata.com> wrote:
>
> > Hi Petr and Dave,
> >
> > I have a couple of comments on Petr's email regarding CPU count.
> >
> > When the dump is the result of an NMI (nmi switch pressed) due to a
> hung
> > system, one often needs to analyze the state and backtrace for all
> the
> > CPU's. Since the kernel halts all but CPU0, the crash utility
> cannot
> > see the other "offline" CPU's.
>
> I've never seen that behavior before. Probably because I've never
> seen
> an x86_64 dumpfile that was created as a result of the NMI switch
> being
> pressed? Anyway, are you saying that the NMI switch shutdown handler
>
> takes the other cpus offline?
>
> > This behavior has changed for the x86 architecture somewhere
> between
> > 2.6.16 (SLES10) and 2.6.32 (SLES11) due to the removal of the
> x8664_pda
> > structure.
> > The function x86_64_init (in x86_64.c) now calls
> x86_64_per_cpu_init
> > which doesn't count the offline CPUS when calculating the number of
> > CPU's. Previously, x86_64_cpu_pda_init (called if x8664_pda
> exists),
> > didn't check for online/offline status.
>
> Again -- I've never seen this behaviour before.
>
> In any case, I'll look at any patch suggestions you guys have in
> mind.
>
> Thanks,
> Dave
>
>
> > Regarding #3 in Petr's email. It appears that the set command
> won't
> > accept a value >= kt_cpus (number of CPUS). It doesn't check if
> the
> CPU
> > is offline or not.
> >
> > Thanks,
> >
> > Jeff Hagen
> >
> >
> >
> > >
> > > Hi all,
> > >
> > > before making a larger cleanup, I want to ask here for your
> > opinion.
> > It
> > > seems that there is quite a bit of confusion about the meaning of
> > CPU
> > > count printed out by the crash utility.
> > >
> > > 1. Number of CPUs
> > >
> > > Some people think that crash should always output the number of
> > CPUs
> > in
> > > the system (ie. a quad-core server should always output 'CPUS:
> 4'),
> > > while other people think that only online CPUs should be counted.
> > >
> > > 2. CPU numbering
> > >
> > > For example, if there are 4 CPUs in the system, but some of them
> > are
> > > taken offline (e.g. CPU 1 and CPU 3), _and_ crash output the
> number
> > of
> > > online CPUs, it would print out 'CPUS: 2'. It's not easy to find
> > out
> > > that valid CPU numbers are 0 and 2 in this case.
> >
> > Hi Petr,
> >
> > For all but ppc64, the number shown by the initial banner and the
> > "sys" command is essentially "the-highest-cpu-number-plus-one".
> > For ppc64 (as requested and implemented by the IBM/ppc64
> > maintainers),
> > it shows the number of online cpus. There's reasons for doing it
> > either of the two ways, but I'm on vacation now, and you can
> research
> > the list archives for the various arguments for-and-against doing
> it
> > either way. Check the changelog.html for when it was changed for
> > ppc64, and then cross-reference the revision date with the list
> > archives.
> >
> > > 3. Examining offline CPU
> > >
> > > Sometimes, it may be useful to examine the state of an offline
> CPU.
> > Now,
> > > I know that the saved state is most likely stale, but it can be
> > useful
> > > in some cases (e.g. a crash after dropping to kdb). The crash
> > utility
> > > currently refuses to select an offline CPU with 'set -c #'. Are
> > there
> > > any concerns about allowing it?
> >
> > I tend to agree with you, but the only thing that's useful and
> > available from an offline cpu is the swapper task for that cpu
> > and the runqueue for that cpu. And both of those entities are
> > readily accessible if you really need them. Although I don't know
> > anything about kdb status, so maybe there's something of per-cpu
> > interest, but I don't know why it would be necessary to "set"
> > that cpu?
> >
> > In any case, like I said before, I'm just temporarily online while
> > on vacation, and will be back to work on the 9th.
> >
> > Thanks,
> > Dave
> >
> > --
> > Crash-utility mailing list
> > Crash-utility(a)redhat.com
> > https://www.redhat.com/mailman/listinfo/crash-utility
>
> --
> Crash-utility mailing list
> Crash-utility(a)redhat.com
> https://www.redhat.com/mailman/listinfo/crash-utility
>
> --
> Crash-utility mailing list
> Crash-utility(a)redhat.com
> https://www.redhat.com/mailman/listinfo/crash-utility
14 years, 2 months