From eb71177e77771cd6698f62185f79f26f595b39ec Mon Sep 17 00:00:00 2001
From: Lei Wen <leiwen@marvell.com>
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 <leiwen@marvell.com>
---
 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, &regs->uregs[16]);
++	reg_pc = extract_unsigned_integer(&regs->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=<optimized out>, buf=<optimized out>, count=2, ppos=0x1) at drivers/tty/sysrq.c:870",
+"     #3  0xc01d89cc in proc_reg_write (file=0xd3295cc0, buf=0x36554 <Address 0x36554 out of bounds>, count=2, ppos=0xd29d5f80) at fs/proc/inode.c:200",
+"     #4  0xc0194680 in vfs_write (file=0xd3295cc0, buf=0x36554 <Address 0x36554 out of bounds>, count=<optimized out>, pos=0xd29d5f80) at fs/read_write.c:377",
+"     #5  0xc01947b4 in sys_write (fd=<optimized out>, buf=0x36554 <Address 0x36554 out of bounds>, 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=<optimized out>, buf=<optimized out>, count=2, ppos=0x1) at drivers/tty/sysrq.c:870",
+"    No locals.",
+"    #3  0xc01d89cc in proc_reg_write (file=0xd3295cc0, buf=0x36554 <Address 0x36554 out of bounds>, count=2, ppos=0xd29d5f80) at fs/proc/inode.c:200",
+"            pde = 0xdfc494c0",
+"            rv = -1070749788",
+"            write = <optimized out>",
+"    #4  0xc0194680 in vfs_write (file=0xd3295cc0, buf=0x36554 <Address 0x36554 out of bounds>, count=<optimized out>, pos=0xd29d5f80) at fs/read_write.c:377",
+"            ret = 2",
+"    #5  0xc01947b4 in sys_write (fd=<optimized out>, buf=0x36554 <Address 0x36554 out of bounds>, 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

