The MIPS kernel's pt_regs structure changes between kernel versions.
For example, fields are inserted into the middle based on build time
options, and the amount of padding at the head of the structure was
changed relatively recently.
To handle this, split the structure definition into two parts and get
the offsets of these two parts dynamically.
---
defs.h | 8 ++++++--
mips.c | 57 +++++++++++++++++++++++++++++++++++++--------------------
symbols.c | 4 ++++
3 files changed, 47 insertions(+), 22 deletions(-)
diff --git a/defs.h b/defs.h
index 853fa62..d2a8215 100644
--- a/defs.h
+++ b/defs.h
@@ -1938,6 +1938,8 @@ struct offset_table { /* stash of commonly-used
offsets */
long mm_struct_mm_count;
long task_struct_thread_reg29;
long task_struct_thread_reg31;
+ long pt_regs_regs;
+ long pt_regs_cp0_badvaddr;
};
struct size_table { /* stash of commonly-used sizes */
@@ -5612,12 +5614,14 @@ struct mips_regset {
ulong regs[45];
};
-struct mips_pt_regs {
- ulong pad0[8];
+struct mips_pt_regs_main {
ulong regs[32];
ulong cp0_status;
ulong hi;
ulong lo;
+};
+
+struct mips_pt_regs_cp0 {
ulong cp0_badvaddr;
ulong cp0_cause;
ulong cp0_epc;
diff --git a/mips.c b/mips.c
index e5567f0..bf81115 100644
--- a/mips.c
+++ b/mips.c
@@ -320,28 +320,34 @@ mips_kvtop(struct task_context *tc, ulong kvaddr, physaddr_t *paddr,
int verbose
}
static void
-mips_dump_exception_stack(struct bt_info *bt, struct mips_pt_regs *regs)
+mips_dump_exception_stack(struct bt_info *bt, char *pt_regs)
{
+ struct mips_pt_regs_main *mains;
+ struct mips_pt_regs_cp0 *cp0;
int i;
char buf[BUFSIZE];
+ mains = (struct mips_pt_regs_main *) (pt_regs + OFFSET(pt_regs_regs));
+ cp0 = (struct mips_pt_regs_cp0 *) \
+ (pt_regs + OFFSET(pt_regs_cp0_badvaddr));
+
for (i = 0; i < 32; i += 4) {
fprintf(fp, " $%2d : %08lx %08lx %08lx %08lx\n",
- i, regs->regs[i], regs->regs[i+1],
- regs->regs[i+2], regs->regs[i+3]);
+ i, mains->regs[i], mains->regs[i+1],
+ mains->regs[i+2], mains->regs[i+3]);
}
- fprintf(fp, " Hi : %08lx\n", regs->hi);
- fprintf(fp, " Lo : %08lx\n", regs->lo);
+ fprintf(fp, " Hi : %08lx\n", mains->hi);
+ fprintf(fp, " Lo : %08lx\n", mains->lo);
- value_to_symstr(regs->cp0_epc, buf, 16);
- fprintf(fp, " epc : %08lx %s\n", regs->cp0_epc, buf);
+ value_to_symstr(cp0->cp0_epc, buf, 16);
+ fprintf(fp, " epc : %08lx %s\n", cp0->cp0_epc, buf);
- value_to_symstr(regs->regs[31], buf, 16);
- fprintf(fp, " ra : %08lx %s\n", regs->regs[31], buf);
+ value_to_symstr(mains->regs[31], buf, 16);
+ fprintf(fp, " ra : %08lx %s\n", mains->regs[31], buf);
- fprintf(fp, " Status: %08lx\n", regs->cp0_status);
- fprintf(fp, " Cause : %08lx\n", regs->cp0_cause);
- fprintf(fp, " BadVA : %08lx\n", regs->cp0_badvaddr);
+ fprintf(fp, " Status: %08lx\n", mains->cp0_status);
+ fprintf(fp, " Cause : %08lx\n", cp0->cp0_cause);
+ fprintf(fp, " BadVA : %08lx\n", cp0->cp0_badvaddr);
}
struct mips_unwind_frame {
@@ -431,10 +437,10 @@ mips_dump_backtrace_entry(struct bt_info *bt, struct syment *sym,
}
if (mips_is_exception_entry(sym)) {
- struct mips_pt_regs ptregs;
+ char pt_regs[SIZE(pt_regs)];
- GET_STACK_DATA(current->sp, &ptregs, sizeof(ptregs));
- mips_dump_exception_stack(bt, &ptregs);
+ GET_STACK_DATA(current->sp, &pt_regs, SIZE(pt_regs));
+ mips_dump_exception_stack(bt, pt_regs);
}
if (bt->flags & BT_FULL) {
@@ -579,13 +585,20 @@ mips_back_trace_cmd(struct bt_info *bt)
}
if (mips_is_exception_entry(symbol)) {
- struct mips_pt_regs ptregs;
+ struct mips_pt_regs_main *mains;
+ struct mips_pt_regs_cp0 *cp0;
+ char pt_regs[SIZE(pt_regs)];
+
+ mains = (struct mips_pt_regs_main *) \
+ (pt_regs + OFFSET(pt_regs_regs));
+ cp0 = (struct mips_pt_regs_cp0 *) \
+ (pt_regs + OFFSET(pt_regs_cp0_badvaddr));
- GET_STACK_DATA(current.sp, &ptregs, sizeof(ptregs));
+ GET_STACK_DATA(current.sp, pt_regs, sizeof(pt_regs));
- previous.ra = ptregs.regs[31];
- previous.sp = ptregs.regs[29];
- current.ra = ptregs.cp0_epc;
+ previous.ra = mains->regs[31];
+ previous.sp = mains->regs[29];
+ current.ra = cp0->cp0_epc;
if (CRASHDEBUG(8))
fprintf(fp, "exception pc %#lx ra %#lx sp %lx\n",
@@ -666,6 +679,10 @@ mips_stackframe_init(void)
task_struct_thread + thread_reg29;
ASSIGN_OFFSET(task_struct_thread_reg31) =
task_struct_thread + thread_reg31;
+
+ STRUCT_SIZE_INIT(pt_regs, "pt_regs");
+ MEMBER_OFFSET_INIT(pt_regs_regs, "pt_regs", "regs");
+ MEMBER_OFFSET_INIT(pt_regs_cp0_badvaddr, "pt_regs",
"cp0_badvaddr");
}
static void
diff --git a/symbols.c b/symbols.c
index dd87cbc..48d9f58 100644
--- a/symbols.c
+++ b/symbols.c
@@ -8993,6 +8993,10 @@ dump_offset_table(char *spec, ulong makestruct)
OFFSET(rt_prio_array_queue));
fprintf(fp, " prio_array_nr_active: %ld\n",
OFFSET(prio_array_nr_active));
+ fprintf(fp, " pt_regs_regs: %ld\n",
+ OFFSET(pt_regs_regs));
+ fprintf(fp, " pt_regs_cp0_badvaddr: %ld\n",
+ OFFSET(pt_regs_cp0_badvaddr));
fprintf(fp, " user_regs_struct_ebp: %ld\n",
OFFSET(user_regs_struct_ebp));
fprintf(fp, " user_regs_struct_eip: %ld\n",
--
1.7.10.4