From eb71177e77771cd6698f62185f79f26f595b39ec Mon Sep 17 00:00:00 2001 From: Lei Wen Date: Sat, 20 Oct 2012 22:48:39 +0800 Subject: [PATCH] BT: show out param and local name and value when do bt Add new -c and -C flag to do this task. While -c would only display the function param and its value during backtrace, -C option would display extra local variable info. Signed-off-by: Lei Wen --- arm.c | 14 ++++ defs.h | 3 + gdb-7.3.1.patch | 178 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ gdb_interface.c | 3 + help.c | 31 ++++++++++ kernel.c | 36 +++++++++++- 6 files changed, 264 insertions(+), 1 deletions(-) diff --git a/arm.c b/arm.c index 45658dc..2516d11 100644 --- a/arm.c +++ b/arm.c @@ -73,6 +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 normal_task; #define PGDIR_SIZE() (4 * PAGESIZE()) #define PGDIR_OFFSET(X) (((ulong)(X)) & (PGDIR_SIZE() - 1)) @@ -1083,6 +1084,7 @@ static int arm_get_frame(struct bt_info *bt, ulong *pcp, ulong *spp) { const char *cpu_context; + unsigned int i; if (!bt->tc || !(tt->flags & THREAD_INFO)) return FALSE; @@ -1095,6 +1097,18 @@ arm_get_frame(struct bt_info *bt, ulong *pcp, ulong *spp) cpu_context = tt->thread_info + OFFSET(thread_info_cpu_context); + /* + * At context switch, ARM would store {r4 - sl, fp, sp, pc} + * in the thread_info structure + */ + bt->machdep = &normal_task; + memset(&normal_task, 0, sizeof(&normal_task)); + for (i = 0; i <= 7; i ++) + normal_task.uregs[i + 4] = + *(unsigned int *)(cpu_context + i * 4); + normal_task.uregs[13] = *(unsigned int *)(cpu_context + i * 4); + normal_task.uregs[15] = *(unsigned int *)(cpu_context + (i + 1) * 4); + #define GET_REG(ptr, cp, off) ((*ptr) = (*((ulong *)((cp) + OFFSET(off))))) /* * Unwinding code needs FP value also so we pass it with bt. diff --git a/defs.h b/defs.h index 319584f..90a5f27 100755 --- a/defs.h +++ b/defs.h @@ -3611,6 +3611,7 @@ struct gnu_request { #define GNU_GET_SYMBOL_TYPE (15) #define GNU_USER_PRINT_OPTION (16) #define GNU_SET_CRASH_BLOCK (17) +#define GNU_DIS_FUNC_UNWIND (18) #define GNU_DEBUG_COMMAND (100) /* * GNU flags @@ -4464,6 +4465,8 @@ ulong cpu_map_addr(const char *type); #define BT_KDUMP_ELF_REGS (0x80000000000ULL) #define BT_USER_SPACE (0x100000000000ULL) #define BT_KERNEL_SPACE (0x200000000000ULL) +#define BT_SHOW_PARAM (0x400000000000ULL) +#define BT_SHOW_VAR (0x800000000000ULL) #define BT_SYMBOL_OFFSET (BT_SYMBOLIC_ARGS) #define BT_REF_HEXVAL (0x1) diff --git a/gdb-7.3.1.patch b/gdb-7.3.1.patch index efcade6..222f1c9 100644 --- a/gdb-7.3.1.patch +++ b/gdb-7.3.1.patch @@ -1791,3 +1791,181 @@ diff -up gdb-7.3.1/gdb/psymtab.c.orig gdb-7.3.1/gdb/psymtab.c /* Free an entire objalloc structure. */ extern void objalloc_free (struct objalloc *); +--- gdb-7.3.1/gdb/stack.c ++++ gdb-7.3.1/gdb/stack.c +@@ -66,8 +66,6 @@ static const char *print_frame_arguments = "scalars"; + + /* Prototypes for local functions. */ + +-static void print_frame_local_vars (struct frame_info *, int, +- struct ui_file *); + + static void print_frame (struct frame_info *frame, int print_level, + enum print_what print_what, int print_args, +@@ -1623,7 +1621,7 @@ do_print_variable_and_value (const char *print_name, + p->values_printed = 1; + } + +-static void ++void + print_frame_local_vars (struct frame_info *frame, int num_tabs, + struct ui_file *stream) + { +diff --git a/gdb/stack.h b/gdb/stack.h +index 3cce623..85afd0f 100644 +--- gdb-7.3.1/gdb/stack.h ++++ gdb-7.3.1/gdb/stack.h +@@ -22,6 +22,8 @@ + #define STACK_H + + void select_frame_command (char *level_exp, int from_tty); ++void print_frame_local_vars (struct frame_info *frame, int num_tabs, ++ struct ui_file *stream); + + void find_frame_funname (struct frame_info *frame, char **funname, + enum language *funlang, struct symbol **funcp); +diff --git a/gdb/symtab.c b/gdb/symtab.c +index 5b9b8d4..a29b8ae 100644 +--- gdb-7.3.1/gdb/symtab.c ++++ gdb-7.3.1/gdb/symtab.c +@@ -4848,6 +4848,7 @@ static void gdb_get_symbol_type(struct gnu_request *); + static void gdb_command_exists(struct gnu_request *); + static void gdb_debug_command(struct gnu_request *); + static void gdb_function_numargs(struct gnu_request *); ++static void gdb_dis_func_unwind(struct gnu_request *); + static void gdb_add_symbol_file(struct gnu_request *); + static void gdb_delete_symbol_file(struct gnu_request *); + static void gdb_patch_symbol_values(struct gnu_request *); +@@ -4940,6 +4941,10 @@ gdb_command_funnel(struct gnu_request *req) + gdb_function_numargs(req); + break; + ++ case GNU_DIS_FUNC_UNWIND: ++ gdb_dis_func_unwind(req); ++ break; ++ + case GNU_DEBUG_COMMAND: + gdb_debug_command(req); + break; +@@ -5243,6 +5248,103 @@ gdb_function_numargs(struct gnu_request *req) + req->value = (ulong)TYPE_NFIELDS(sym->type); + } + ++struct arm_pt_regs { ++ ulong uregs[18]; ++}; ++#define INT_REGISTER_SIZE 4 ++enum gdb_regnum { ++ ARM_A1_REGNUM = 0, /* first integer-like argument */ ++ ARM_A4_REGNUM = 3, /* last integer-like argument */ ++ ARM_AP_REGNUM = 11, ++ ARM_IP_REGNUM = 12, ++ ARM_SP_REGNUM = 13, /* Contains address of top of stack */ ++ ARM_LR_REGNUM = 14, /* address to return to from a function call */ ++ ARM_PC_REGNUM = 15, /* Contains program counter */ ++ ARM_F0_REGNUM = 16, /* first floating point register */ ++ ARM_F3_REGNUM = 19, /* last floating point argument register */ ++ ARM_F7_REGNUM = 23, /* last floating point register */ ++ ARM_FPS_REGNUM = 24, /* floating point status register */ ++ ARM_PS_REGNUM = 25, /* Contains processor status */ ++ ARM_WR0_REGNUM, /* WMMX data registers. */ ++ ARM_WR15_REGNUM = ARM_WR0_REGNUM + 15, ++ ARM_WC0_REGNUM, /* WMMX control registers. */ ++ ARM_WCSSF_REGNUM = ARM_WC0_REGNUM + 2, ++ ARM_WCASF_REGNUM = ARM_WC0_REGNUM + 3, ++ ARM_WC7_REGNUM = ARM_WC0_REGNUM + 7, ++ ARM_WCGR0_REGNUM, /* WMMX general purpose registers. */ ++ ARM_WCGR3_REGNUM = ARM_WCGR0_REGNUM + 3, ++ ARM_WCGR7_REGNUM = ARM_WCGR0_REGNUM + 7, ++ ARM_D0_REGNUM, /* VFP double-precision registers. */ ++ ARM_D31_REGNUM = ARM_D0_REGNUM + 31, ++ ARM_FPSCR_REGNUM, ++ ++ ARM_NUM_REGS, ++ ++ /* Other useful registers. */ ++ ARM_FP_REGNUM = 11, /* Frame register in ARM code, if used. */ ++ THUMB_FP_REGNUM = 7, /* Frame register in Thumb code, if used. */ ++ ARM_NUM_ARG_REGS = 4, ++ ARM_LAST_ARG_REGNUM = ARM_A4_REGNUM, ++ ARM_NUM_FP_ARG_REGS = 4, ++ ARM_LAST_FP_ARG_REGNUM = ARM_F3_REGNUM ++}; ++ ++static void ++arm_supply_regcache(struct regcache *regcache, struct gdbarch *gdbarch, ++ void *buf, int *sp, int *pc) ++{ ++ gdb_byte pc_buf[INT_REGISTER_SIZE]; ++ struct arm_pt_regs *regs = (struct arm_pt_regs *)buf; ++ CORE_ADDR reg_pc; ++ enum bfd_endian byte_order; ++ int i; ++ ++ byte_order = gdbarch_byte_order (gdbarch); ++ for (i = ARM_A1_REGNUM; i < ARM_PC_REGNUM; i ++) ++ regcache_raw_supply(regcache, i, buf + INT_REGISTER_SIZE * i); ++ regcache_raw_supply (regcache, ARM_PS_REGNUM, ®s->uregs[16]); ++ reg_pc = extract_unsigned_integer(®s->uregs[15], ++ INT_REGISTER_SIZE, gdbarch_byte_order (gdbarch)); ++ reg_pc = gdbarch_addr_bits_remove (gdbarch, reg_pc); ++ store_unsigned_integer (pc_buf, INT_REGISTER_SIZE, byte_order, reg_pc); ++ regcache_raw_supply (regcache, ARM_PC_REGNUM, pc_buf); ++ ++ *sp = regs->uregs[13]; ++ *pc = regs->uregs[15]; ++} ++ ++static struct frame_info *current_frame; ++static void ++gdb_dis_func_unwind(struct gnu_request *req) ++{ ++ struct frame_info * fi; ++ unsigned int sp, pc, i; ++ struct regcache *regcache; ++ struct gdbarch *gdbarch; ++ struct bfd_arch_info *bfd_arch_info; ++ ++ regcache = get_current_regcache (); ++ gdbarch = get_regcache_arch (regcache); ++ bfd_arch_info = gdbarch_bfd_arch_info(gdbarch); ++ ++ if (strcmp(bfd_arch_info->arch_name, "arm") == 0) ++ arm_supply_regcache(regcache, gdbarch, req->buf, &sp, &pc); ++ else { ++ printf("platform not support!!!\n"); ++ req->flags |= GNU_COMMAND_FAILED; ++ return; ++ } ++ ++ fi = create_new_frame(sp, pc); ++ current_frame = fi; ++ ++ for (i = 0; fi; i ++, fi = get_prev_frame(fi)) { ++ print_frame_info(fi, 1, LOCATION, 1); ++ if (req->value) ++ print_frame_local_vars (fi, 1, gdb_stdout); ++ } ++} ++ + struct load_module *gdb_current_load_module = NULL; + + static void +diff --git a/gdb/target.c b/gdb/target.c +index 6e05ad1..58d5d26 100644 +--- gdb-7.3.1/gdb/target.c ++++ gdb-7.3.1/gdb/target.c +@@ -1698,6 +1698,13 @@ target_read_memory (CORE_ADDR memaddr, gdb_byte *myaddr, int len) + int + target_read_stack (CORE_ADDR memaddr, gdb_byte *myaddr, int len) + { ++#ifdef CRASH_MERGE ++ extern int gdb_readmem_callback(unsigned long, void *, int, int); ++ if (gdb_readmem_callback(memaddr, (void *)myaddr, len, 0)) ++ return 0; ++ else ++ return EIO; ++#endif + /* Dispatch to the topmost target, not the flattened current_target. + Memory accesses check target->to_has_(all_)memory, and the + flattened target doesn't inherit those. */ diff --git a/gdb_interface.c b/gdb_interface.c index 8690bb7..4b9be14 100755 --- a/gdb_interface.c +++ b/gdb_interface.c @@ -590,6 +590,9 @@ gdb_command_string(int cmd, char *buf, int live) case GNU_SET_CRASH_BLOCK: sprintf(buf, "GNU_SET_CRASH_BLOCK"); break; + case GNU_DIS_FUNC_UNWIND: + sprintf(buf, "GNU_DIS_FUNC_UNWIND"); + break; case 0: buf[0] = NULLCHAR; break; diff --git a/help.c b/help.c index 14bf533..f35f7c7 100755 --- a/help.c +++ b/help.c @@ -1613,6 +1613,8 @@ char *help_bt[] = { " trace of the current context will be displayed.\n", " -a displays the stack traces of the active task on each CPU.", " (only applicable to crash dumps)", +" -c show only function parameter name and value during backtrace", +" -C show function parameter and local variable info during backtrace", #ifdef GDB_5_3 " -g use gdb stack trace code. (alpha only)", #else @@ -1685,6 +1687,35 @@ char *help_bt[] = { " DS: 002b ESI: bfffc8a0 ES: 002b EDI: 00000000 ", " SS: 002b ESP: bfffc82c EBP: bfffd224 ", " CS: 0023 EIP: 400d032e ERR: 0000008e EFLAGS: 00000246 ", +"\n Display the stack trace with function param info showing:\n", +" %s> bt -c", +" PID: 886 TASK: c54991a0 CPU: 0 COMMAND: \"sh\"", +" #0 0xc02da1c0 in sysrq_handle_crash (key=99) at drivers/tty/sysrq.c:134", +" #1 0xc02da6dc in __handle_sysrq (key=99, check_mask=false) at drivers/tty/sysrq.c:522", +" #2 0xc02da7cc in write_sysrq_trigger (file=, buf=, count=2, ppos=0x1) at drivers/tty/sysrq.c:870", +" #3 0xc01d89cc in proc_reg_write (file=0xd3295cc0, buf=0x36554
, count=2, ppos=0xd29d5f80) at fs/proc/inode.c:200", +" #4 0xc0194680 in vfs_write (file=0xd3295cc0, buf=0x36554
, count=, pos=0xd29d5f80) at fs/read_write.c:377", +" #5 0xc01947b4 in sys_write (fd=, buf=0x36554
, count=2) at fs/read_write.c:429", +"\n Display the stack trace with both function param and local var info showing:\n", +" %s> bt -C", +" PID: 886 TASK: c54991a0 CPU: 0 COMMAND: \"sh\"", +" #0 0xc02da1c0 in sysrq_handle_crash (key=99) at drivers/tty/sysrq.c:134", +" No locals.", +" #1 0xc02da6dc in __handle_sysrq (key=99, check_mask=false) at drivers/tty/sysrq.c:522", +" op_p = 0xc06dbeb8", +" orig_log_level = 7", +" i = -1066549576", +" flags = 1610612755", +" #2 0xc02da7cc in write_sysrq_trigger (file=, buf=, count=2, ppos=0x1) at drivers/tty/sysrq.c:870", +" No locals.", +" #3 0xc01d89cc in proc_reg_write (file=0xd3295cc0, buf=0x36554
, count=2, ppos=0xd29d5f80) at fs/proc/inode.c:200", +" pde = 0xdfc494c0", +" rv = -1070749788", +" write = ", +" #4 0xc0194680 in vfs_write (file=0xd3295cc0, buf=0x36554
, count=, pos=0xd29d5f80) at fs/read_write.c:377", +" ret = 2", +" #5 0xc01947b4 in sys_write (fd=, buf=0x36554
, count=2) at fs/read_write.c:429", +" pos = bt: invalid kernel virtual address: fffffff1 type: \"gdb_readmem_callback\"", "\n Display the stack traces of task f2814000 and PID 1592:\n", " %s> bt f2814000 1592", " PID: 1018 TASK: f2814000 CPU: 1 COMMAND: \"java\"", diff --git a/kernel.c b/kernel.c index 45da48e..5203970 100755 --- a/kernel.c +++ b/kernel.c @@ -1908,7 +1908,7 @@ cmd_bt(void) if (kt->flags & USE_OLD_BT) bt->flags |= BT_OLD_BACK_TRACE; - while ((c = getopt(argcnt, args, "D:fFI:S:aloreEgstTdxR:O")) != EOF) { + while ((c = getopt(argcnt, args, "D:fFI:S:aloreEgstTdxR:OcC")) != EOF) { switch (c) { case 'f': @@ -2052,6 +2052,14 @@ cmd_bt(void) active++; break; + case 'c': + bt->flags |= BT_SHOW_PARAM; + break; + + case 'C': + bt->flags |= (BT_SHOW_PARAM | BT_SHOW_VAR); + break; + case 'r': bt->flags |= BT_RAW; break; @@ -2216,6 +2224,27 @@ cmd_bt(void) } } +static void +all_symbols_dump(struct bt_info *bt) +{ + struct gnu_request *req; + int ret; + + req = (struct gnu_request *)GETBUF(sizeof(struct gnu_request)); + req->buf = bt->machdep; + + req->command = GNU_DIS_FUNC_UNWIND; + req->value = !!(bt->flags & BT_SHOW_VAR); + req->flags |= GNU_RETURN_ON_ERROR; + + gdb_interface(req); + if (req->flags & GNU_COMMAND_FAILED) { + FREEBUF(req); + error(FATAL, "display function unwind fail\n"); + } + FREEBUF(req); +} + void print_stack_text_syms(struct bt_info *bt, ulong esp, ulong eip) { @@ -2424,6 +2453,11 @@ back_trace(struct bt_info *bt) return; } + if (bt->flags & BT_SHOW_PARAM) { + all_symbols_dump(bt); + return; + } + if (bt->flags & (BT_TEXT_SYMBOLS|BT_TEXT_SYMBOLS_PRINT|BT_TEXT_SYMBOLS_NOPRINT)) { -- 1.7.5.4