[Crash-utility] [PATCH] ARM: fix unwinding on recent kernels

Rabin Vincent rabin at rab.in
Sat Feb 11 14:30:34 UTC 2012


Unwinding doesn't work on recent ARM kernels since after the following
commit the kernel doesn't perform the prel31_to_addr() conversion of the
offsets in the index table.  The leads to crash not finding the correct
unwind instructions.

http://git.kernel.org/linus/de66a979012dbc66b1ec0125795a3f79ee667b8a

The patch below makes crash do the conversion itself if necessary.

Rabin

diff --git a/unwind_arm.c b/unwind_arm.c
index d86ec63..e804cfb 100644
--- a/unwind_arm.c
+++ b/unwind_arm.c
@@ -71,6 +71,8 @@ struct unwind_table {
 static struct unwind_table	*kernel_unwind_table;
 static struct unwind_table	*module_unwind_tables;
 
+static int index_in_prel31;
+
 struct unwind_ctrl_block {
 	ulong	vrs[16];
 	ulong	insn;
@@ -104,6 +106,7 @@ static int is_core_kernel_text(ulong);
 static struct unwind_table *search_table(ulong);
 static struct unwind_idx *search_index(const struct unwind_table *, ulong);
 static ulong prel31_to_addr(ulong, ulong);
+static void index_prel31_to_addr(struct unwind_table *);
 static int unwind_frame(struct stackframe *, ulong);
 
 /*
@@ -187,6 +190,8 @@ init_kernel_unwind_table(void)
 		goto fail;
 	}
 
+	index_in_prel31 = !is_kernel_text(kernel_unwind_table->idx[0].addr);
+
 	kernel_unwind_table->start = kernel_unwind_table->idx;
 	kernel_unwind_table->end = (struct unwind_idx *)
 		((char *)kernel_unwind_table->idx + idx_size);
@@ -194,6 +199,9 @@ init_kernel_unwind_table(void)
 	kernel_unwind_table->end_addr = (kernel_unwind_table->end - 1)->addr;
 	kernel_unwind_table->kv_base = idx_start;
 
+	if (index_in_prel31)
+		index_prel31_to_addr(kernel_unwind_table);
+
 	if (CRASHDEBUG(1)) {
 		fprintf(fp, "UNWIND: master kernel table start\n");
 		fprintf(fp, "UNWIND: size      : %ld\n", idx_size);
@@ -260,6 +268,9 @@ read_module_unwind_table(struct unwind_table *tbl, ulong addr)
 	tbl->end_addr = TABLE_VALUE(buf, unwind_table_end_addr);
 	tbl->kv_base = idx_start;
 
+	if (index_in_prel31)
+		index_prel31_to_addr(tbl);
+
 	if (CRASHDEBUG(1)) {
 		fprintf(fp, "UNWIND: module table start\n");
 		fprintf(fp, "UNWIND: start     : %p\n", tbl->start);
@@ -571,6 +582,16 @@ prel31_to_addr(ulong addr, ulong insn)
 	return addr + offset;
 }
 
+static void
+index_prel31_to_addr(struct unwind_table *tbl)
+{
+	struct unwind_idx *idx = tbl->start;
+	ulong kvaddr = tbl->kv_base;
+
+	for (; idx < tbl->end; idx++, kvaddr += sizeof(struct unwind_idx))
+		idx->addr = prel31_to_addr(kvaddr, idx->addr);
+}
+
 static int
 unwind_frame(struct stackframe *frame, ulong stacktop)
 {




More information about the Crash-utility mailing list