Hi Dave, When a percpu symbol is of type pointer, the 'struct' command does not generate the expected output. For example: Note: The correct value of 'exec_start' should be 0x15b070b28b0c27 not 0x0 crash> struct task_struct.se.exec_start softlockup_watchdog:0 [0]: ffff880214e55a00 se.exec_start = 0x0, crash> px softlockup_watchdog:0-1 per_cpu(softlockup_watchdog, 0) = $1 = (struct task_struct *) 0xffff880fe97e2e00 crash> px ((struct task_struct *)0xffff880fe97e2e00)->se.exec_start $2 = 0x15b070b28b0c27 Currently, the 'struct' and 'p' command simply calculates 'cpuaddr' as follows -- where 'addr' is a percpu's value: cpuaddr = addr + __per_cpu_offset This is correct if the percpu symbol or offset (i.e. [percpu symbol:cpu-specifier] or [percpu value:cpu-specifier]) is not of type pointer. If a given percpu symbol is of type pointer such as in 'static DEFINE_PER_CPU(struct task_struct *, softlockup_watchdog)', we need to dereference the pointer to obtain the above correct kernel virtual address. For instance, using the above example, we need to pass the following to gdb to resolve appropriately: kernel virtual addresses for the cpus specified. crash> set gdb on gdb: on gdb> p *(struct task_struct **) 0xffff880fffc0ddc0 $1 = (struct task_struct *) 0xffff880fe97e2e00 gdb> With this patch, we now obtain the expected output: crash> struct task_struct.se.exec_start softlockup_watchdog:0 [0]: ffff880214e55a00 se.exec_start = 0x15b070b28b0c27, In short, this patch does the following: 1. Fix the handling of a percpu symbol which are of type pointer 2. The 'struct' and 'p' command is now able to correctly handle a percpu symbol's value for example: Note: we show the address of the percpu object irrespective of data type crash> p f738 PER-CPU DATA TYPE: struct task_struct *softlockup_watchdog; PER-CPU ADDRESSES: [0]: ffff88021e20f738 [1]: ffff88021e24f738 [2]: ffff88021e28f738 [3]: ffff88021e2cf738 crash> p f738:a per_cpu(softlockup_watchdog, 0) = $5 = (struct task_struct *) 0xffff880214e55a00 per_cpu(softlockup_watchdog, 1) = $6 = (struct task_struct *) 0xffff88021498da00 per_cpu(softlockup_watchdog, 2) = $7 = (struct task_struct *) 0xffff8802149c3c00 per_cpu(softlockup_watchdog, 3) = $8 = (struct task_struct *) 0xffff880214b39e00 crash> struct task_struct.se.cfs_rq f738:a [0]: ffff880214e55a00 se.cfs_rq = 0xffff88021e216e78, [1]: ffff88021498da00 se.cfs_rq = 0xffff88021e256e78, [2]: ffff8802149c3c00 se.cfs_rq = 0xffff88021e296e78, [3]: ffff880214b39e00 se.cfs_rq = 0xffff88021e2d6e78, Signed-off-by: Aaron Tomlin <atomlin@xxxxxxxxxx> --- symbols.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 82 insertions(+), 14 deletions(-) diff --git a/symbols.c b/symbols.c index 51d41d8..0ded35d 100644 --- a/symbols.c +++ b/symbols.c @@ -76,8 +76,11 @@ static void cmd_datatype_common(ulong); static void do_datatype_addr(struct datatype_member *, ulong, int, ulong, char **, int); static void process_gdb_output(char *, unsigned, const char *, int); +static char *expr_type_name(const char *); static int display_per_cpu_info(struct syment *, int, char *); static struct load_module *get_module_percpu_sym_owner(struct syment *); +static struct syment *__per_cpu_symbol_search(char *); +static struct syment *per_cpu_symbol_value_search(ulong); static int is_percpu_symbol(struct syment *); static void dump_percpu_symbols(struct load_module *); static void print_struct_with_dereference(ulong, struct datatype_member *, ulong); @@ -5119,17 +5122,8 @@ symbol_exists(char *symbol) return(FALSE); } -/* - * Determine whether a per-cpu symbol exists. - - * The old-style per-cpu symbol names were pre-pended with - * "per_cpu__", whereas the new-style ones (as of 2.6.34) - * are not. This function allows the symbol argument to - * use either the old- or new-sytle format, and find either - * type. - */ struct syment * -per_cpu_symbol_search(char *symbol) +__per_cpu_symbol_search(char *symbol) { struct syment *sp; char old[BUFSIZE]; @@ -5164,6 +5158,37 @@ per_cpu_symbol_search(char *symbol) } /* + * Determine whether a per-cpu symbol exists. + + * The old-style per-cpu symbol names were pre-pended with + * "per_cpu__", whereas the new-style ones (as of 2.6.34) + * are not. This function allows the symbol argument to + * use either the old- or new-sytle format, and find either + * type. + */ +struct syment * +per_cpu_symbol_search(char *symbol) +{ + struct syment *sp; + return sp = __per_cpu_symbol_search(symbol); +} + +struct syment * +per_cpu_symbol_value_search(ulong value) +{ + struct syment *sp; + + if ((sp = symval_hash_search(value)) == NULL) + sp = st->symtable; + + for (; sp < st->symend; sp++) + if (value == sp->value) + return sp = __per_cpu_symbol_search(sp->name); + + return NULL; +} + +/* * Determine whether a static kernel symbol exists. */ int @@ -5987,12 +6012,17 @@ cmd_datatype_common(ulong flags) ulong list_head_offset; int count; int argc_members; + int ptype; int optind_save; unsigned int radix, restore_radix; struct datatype_member datatype_member, *dm; - char *separator; - char *structname, *members; - char *memberlist[MAXARGS]; + char *separator; + char *structname, *members; + char *memberlist[MAXARGS]; + char *typename; + char buf[BUFSIZE]; + char *argv[MAXARGS]; + FILE *tmpfp; dm = &datatype_member; count = 0xdeadbeef; @@ -6000,9 +6030,11 @@ cmd_datatype_common(ulong flags) list_head_offset = 0; argc_members = 0; radix = restore_radix = 0; + ptype = 0; separator = members = NULL; cpuspec = NULL; cpus = NULL; + typename = NULL; while ((c = getopt(argcnt, args, "pxdhfuc:rvol:")) != EOF) { switch (c) @@ -6104,6 +6136,10 @@ cmd_datatype_common(ulong flags) if (pc->curcmd_flags & MEMTYPE_FILEADDR) error(FATAL, "-f option cannot be used with percpu\n"); addr = htol(args[optind], FAULT_ON_ERROR, NULL); + if (!(sp = per_cpu_symbol_value_search(addr))) + error(FATAL, + "invalid percpu symbol value: %s\n", + args[optind]); aflag++; } else { if (pc->curcmd_flags & MEMTYPE_FILEADDR) @@ -6138,6 +6174,7 @@ cmd_datatype_common(ulong flags) } if (cpuspec) { + typename = expr_type_name(sp->name); cpus = get_cpumask_buf(); if (STREQ(cpuspec, "")) SET_BIT(cpus, CURRENT_CONTEXT()->processor); @@ -6212,6 +6249,8 @@ cmd_datatype_common(ulong flags) dm->name, memberlist[0]); do_datatype_declaration(dm, flags | (dm->flags & TYPEDEF)); } else if (cpus) { + if (typename && (ptype = (LASTCHAR(typename) == '*'))) + open_tmpfile2(); for (c = 0; c < kt->cpus; c++) { ulong cpuaddr; @@ -6227,9 +6266,25 @@ cmd_datatype_common(ulong flags) continue; } + if (ptype) { + snprintf(buf, sizeof buf, "p *(%s*) 0x%lx", + typename, cpuaddr); + gdb_pass_through(buf, pc->tmpfile2, GNU_RETURN_ON_ERROR); + + rewind(pc->tmpfile2); + fgets(buf, BUFSIZE, pc->tmpfile2); + parse_line(buf, argv); + cpuaddr = htol(argv[3], FAULT_ON_ERROR, NULL); + rewind(pc->tmpfile2); + tmpfp = pc->tmpfile2; + pc->tmpfile2 = NULL; + } fprintf(fp, "%lx\n", cpuaddr); + do_datatype_addr(dm, cpuaddr , count, flags, memberlist, argc_members); + if (ptype) + set_tmpfile2(tmpfp); } } else do_datatype_addr(dm, addr, count, flags, @@ -6237,6 +6292,9 @@ cmd_datatype_common(ulong flags) restore_current_radix(restore_radix); + if (ptype) + close_tmpfile2(); + freebuf: if (argc_members) { FREEBUF(structname); @@ -6245,6 +6303,9 @@ freebuf: if (cpus) FREEBUF(cpus); + + if (typename) + FREEBUF(typename); } static void @@ -6773,7 +6834,14 @@ cmd_p(void) if (cpuspec) *cpuspec++ = NULLCHAR; - sp = NULL; + if (hexadecimal(args[optind], 0)) { + if ((sp = per_cpu_symbol_value_search(htol(args[optind], + FAULT_ON_ERROR, NULL)))) { + display_per_cpu_info(sp, radix, cpuspec); + return; + } + } else + sp = NULL; if ((sp = symbol_search(args[optind])) && !args[optind+1]) { if ((percpu_sp = per_cpu_symbol_search(args[optind])) && display_per_cpu_info(percpu_sp, radix, cpuspec)) -- 2.5.5 -- Crash-utility mailing list Crash-utility@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/crash-utility