>From 89d6a242ed95f9a50f99bf75aa08a71556a336ce Mon Sep 17 00:00:00 2001
From: Toshikazu Nakayama <nakayama.ts@ncos.nec.co.jp>
Date: Thu, 27 Oct 2011 11:19:20 +0900
Subject: [PATCH 8/8] ppc: handle link register

Porting from ppc64.

Add link register of exception frame handling and newpc is also cleanuped
with new LR macro.
Ported BT_FULL parts from ppc64.

Signed-off-by: Toshikazu Nakayama <nakayama.ts@ncos.nec.co.jp>
---
 defs.h |    1 +
 ppc.c  |   94 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
 2 files changed, 84 insertions(+), 11 deletions(-)

diff --git a/defs.h b/defs.h
index 022af0d..212c561 100755
--- a/defs.h
+++ b/defs.h
@@ -2616,6 +2616,7 @@ struct load_module {
 #define _MAX_PHYSMEM_BITS	44
 
 #define STACK_FRAME_OVERHEAD	16
+#define STACK_FRAME_LR_SAVE	(sizeof(ulong))
 #define STACK_FRAME_MARKER	(2 * sizeof(ulong))
 #define STACK_FRAME_REGS_MARKER	0x72656773
 #define PPC_STACK_SIZE		8192
diff --git a/ppc.c b/ppc.c
index f2adff0..a6e67fd 100755
--- a/ppc.c
+++ b/ppc.c
@@ -53,10 +53,11 @@ static void ppc_back_trace_cmd(struct bt_info *);
 static void ppc_back_trace(struct gnu_request *, struct bt_info *);
 static void get_ppc_frame(struct bt_info *, ulong *, ulong *);
 static void ppc_print_stack_entry(int,struct gnu_request *,
-	ulong, char *, struct bt_info *);
+	ulong, ulong, struct bt_info *);
 static char *ppc_check_eframe(struct ppc_pt_regs *);
 static void ppc_print_eframe(char *, struct ppc_pt_regs *, struct bt_info *);
 static void ppc_print_regs(struct ppc_pt_regs *);
+static void ppc_display_full_frame(struct bt_info *, ulong, FILE *);
 static void ppc_dump_irq(int);
 static ulong ppc_get_pc(struct bt_info *);
 static ulong ppc_get_sp(struct bt_info *);
@@ -839,6 +840,7 @@ static void
 ppc_back_trace(struct gnu_request *req, struct bt_info *bt)
 {
 	int frame = 0;
+	ulong lr = 0;
 	ulong newpc = 0, newsp, marker;
 	int eframe_found;
 
@@ -859,7 +861,8 @@ ppc_back_trace(struct gnu_request *req, struct bt_info *bt)
 	while (INSTACK(req->sp, bt)) {
 		newsp = *(ulong *)&bt->stackbuf[req->sp - bt->stackbase];
 		if (IS_KVADDR(newsp) && INSTACK(newsp, bt))
-			newpc = *(ulong *)&bt->stackbuf[newsp + 4 -
+			newpc = *(ulong *)&bt->stackbuf[newsp +
+							STACK_FRAME_LR_SAVE -
 							bt->stackbase];
 		if ((req->name = closest_symbol(req->pc)) == NULL) {
 			error(FATAL, 
@@ -869,8 +872,9 @@ ppc_back_trace(struct gnu_request *req, struct bt_info *bt)
 		}
 
 		bt->flags |= BT_SAVE_LASTSP;
-		ppc_print_stack_entry(frame, req, req->pc, req->name, bt);
+		ppc_print_stack_entry(frame, req, newsp, lr, bt);
 		bt->flags &= ~(ulonglong)BT_SAVE_LASTSP;
+		lr = 0;
 
 		if (BT_REFERENCE_FOUND(bt))
 			return;
@@ -908,6 +912,7 @@ ppc_back_trace(struct gnu_request *req, struct bt_info *bt)
 			efrm_str = ppc_check_eframe(&regs);
 			if (efrm_str) {
 				ppc_print_eframe(efrm_str, &regs, bt);
+				lr = regs.link;
 				newpc = regs.nip;
 				newsp = regs.gpr[1];
 			}
@@ -924,45 +929,112 @@ ppc_back_trace(struct gnu_request *req, struct bt_info *bt)
 	return;
 }
 
+static void
+ppc_display_full_frame(struct bt_info *bt, ulong nextsp, FILE *ofp)
+{
+	int i, u_idx;
+	ulong *nip;
+	ulong words, addr;
+	char buf[BUFSIZE];
+
+	if (!INSTACK(nextsp, bt))
+		nextsp =  bt->stacktop;
+
+	words = (nextsp - bt->frameptr) / sizeof(ulong);
+	addr = bt->frameptr;
+	u_idx = (bt->frameptr - bt->stackbase)/sizeof(ulong);
+	for (i = 0; i < words; i++, u_idx++) {
+		if (!(i & 1))
+			fprintf(ofp, "%s    %lx: ", i ? "\n" : "", addr);
+
+		nip = (ulong *)(&bt->stackbuf[u_idx*sizeof(ulong)]);
+		fprintf(ofp, "%s ", format_stack_entry(bt, buf, *nip, 0));
+		addr += sizeof(ulong);
+	}
+	fprintf(ofp, "\n");
+}
+
 /*
  *  print one entry of a stack trace
  */
 static void 
 ppc_print_stack_entry(int frame, 
 		      struct gnu_request *req, 
-		      ulong callpc, 	
-		      char *name, 
+		      ulong newsp, 	
+		      ulong lr, 
 		      struct bt_info *bt)
 {
 	struct load_module *lm;
+	char *lrname = NULL;
 
 	if (BT_REFERENCE_CHECK(bt)) {
                 switch (bt->ref->cmdflags & (BT_REF_SYMBOL|BT_REF_HEXVAL))
                 {
                 case BT_REF_SYMBOL:
-                        if (STREQ(name, bt->ref->str)) 
+                        if (STREQ(req->name, bt->ref->str)) 
                         	bt->ref->cmdflags |= BT_REF_FOUND;
                         break;
 
                 case BT_REF_HEXVAL:
-                        if (bt->ref->hexval == callpc) 
+                        if (bt->ref->hexval == req->pc) 
                                 bt->ref->cmdflags |= BT_REF_FOUND;
                         break;
                 }
 	} else {
 		fprintf(fp, "%s#%d [%lx] %s at %lx",
         		frame < 10 ? " " : "", frame,
-                	req->sp, name, callpc);
-		if (module_symbol(callpc, NULL, &lm, NULL, 0))
+                	req->sp, req->name, req->pc);
+		if (module_symbol(req->pc, NULL, &lm, NULL, 0))
 			fprintf(fp, " [%s]", lm->mod_name);
-                fprintf(fp, "\n");
+
+		if (req->ra) {
+			/*
+			 * Previous frame is an exception one. If the func
+			 * symbol for the current frame is same as with
+			 * the previous frame's LR value, print "(unreliable)".
+			 */
+			lrname = closest_symbol(req->ra);
+			req->ra = 0;
+			if (!lrname) {
+				if (CRASHDEBUG(1))
+					error(FATAL,
+					"ppc_back_trace hit unknown symbol (%lx).\n",
+						req->ra);
+				return;
+			}
+		}
+		if (lr) {
+			/*
+			 * Link register value for an expection frame.
+			 */
+			if ((lrname = closest_symbol(lr)) == NULL) {
+				if (CRASHDEBUG(1))
+					error(FATAL,
+					"ppc_back_trace hit unknown symbol (%lx).\n",
+						lr);
+				return;
+			}
+			if (req->pc != lr) {
+				fprintf(fp, "\n [Link Register ] ");
+				fprintf(fp, " [%lx] %s at %lx",
+					req->sp, lrname, lr);
+			}
+			req->ra = lr;
+		}
+		if (!req->name || STREQ(req->name,lrname))
+			fprintf(fp, "  (unreliable)");
+		fprintf(fp, "\n");
 	}
 
 	if (bt->flags & BT_SAVE_LASTSP)
 		req->lastsp = req->sp;
 
+	bt->frameptr = req->sp;
+	if (bt->flags & BT_FULL)
+		if (IS_KVADDR(newsp))
+			ppc_display_full_frame(bt, newsp, fp);
 	if (bt->flags & BT_LINE_NUMBERS)
-		ppc_dump_line_number(callpc);
+		ppc_dump_line_number(req->pc);
 }
 
 /*
-- 
1.7.6.rc2.11.g13b7

