Hello Dave,
I attach patches which are updating powerpc based on linux-2.6.27.
Please review them.
Following updates have been done but
some of them could not test yet because of constraints in environment.
(Non-SMP powerpc virtual machine of qemu can only use)
- Get rid of __func__. symbols (patch 0001)
This patch can delete such symbols from command output like
crash> sym -l | grep __func__ -m 3
c03604ac (r) __func__.21434
c0360500 (r) __func__.21333
c0360508 (r) __func__.21309
- Minor updates (patch 0002/0003/0004)
ppc_processor_speed() support "ibm,extended-clock-frequency" [Not tested]
ppc_get_smp_cpus() can return correct cpu numbers on SMP [Not tested]
"bt", "mach" can handle (tt->flags & IRQSTACKS) [Not tested]
- Enhancement of "bt" (patch 0005/0006/0007/0008)
Detect exeption frame of linux-2.6 style ("bt" can dispaly '+' parts of below)
Some functions are cleanuped with ppc64's.
* Link Register of nested exception frame could not be tested.
This may require the exception in kernel mode like oops but
can not try kernel dump for a while...
crash> bt 1
PID: 1 TASK: c8818000 CPU: 0 COMMAND: "init"
#0 [c881da10] schedule at c0356ac4
#1 [c881da70] schedule_timeout at c0357468
#2 [c881dab0] do_select at c00c4758
#3 [c881dd90] core_sys_select at c00c4bd0
#4 [c881dee0] sys_select at c00c52b0
#5 [c881df30] ppc_select at c00053c0
#6 [c881df40] ret_from_syscall at c0011f64
+ syscall [c01] exception frame:
+R0: 0000008e R1: b8c11a60 R2: 48008660 R3: 0000000b
+R4: b8c11cac R5: 00000000 R6: 00000000 R7: b8c11b24
+R8: 00000000 R9: 00000400 R10: 00000000 R11: 0ff24b2c
+R12: 0ff1b8ec R13: 100207f0
+NIP: 0ff24b40 MSR: 0000d032 OR3: 0000000b CTR: 0ff24b2c
+LR: 10005314 XER: 00000000 CCR: 24002462 MQ: 00000000
+DAR: 0ffb4cd0 DSISR: 0a000000 Syscall Result: 00000000
Still remaining the parts of PPC update and I have to setup more useful
environment
for the tests as soon as possible.
Thanks,
Toshi.
>From 89d6a242ed95f9a50f99bf75aa08a71556a336ce Mon Sep 17 00:00:00 2001
From: Toshikazu Nakayama <[email protected]>
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 <[email protected]>
---
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(®s);
if (efrm_str) {
ppc_print_eframe(efrm_str, ®s, 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
>From 1916480dfe14989dbd9346ddbc1ec5efbd28a8ce Mon Sep 17 00:00:00 2001
From: Toshikazu Nakayama <[email protected]>
Date: Tue, 25 Oct 2011 11:19:03 +0900
Subject: [PATCH 1/8] ppc: update symbol table
Porting from ppc64.
Get rid of __func__. symbols from symbol table at ppc_verify_symbol().
This update gives effect for some command results, example:
[Before]
crash> sym -l | grep __func__ -m 3
c03604ac (r) __func__.21434
c0360500 (r) __func__.21333
c0360508 (r) __func__.21309
[After]
=> disappeared
Signed-off-by: Toshikazu Nakayama <[email protected]>
---
ppc.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/ppc.c b/ppc.c
index 1ec8e70..b17143b 100755
--- a/ppc.c
+++ b/ppc.c
@@ -599,7 +599,7 @@ ppc_verify_symbol(const char *name, ulong value, char type)
machdep->flags |= KSYMS_START;
return (name && strlen(name) && (machdep->flags & KSYMS_START) &&
- !STREQ(name, "Letext"));
+ !STREQ(name, "Letext") && !STRNEQ(name, "__func__."));
}
--
1.7.6.rc2.11.g13b7
>From f769af54e9f80a98a54404545adf6893953f8959 Mon Sep 17 00:00:00 2001
From: Toshikazu Nakayama <[email protected]>
Date: Tue, 25 Oct 2011 11:35:30 +0900
Subject: [PATCH 2/8] ppc: update processor frequency
Porting from ppc64.
Add "ibm,extended-clock-frequency" device property which is
appeared in the ppc common code arch/powerpc/kernel/time.c.
Fix indent nearby readmem().
Signed-off-by: Toshikazu Nakayama <[email protected]>
---
ppc.c | 43 ++++++++++++++++++++++++++++---------------
1 files changed, 28 insertions(+), 15 deletions(-)
diff --git a/ppc.c b/ppc.c
index b17143b..60d4028 100755
--- a/ppc.c
+++ b/ppc.c
@@ -523,15 +523,28 @@ ppc_processor_speed(void)
"clock frequency value",
FAULT_ON_ERROR);
mhz /= 1000000;
-
+ break;
+ } else if(len && (strcasecmp(str_buf,
+ "ibm,extended-clock-frequency") == 0)){
+ /* found the right cpu property */
+
+ readmem(properties+
+ OFFSET(property_value),
+ KVADDR, &value, sizeof(ulong),
+ "clock freqency pointer",
+ FAULT_ON_ERROR);
+ readmem(value, KVADDR, &mhz,
+ sizeof(ulong),
+ "clock frequency value",
+ FAULT_ON_ERROR);
+ mhz /= 1000000;
break;
}
/* keep looking */
-
readmem(properties+
- OFFSET(property_next),
- KVADDR, &properties, sizeof(ulong),
- "property next", FAULT_ON_ERROR);
+ OFFSET(property_next),
+ KVADDR, &properties, sizeof(ulong),
+ "property next", FAULT_ON_ERROR);
}
if(!properties) {
/* didn't find the cpu speed for some reason */
@@ -551,19 +564,19 @@ ppc_processor_speed(void)
get_symbol_data("ppc_md", sizeof(void *),
&ppc_md);
readmem(ppc_md +
- OFFSET(machdep_calls_setup_residual),
- KVADDR, &md_setup_res,
- sizeof(ulong), "ppc_md setup_residual",
- FAULT_ON_ERROR);
+ OFFSET(machdep_calls_setup_residual),
+ KVADDR, &md_setup_res,
+ sizeof(ulong), "ppc_md setup_residual",
+ FAULT_ON_ERROR);
if(prep_setup_res == md_setup_res) {
- /* PREP machine */
+ /* PREP machine */
readmem(res+
- OFFSET(RESIDUAL_VitalProductData)+
- OFFSET(VPD_ProcessorHz),
- KVADDR, &mhz, sizeof(ulong),
- "res VitalProductData",
- FAULT_ON_ERROR);
+ OFFSET(RESIDUAL_VitalProductData)+
+ OFFSET(VPD_ProcessorHz),
+ KVADDR, &mhz, sizeof(ulong),
+ "res VitalProductData",
+ FAULT_ON_ERROR);
mhz = (mhz > 1024) ? mhz >> 20 : mhz;
}
--
1.7.6.rc2.11.g13b7
>From c826e4f244fb5a369ccf44d566c9d84308fd5747 Mon Sep 17 00:00:00 2001
From: Toshikazu Nakayama <[email protected]>
Date: Tue, 25 Oct 2011 14:21:05 +0900
Subject: [PATCH 3/8] ppc: update get_smp_cpus
Porting from ppc64.
ppc_get_smp_cpus() returned kt->cpus for kt->cpus setting,
won't overwrite cpus.
Return get_cpus_online() which cpu_online_map is common symbol
in powerpc kernel.
[Before] maybe everytime print "1" even if SMP machine.
crash> mach | grep CPUS
CPUS: 1
crash> help -k | grep "cpus:"
cpus: 1
[After] Could print correctable cpus (not tested yet)
Signed-off-by: Toshikazu Nakayama <[email protected]>
---
ppc.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/ppc.c b/ppc.c
index 60d4028..adcf239 100755
--- a/ppc.c
+++ b/ppc.c
@@ -1328,7 +1328,7 @@ ppc_dis_filter(ulong vaddr, char *inbuf, unsigned int output_radix)
int
ppc_get_smp_cpus(void)
{
- return kt->cpus;
+ return (get_cpus_online() > 0) ? get_cpus_online() : kt->cpus;
}
/*
--
1.7.6.rc2.11.g13b7
>From 83199eb1aced18b509c798bb9db9a90df8173c8e Mon Sep 17 00:00:00 2001
From: Toshikazu Nakayama <[email protected]>
Date: Fri, 28 Oct 2011 13:07:27 +0900
Subject: [PATCH 4/8] ppc: mach and bt can handle irq stack
Porting from ppc64.
When CONFIG_IRQSTACK is y (tt->flags & IRQSTACKS),
mach command can show IRQ stacks and bt command can
display backtrace in IRQ stacks.
IRQ stack -> current task's stack switch can not support yet.
Signed-off-by: Toshikazu Nakayama <[email protected]>
---
ppc.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 68 insertions(+), 1 deletions(-)
diff --git a/ppc.c b/ppc.c
index adcf239..ed21236 100755
--- a/ppc.c
+++ b/ppc.c
@@ -27,6 +27,7 @@ static int ppc_translate_pte(ulong, void *, ulonglong);
static ulong ppc_processor_speed(void);
static int ppc_eframe_search(struct bt_info *);
+static ulong ppc_in_irqstack(ulong);
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 *);
@@ -155,6 +156,12 @@ ppc_init(int when)
machdep->flags |= CPU_BOOKE;
machdep->section_size_bits = _SECTION_SIZE_BITS;
machdep->max_physmem_bits = _MAX_PHYSMEM_BITS;
+ /*
+ * IRQ stacks are introduced in 2.6 and also configurable.
+ */
+ if ((THIS_KERNEL_VERSION >= LINUX(2,6,0)) &&
+ symbol_exists("hardirq_ctx"))
+ STRUCT_SIZE_INIT(irq_ctx, "hardirq_ctx");
break;
case POST_INIT:
@@ -762,6 +769,30 @@ ppc_eframe_search(struct bt_info *bt)
return (error(FATAL, "ppc_eframe_search: function not written yet!\n"));
}
+static ulong
+ppc_in_irqstack(ulong addr)
+{
+ int c;
+
+ if (!(tt->flags & IRQSTACKS))
+ return 0;
+
+ for (c = 0; c < kt->cpus; c++) {
+ if (tt->hardirq_ctx[c]) {
+ if ((addr >= tt->hardirq_ctx[c]) &&
+ (addr < (tt->hardirq_ctx[c] + SIZE(irq_ctx))))
+ return tt->hardirq_ctx[c];
+ }
+ if (tt->softirq_ctx[c]) {
+ if ((addr >= tt->softirq_ctx[c]) &&
+ (addr < (tt->softirq_ctx[c] + SIZE(irq_ctx))))
+ return tt->softirq_ctx[c];
+ }
+ }
+
+ return 0;
+}
+
/*
* Unroll a kernel stack.
*/
@@ -808,6 +839,20 @@ ppc_back_trace(struct gnu_request *req, struct bt_info *bt)
int frame;
int done;
+ if (!INSTACK(req->sp, bt)) {
+ ulong irqstack;
+
+ if ((irqstack = ppc_in_irqstack(req->sp))) {
+ bt->stackbase = irqstack;
+ bt->stacktop = bt->stackbase + SIZE(irq_ctx);
+ alter_stackbuf(bt);
+ } else {
+ if (CRASHDEBUG(1))
+ fprintf(fp, "cannot find the stack info.\n");
+ return;
+ }
+ }
+
for (frame = 0, done = FALSE; !done && (frame < 100); frame++) {
if ((req->name = closest_symbol(req->pc)) == NULL) {
error(FATAL,
@@ -1360,6 +1405,7 @@ ppc_cmd_mach(void)
static void
ppc_display_machine_stats(void)
{
+ int c;
struct new_utsname *uts;
char buf[BUFSIZE];
ulong mhz;
@@ -1376,10 +1422,31 @@ ppc_display_machine_stats(void)
fprintf(fp, "(unknown)\n");
fprintf(fp, " HZ: %d\n", machdep->hz);
fprintf(fp, " PAGE SIZE: %d\n", PAGESIZE());
- fprintf(fp, " L1 CACHE SIZE: %d\n", l1_cache_size());
+// fprintf(fp, " L1 CACHE SIZE: %d\n", l1_cache_size());
fprintf(fp, "KERNEL VIRTUAL BASE: %lx\n", machdep->kvbase);
fprintf(fp, "KERNEL VMALLOC BASE: %lx\n", vt->vmalloc_start);
fprintf(fp, " KERNEL STACK SIZE: %ld\n", STACKSIZE());
+
+ if (tt->flags & IRQSTACKS) {
+ fprintf(fp, "HARD IRQ STACK SIZE: %ld\n", SIZE(irq_ctx));
+ fprintf(fp, " HARD IRQ STACKS:\n");
+
+ for (c = 0; c < kt->cpus; c++) {
+ if (!tt->hardirq_ctx[c])
+ break;
+ sprintf(buf, "CPU %d", c);
+ fprintf(fp, "%19s: %lx\n", buf, tt->hardirq_ctx[c]);
+ }
+
+ fprintf(fp, "SOFT IRQ STACK SIZE: %ld\n", SIZE(irq_ctx));
+ fprintf(fp, " SOFT IRQ STACKS:\n");
+ for (c = 0; c < kt->cpus; c++) {
+ if (!tt->softirq_ctx[c])
+ break;
+ sprintf(buf, "CPU %d", c);
+ fprintf(fp, "%19s: %lx\n", buf, tt->softirq_ctx[c]);
+ }
+ }
}
--
1.7.6.rc2.11.g13b7
>From 1599ec683994f7b4b71a87680613e6a414efdf55 Mon Sep 17 00:00:00 2001
From: Toshikazu Nakayama <[email protected]>
Date: Wed, 26 Oct 2011 14:47:32 +0900
Subject: [PATCH 5/8] ppc: cleanup backtrace loop
Porting from ppc64.
Apply using newsp, newpc into stack frame loop.
This can also avoid unnecessary readmem().
Drop loop limitation 100, use INSTACK().
Signed-off-by: Toshikazu Nakayama <[email protected]>
---
ppc.c | 41 ++++++++++++++++++-----------------------
1 files changed, 18 insertions(+), 23 deletions(-)
diff --git a/ppc.c b/ppc.c
index ed21236..ff14827 100755
--- a/ppc.c
+++ b/ppc.c
@@ -836,8 +836,8 @@ ppc_back_trace_cmd(struct bt_info *bt)
static void
ppc_back_trace(struct gnu_request *req, struct bt_info *bt)
{
- int frame;
- int done;
+ int frame = 0;
+ ulong newpc = 0, newsp;
if (!INSTACK(req->sp, bt)) {
ulong irqstack;
@@ -853,44 +853,39 @@ ppc_back_trace(struct gnu_request *req, struct bt_info *bt)
}
}
- for (frame = 0, done = FALSE; !done && (frame < 100); frame++) {
+ 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 -
+ bt->stackbase];
if ((req->name = closest_symbol(req->pc)) == NULL) {
error(FATAL,
- "ppc_back_trace hit unknown symbol (%lx).\n",
+ "ppc_back_trace hit unknown symbol (%lx).\n",
req->pc);
- req->ra = req->pc = 0;
break;
}
bt->flags |= BT_SAVE_LASTSP;
ppc_print_stack_entry(frame, req, req->pc, req->name, bt);
bt->flags &= ~(ulonglong)BT_SAVE_LASTSP;
-
+
if (BT_REFERENCE_FOUND(bt))
return;
- /* get the next sp and ip values */
- readmem(req->sp, KVADDR, &req->sp, sizeof(ulong),
- "stack frame", FAULT_ON_ERROR);
-
- /* an actual valid end of the back-chain! */
- if(req->sp == 0)
- break;
-
- if((req->sp - req->lastsp) >= sizeof(struct ppc_pt_regs)) {
+ if((newsp - req->sp) >= sizeof(struct ppc_pt_regs)) {
/* there might be an exception frame here... */
- ppc_exception_frame(req->lastsp, bt, req);
- } else if(!IS_KVADDR(req->sp) || (req->sp < req->lastsp)) {
+ ppc_exception_frame(req->sp, bt, req);
+ } else if(!IS_KVADDR(newsp) || (newsp < req->sp)) {
/* also possible one here... */
- ppc_exception_frame(req->lastsp, bt, req);
+ ppc_exception_frame(req->sp, bt, req);
}
-
- if (!INSTACK(req->sp, bt) ||
- STREQ(req->name, "start_kernel"))
+
+ if (STREQ(req->name, "start_kernel"))
break;
- readmem(req->sp+sizeof(long), KVADDR, &req->pc, sizeof(ulong),
- "instruction pointer", FAULT_ON_ERROR);
+ req->pc = newpc;
+ req->sp = newsp;
+ frame++;
}
return;
--
1.7.6.rc2.11.g13b7
>From c65bd42bae131a6d225510f7e23848a6c2577898 Mon Sep 17 00:00:00 2001
From: Toshikazu Nakayama <[email protected]>
Date: Fri, 28 Oct 2011 13:45:31 +0900
Subject: [PATCH 6/8] ppc: update exception frame search
Porting from ppc64.
The backtrace of ppc can handle exception frame and print frame information
for linux-2.6 style by checking exception frame marker.
Clear LS-4bits of trap register when refer exception number for linux-2.6.
Signed-off-by: Toshikazu Nakayama <[email protected]>
---
defs.h | 2 ++
ppc.c | 37 ++++++++++++++++++++++++++++---------
2 files changed, 30 insertions(+), 9 deletions(-)
diff --git a/defs.h b/defs.h
index 970b78e..022af0d 100755
--- a/defs.h
+++ b/defs.h
@@ -2616,6 +2616,8 @@ struct load_module {
#define _MAX_PHYSMEM_BITS 44
#define STACK_FRAME_OVERHEAD 16
+#define STACK_FRAME_MARKER (2 * sizeof(ulong))
+#define STACK_FRAME_REGS_MARKER 0x72656773
#define PPC_STACK_SIZE 8192
#endif /* PPC */
diff --git a/ppc.c b/ppc.c
index ff14827..1bbde2c 100755
--- a/ppc.c
+++ b/ppc.c
@@ -837,7 +837,8 @@ static void
ppc_back_trace(struct gnu_request *req, struct bt_info *bt)
{
int frame = 0;
- ulong newpc = 0, newsp;
+ ulong newpc = 0, newsp, marker;
+ int eframe_found;
if (!INSTACK(req->sp, bt)) {
ulong irqstack;
@@ -872,13 +873,31 @@ ppc_back_trace(struct gnu_request *req, struct bt_info *bt)
if (BT_REFERENCE_FOUND(bt))
return;
- if((newsp - req->sp) >= sizeof(struct ppc_pt_regs)) {
- /* there might be an exception frame here... */
- ppc_exception_frame(req->sp, bt, req);
- } else if(!IS_KVADDR(newsp) || (newsp < req->sp)) {
- /* also possible one here... */
- ppc_exception_frame(req->sp, bt, req);
+ eframe_found = FALSE;
+ /*
+ * Is this frame an execption one?
+ * In 2.6, 0x72656773 is saved and used
+ * to determine the execption frame.
+ */
+ if (THIS_KERNEL_VERSION < LINUX(2,6,0)) {
+ if (frame && (newsp - req->sp - STACK_FRAME_OVERHEAD >=
+ sizeof(struct ppc_pt_regs)))
+ /* there might be an exception frame here... */
+ eframe_found = TRUE;
+ /* also possible ones here... */
+ else if(!IS_KVADDR(newsp) || (newsp < req->sp))
+ eframe_found = TRUE;
+ else if (STREQ(req->name, ".ret_from_except"))
+ eframe_found = TRUE;
+ } else if ((newsp - req->sp - STACK_FRAME_OVERHEAD) >=
+ sizeof(struct ppc_pt_regs)){
+ readmem(req->sp + STACK_FRAME_MARKER, KVADDR, &marker,
+ sizeof(ulong), "frame marker", FAULT_ON_ERROR);
+ if (marker == STACK_FRAME_REGS_MARKER)
+ eframe_found = TRUE;
}
+ if (eframe_found)
+ ppc_exception_frame(req->sp, bt, req);
if (STREQ(req->name, "start_kernel"))
break;
@@ -944,10 +963,10 @@ ppc_exception_frame(ulong addr, struct bt_info *bt, struct gnu_request *req)
if (BT_REFERENCE_CHECK(bt))
return;
- readmem(addr+16, KVADDR, ®s, sizeof(regs),
+ readmem(addr + STACK_FRAME_OVERHEAD, KVADDR, ®s, sizeof(regs),
"exception frame", FAULT_ON_ERROR);
- switch(regs.trap) {
+ switch(regs.trap & ~0xF) {
case 0x200:
fprintf(fp, "machine check");
break;
--
1.7.6.rc2.11.g13b7
>From 365a7175685413fa58d8773c992ea1b04013a27b Mon Sep 17 00:00:00 2001
From: Toshikazu Nakayama <[email protected]>
Date: Fri, 28 Oct 2011 13:59:29 +0900
Subject: [PATCH 7/8] ppc: devided exception frame printer function
Porting from ppc64.
This update can also get rid of unused GIP[14-31] field for linux-2.6.
Signed-off-by: Toshikazu Nakayama <[email protected]>
---
ppc.c | 175 +++++++++++++++++++++++++++++++++++-----------------------------
1 files changed, 96 insertions(+), 79 deletions(-)
diff --git a/ppc.c b/ppc.c
index 1bbde2c..f2adff0 100755
--- a/ppc.c
+++ b/ppc.c
@@ -17,6 +17,27 @@
#ifdef PPC
#include "defs.h"
+/*
+ * This structure was copied from kernel source
+ * in include/asm-ppc/ptrace.h
+ */
+struct ppc_pt_regs {
+ long gpr[32];
+ long nip;
+ long msr;
+ long orig_gpr3; /* Used for restarting system calls */
+ long ctr;
+ long link;
+ long xer;
+ long ccr;
+ long mq; /* 601 only (not used at present) */
+ /* Used on APUS to hold IPL value. */
+ long trap; /* Reason for being here */
+ long dar; /* Fault registers */
+ long dsisr;
+ long result; /* Result of a system call */
+};
+
static int ppc_kvtop(struct task_context *, ulong, physaddr_t *, int);
static int ppc_uvtop(struct task_context *, ulong, physaddr_t *, int);
static ulong ppc_vmalloc_start(void);
@@ -33,7 +54,9 @@ 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 *);
-static void ppc_exception_frame(ulong, struct bt_info *, struct gnu_request *);
+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_dump_irq(int);
static ulong ppc_get_pc(struct bt_info *);
static ulong ppc_get_sp(struct bt_info *);
@@ -742,27 +765,6 @@ ppc_translate_pte(ulong pte, void *physaddr, ulonglong unused)
* Look for likely exception frames in a stack.
*/
-/*
- * This structure was copied from kernel source
- * in include/asm-ppc/ptrace.h
- */
-struct ppc_pt_regs {
- long gpr[32];
- long nip;
- long msr;
- long orig_gpr3; /* Used for restarting system calls */
- long ctr;
- long link;
- long xer;
- long ccr;
- long mq; /* 601 only (not used at present) */
- /* Used on APUS to hold IPL value. */
- long trap; /* Reason for being here */
- long dar; /* Fault registers */
- long dsisr;
- long result; /* Result of a system call */
-};
-
static int
ppc_eframe_search(struct bt_info *bt)
{
@@ -896,8 +898,20 @@ ppc_back_trace(struct gnu_request *req, struct bt_info *bt)
if (marker == STACK_FRAME_REGS_MARKER)
eframe_found = TRUE;
}
- if (eframe_found)
- ppc_exception_frame(req->sp, bt, req);
+ if (eframe_found) {
+ char *efrm_str;
+ struct ppc_pt_regs regs;
+
+ readmem(req->sp + STACK_FRAME_OVERHEAD, KVADDR, ®s,
+ sizeof(struct ppc_pt_regs),
+ "exception frame", FAULT_ON_ERROR);
+ efrm_str = ppc_check_eframe(®s);
+ if (efrm_str) {
+ ppc_print_eframe(efrm_str, ®s, bt);
+ newpc = regs.nip;
+ newsp = regs.gpr[1];
+ }
+ }
if (STREQ(req->name, "start_kernel"))
break;
@@ -952,65 +966,47 @@ ppc_print_stack_entry(int frame,
}
/*
- * Print exception frame information for PowerPC
+ * Check whether the frame is exception one!
*/
-static void
-ppc_exception_frame(ulong addr, struct bt_info *bt, struct gnu_request *req)
+static char *
+ppc_check_eframe(struct ppc_pt_regs *regs)
{
- int i;
- struct ppc_pt_regs regs;
-
- if (BT_REFERENCE_CHECK(bt))
- return;
-
- readmem(addr + STACK_FRAME_OVERHEAD, KVADDR, ®s, sizeof(regs),
- "exception frame", FAULT_ON_ERROR);
-
- switch(regs.trap & ~0xF) {
+ switch(regs->trap & ~0xF) {
case 0x200:
- fprintf(fp, "machine check");
- break;
+ return "machine check";
case 0x300:
- fprintf(fp, "address error (store)");
- break;
+ return "address error (store)";
case 0x400:
- fprintf(fp, "instruction bus error");
- break;
+ return "instruction bus error";
case 0x500:
- fprintf(fp, "interrupt");
- break;
+ return "interrupt";
case 0x600:
- fprintf(fp, "alingment");
- break;
+ return "alingment";
case 0x700:
- fprintf(fp, "breakpoint trap");
- break;
+ return "breakpoint trap";
case 0x800:
- fprintf(fp, "fpu unavailable");
- break;
+ return "fpu unavailable";
case 0x900:
- fprintf(fp, "decrementer");
- break;
+ return "decrementer";
case 0xa00:
- fprintf(fp, "reserved");
- break;
+ return "reserved";
case 0xb00:
- fprintf(fp, "reserved");
- break;
+ return "reserved";
case 0xc00:
- fprintf(fp, "syscall");
- break;
+ return "syscall";
case 0xd00:
- fprintf(fp, "single-step/watch");
- break;
+ return "single-step/watch";
case 0xe00:
- fprintf(fp, "fp assist");
- break;
- default: /* back trace ended, but no exception frame exists */
- return;
+ return "fp assist";
}
+ /* No exception frame exists */
+ return NULL;
+}
- fprintf(fp, " [%lx] exception frame:", regs.trap);
+static void
+ppc_print_regs(struct ppc_pt_regs *regs)
+{
+ int i;
/* print out the gprs... */
for(i=0; i<32; i++) {
@@ -1018,24 +1014,45 @@ ppc_exception_frame(ulong addr, struct bt_info *bt, struct gnu_request *req)
fprintf(fp, "\n");
fprintf(fp, "R%d:%s %08lx ", i,
- ((i < 10) ? " " : ""), regs.gpr[i]);
+ ((i < 10) ? " " : ""), regs->gpr[i]);
+ /*
+ * In 2.6, some stack frame contains only partial regs set.
+ * For the partial set, only 14 regs will be saved and trap
+ * field will contain 1 in the least significant bit.
+ */
+ if ((i == 13) && (regs->trap & 1))
+ break;
}
fprintf(fp, "\n");
/* print out the rest of the registers */
- fprintf(fp, "NIP: %08lx ", regs.nip);
- fprintf(fp, "MSR: %08lx ", regs.msr);
- fprintf(fp, "OR3: %08lx ", regs.orig_gpr3);
- fprintf(fp, "CTR: %08lx\n", regs.ctr);
-
- fprintf(fp, "LR: %08lx ", regs.link);
- fprintf(fp, "XER: %08lx ", regs.xer);
- fprintf(fp, "CCR: %08lx ", regs.ccr);
- fprintf(fp, "MQ: %08lx\n", regs.mq);
- fprintf(fp, "DAR: %08lx ", regs.dar);
- fprintf(fp, "DSISR: %08lx ", regs.dsisr);
- fprintf(fp, " Syscall Result: %08lx\n", regs.result);
+ fprintf(fp, "NIP: %08lx ", regs->nip);
+ fprintf(fp, "MSR: %08lx ", regs->msr);
+ fprintf(fp, "OR3: %08lx ", regs->orig_gpr3);
+ fprintf(fp, "CTR: %08lx\n", regs->ctr);
+
+ fprintf(fp, "LR: %08lx ", regs->link);
+ fprintf(fp, "XER: %08lx ", regs->xer);
+ fprintf(fp, "CCR: %08lx ", regs->ccr);
+ fprintf(fp, "MQ: %08lx\n", regs->mq);
+ fprintf(fp, "DAR: %08lx ", regs->dar);
+ fprintf(fp, "DSISR: %08lx ", regs->dsisr);
+ fprintf(fp, " Syscall Result: %08lx\n", regs->result);
+}
+
+/*
+ * Print the exception frame information
+ */
+static void
+ppc_print_eframe(char *efrm_str, struct ppc_pt_regs *regs, struct bt_info *bt)
+{
+ if (BT_REFERENCE_CHECK(bt))
+ return;
+
+ fprintf(fp, " %s [%lx] exception frame:", efrm_str, regs->trap);
+ ppc_print_regs(regs);
+ fprintf(fp, "\n");
}
/*
--
1.7.6.rc2.11.g13b7
--
Crash-utility mailing list
[email protected]
https://www.redhat.com/mailman/listinfo/crash-utility