From 1ece1335e65e794f9b89e34449e012fe4d722c35 Mon Sep 17 00:00:00 2001
From: Lei Wen <leiwen@marvell.com>
Date: Tue, 16 Oct 2012 15:22:39 +0800
Subject: [PATCH] [RFC] display out parameter and local value for backtrace

Current only works for ARM.
And has the limitation for only could display out first two frame, when
try to extract out the pc pointer for the third frame, it would complain
for "Cannot access memory at address"

NOT FOR MERGE purpose, but only for comments.

Signed-off-by: Lei Wen <leiwen@marvell.com>
---
 defs.h          |    1 +
 gdb-7.3.1.patch |  180 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 gdb_interface.c |    3 +
 unwind_arm.c    |   25 +++++++-
 4 files changed, 208 insertions(+), 1 deletions(-)

diff --git a/defs.h b/defs.h
index 9c50514..6717925 100755
--- a/defs.h
+++ b/defs.h
@@ -3603,6 +3603,7 @@ struct gnu_request {
 #define GNU_GET_SYMBOL_TYPE      (15)
 #define GNU_USER_PRINT_OPTION 	 (16)
 #define GNU_SET_CRASH_BLOCK      (17)
+#define GNU_DISPLAY_LOC          (18)
 #define GNU_DEBUG_COMMAND       (100)
 /*
  *  GNU flags
diff --git a/gdb-7.3.1.patch b/gdb-7.3.1.patch
index 13a4329..6467212 100644
--- a/gdb-7.3.1.patch
+++ b/gdb-7.3.1.patch
@@ -1700,3 +1700,183 @@ diff -up gdb-7.3.1/gdb/psymtab.c.orig gdb-7.3.1/gdb/psymtab.c
  	req->typecode = TYPE_MAIN_TYPE(type)->code;
  	req->length = type->length;
  	target_type = TYPE_MAIN_TYPE(type)->target_type;
+--- 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,
+@@ -1016,7 +1014,7 @@ parse_frame_specification (char *frame_exp)
+ /* Print verbosely the selected frame or the frame at address
+    ADDR_EXP.  Absolutely all information in the frame is printed.  */
+ 
+-static void
++void
+ frame_info (char *addr_exp, int from_tty)
+ {
+   struct frame_info *fi;
+@@ -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)
+ {
+--- gdb-7.3.1/gdb/stack.h
++++ gdb-7.3.1/gdb/stack.h
+@@ -22,6 +22,9 @@
+ #define STACK_H
+ 
+ void select_frame_command (char *level_exp, int from_tty);
++void frame_info (char *addr_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);
+--- gdb-7.3.1/gdb/frame.c
++++ gdb-7.3.1/gdb/frame.c
+@@ -1957,6 +1957,16 @@ get_frame_pc (struct frame_info *frame)
+   return frame_unwind_pc (frame->next);
+ }
+ 
++void
++set_prev_frame_pc (struct frame_info *frame, CORE_ADDR pc)
++{
++	if (frame->prev_pc.p)
++		return;
++
++	frame->prev_pc.value = pc;
++	frame->prev_pc.p = 1;
++}
++
+ int
+ get_frame_pc_if_available (struct frame_info *frame, CORE_ADDR *pc)
+ {
+--- gdb-7.3.1/gdb/frame.h
++++ gdb-7.3.1/gdb/frame.h
+@@ -284,6 +284,9 @@ extern struct frame_info *frame_find_by_id (struct frame_id id);
+    This replaced: frame->pc; */
+ extern CORE_ADDR get_frame_pc (struct frame_info *);
+ 
++/* Set the specified pc to the frame's prev_pc member */
++extern void set_prev_frame_pc (struct frame_info *frame, CORE_ADDR pc);
++
+ /* Same as get_frame_pc, but return a boolean indication of whether
+    the PC is actually available, instead of throwing an error.  */
+ 
+--- 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_display_loc(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_DISPLAY_LOC:
++		gdb_display_loc(req);
++		break;
++
+ 	case GNU_DEBUG_COMMAND:
+ 		gdb_debug_command(req);
+ 		break;
+@@ -5243,6 +5248,86 @@ 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
++gdb_display_loc(struct gnu_request *req)
++{
++	struct frame_info * fi;
++	struct arm_pt_regs *regs = req->buf;
++	unsigned int sp, pc, i;
++	struct regcache *regcache;
++	CORE_ADDR reg_pc;
++	gdb_byte pc_buf[INT_REGISTER_SIZE];
++	struct gdbarch *gdbarch;
++	enum bfd_endian byte_order;
++	void *gregs_buf;
++
++	sp = regs->uregs[13];
++	pc = regs->uregs[15];
++	regcache = get_current_regcache ();
++	gdbarch = get_regcache_arch (regcache);
++	byte_order = gdbarch_byte_order (gdbarch);
++
++	gregs_buf = regs->uregs;
++	for (i = ARM_A1_REGNUM; i < ARM_PC_REGNUM; i ++)
++		regcache_raw_supply(regcache, i, gregs_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);
++
++	fi = create_new_frame(sp,  get_pc_function_start(pc));
++	set_prev_frame_pc(fi, regs->uregs[14]);
++
++	for (i = 0; i < 4; i ++) {
++		print_frame_info(fi, 1, LOCATION, 1);
++		print_frame_local_vars (fi, 1, gdb_stdout);
++		fi = get_prev_frame(fi);
++	}
++}
++
+ struct load_module *gdb_current_load_module = NULL;
+ 
+ static void 
diff --git a/gdb_interface.c b/gdb_interface.c
index 2c2d0ee..7085001 100755
--- a/gdb_interface.c
+++ b/gdb_interface.c
@@ -589,6 +589,9 @@ gdb_command_string(int cmd, char *buf, int live)
         case GNU_SET_CRASH_BLOCK:
                 sprintf(buf, "GNU_SET_CRASH_BLOCK");
 		break;
+	case GNU_DISPLAY_LOC:
+                sprintf(buf, "GNU_DISPLAY_LOC");
+		break;
 	case 0:
 		buf[0] = NULLCHAR;
 		break;
diff --git a/unwind_arm.c b/unwind_arm.c
index 06dd91b..87c7fb5 100755
--- a/unwind_arm.c
+++ b/unwind_arm.c
@@ -720,10 +720,30 @@ unwind_frame(struct stackframe *frame, ulong stacktop)
 	return TRUE;
 }
 
+static display_locs(struct arm_pt_regs *regs)
+{
+	struct gnu_request *req;
+	int ret;
+
+	req = (struct gnu_request *)GETBUF(sizeof(struct gnu_request));
+	req->buf = regs;
+
+	req->command = GNU_DISPLAY_LOC;
+	req->flags |= GNU_RETURN_ON_ERROR;
+
+	gdb_interface(req);
+	if (req->flags & GNU_COMMAND_FAILED) {
+		FREEBUF(req);
+		error(FATAL, "display local fail at %x\n", regs->ARM_pc);
+	}
+	FREEBUF(req);
+}
+
 void
 unwind_backtrace(struct bt_info *bt)
 {
 	struct stackframe frame;
+	struct arm_pt_regs *regs, tmp;
 	int n = 0;
 
 	BZERO(&frame, sizeof(frame));
@@ -736,11 +756,14 @@ unwind_backtrace(struct bt_info *bt)
 	 * LR from there.
 	 */
 	if (bt->machdep) {
-		const struct arm_pt_regs *regs = bt->machdep;
+		regs = bt->machdep;
 		frame.fp = regs->ARM_fp;
 		frame.lr = regs->ARM_lr;
+		n = 0;
 	}
 
+	display_locs(regs);
+	return;
 	while (IS_KVADDR(bt->instptr)) {
 		if (!unwind_frame(&frame, bt->stacktop))
 			break;
-- 
1.7.5.4

