On Wed, Dec 01, 2010 at 11:27:32AM -0500, ext Dave Anderson wrote:
----- "Mika Westerberg" <ext-mika.1.westerberg(a)nokia.com> wrote:
> Enhance backtracing code to print out userspace registers in case we
> are at syscall entry. Other architectures supported by crash are
> already doing this.
>
> Signed-off-by: Mika Westerberg <ext-mika.1.westerberg(a)nokia.com>
> ---
> I tested this with both unwind tables and framepointers enabled on
> my test vmcores, and also on live system.
Works well on my sample dumpfiles -- queued for the next release.
Dave,
I just noticed that there's a bug in this patch - it handles slow
syscall return path wrong.
Below is a patch which applies on top of this and fixes the slow
path also. If you prefer, I can also send you a single patch which
combines both of the patches.
Sorry about the mess.
Regards,
MW
diff --git a/arm.c b/arm.c
index a8a34b9..751fe00 100644
--- a/arm.c
+++ b/arm.c
@@ -31,7 +31,7 @@ static int arm_verify_symbol(const char *, ulong, char);
static int arm_is_module_addr(ulong);
static int arm_is_kvaddr(ulong);
static int arm_in_exception_text(ulong);
-static int arm_in_ret_from_syscall(ulong);
+static int arm_in_ret_from_syscall(ulong, int *);
static void arm_back_trace(struct bt_info *);
static void arm_back_trace_cmd(struct bt_info *);
static ulong arm_processor_speed(void);
@@ -669,13 +669,44 @@ arm_in_exception_text(ulong pc)
}
/*
- * Returns TRUE if given pc points to a return from syscall entrypoint.
+ * Returns TRUE if given pc points to a return from syscall
+ * entrypoint. In case the function returns TRUE and if offset is given,
+ * it is filled with the offset that should be added to the SP to get
+ * address of the exception frame where the user registers are.
*/
static int
-arm_in_ret_from_syscall(ulong pc)
+arm_in_ret_from_syscall(ulong pc, int *offset)
{
- return (pc == symbol_value("ret_fast_syscall") ||
- pc == symbol_value("ret_slow_syscall"));
+ /*
+ * On fast syscall return path, the stack looks like:
+ *
+ * SP + 0 {r4, r5}
+ * SP + 8 user pt_regs
+ *
+ * The asm syscall handler pushes fifth and sixth registers
+ * onto the stack before calling the actual syscall handler.
+ *
+ * So in order to print out the user registers at the time
+ * the syscall was made, we need to adjust SP for 8.
+ */
+ if (pc == symbol_value("ret_fast_syscall")) {
+ if (offset)
+ *offset = 8;
+ return TRUE;
+ }
+
+ /*
+ * In case we are on the slow syscall path, the SP already
+ * points to the start of the user registers hence no
+ * adjustments needs to be done.
+ */
+ if (pc == symbol_value("ret_slow_syscall")) {
+ if (offset)
+ *offset = 0;
+ return TRUE;
+ }
+
+ return FALSE;
}
/*
@@ -1178,6 +1209,7 @@ arm_dump_backtrace_entry(struct bt_info *bt, int level, ulong from,
ulong sp)
{
struct load_module *lm;
const char *name;
+ int offset = 0;
name = closest_symbol(bt->instptr);
@@ -1201,23 +1233,10 @@ arm_dump_backtrace_entry(struct bt_info *bt, int level, ulong
from, ulong sp)
if (arm_in_exception_text(bt->instptr)) {
arm_dump_exception_stack(sp, sp + sizeof(struct arm_pt_regs));
- } else if (arm_in_ret_from_syscall(from)) {
- /*
- * When we are returning from the syscall, here is
- * what the stack frame looks like:
- *
- * SP + 0 {r4, r5}
- * SP + 8 user pt_regs
- *
- * The asm syscall handler pushes fifth and sixth
- * registers onto the stack before calling the
- * actual syscall handler.
- *
- * So in order to print out the user registers when
- * the syscall was made, we need to adjust sp for 8.
- */
- arm_dump_exception_stack(sp + 8,
- sp + 8 + sizeof(struct arm_pt_regs));
+ } else if (arm_in_ret_from_syscall(from, &offset)) {
+ ulong nsp = sp + offset;
+
+ arm_dump_exception_stack(nsp, nsp + sizeof(struct arm_pt_regs));
}
if (bt->flags & BT_FULL) {