diff mbox series

arm64: symbolize user-space stack on SIGSEGV

Message ID 20210817215827.2763811-1-pcc@google.com (mailing list archive)
State New, archived
Headers show
Series arm64: symbolize user-space stack on SIGSEGV | expand

Commit Message

Peter Collingbourne Aug. 17, 2021, 9:58 p.m. UTC
On arm64, dump the userspace stack to the console when a SIGSEGV
occurs. Print filename+offset to allow symbolization.

This is a patch that I frequently need to apply locally in order to
debug segfaults that occur in environments where attaching a debugger
is infeasible.

Although I don't expect this patch to be applied to the mainline
kernel, I am posting it in case anyone else would find it useful
(and because I almost lost track of it recently, and I don't want to
have to write it again).

Signed-off-by: Peter Collingbourne <pcc@google.com>
---
 arch/arm64/mm/fault.c | 33 +++++++++++++++++++++++++++++++++
 1 file changed, 33 insertions(+)
diff mbox series

Patch

diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
index 349c488765ca..8db82788e80b 100644
--- a/arch/arm64/mm/fault.c
+++ b/arch/arm64/mm/fault.c
@@ -526,6 +526,38 @@  static bool is_write_abort(unsigned int esr)
 	return (esr & ESR_ELx_WNR) && !(esr & ESR_ELx_CM);
 }
 
+static void symbolize_addr(const char *prefix, unsigned long addr)
+{
+	struct vm_area_struct *vma = find_vma(current->mm, addr);
+	if (vma && vma->vm_file) {
+		char buf[1024];
+		char *c = d_path(&vma->vm_file->f_path, buf, 1024);
+		printk(KERN_ERR "%s = 0x%lx (%s + 0x%lx)\n", prefix, addr, c,
+		       addr - vma->vm_start + vma->vm_pgoff * PAGE_SIZE);
+	} else {
+		printk(KERN_ERR "%s = 0x%lx", prefix, addr);
+	}
+}
+
+static void symbolize_stack(void)
+{
+	int i;
+	unsigned long frame = current_pt_regs()->regs[29];
+
+	symbolize_addr("pc", current_pt_regs()->pc);
+	symbolize_addr("lr", current_pt_regs()->regs[30]);
+
+	for (i = 0; i != 64; ++i) {
+		unsigned long ret_addr;
+		unsafe_get_user(ret_addr, (unsigned long __user *)(frame + 8),
+				end);
+		symbolize_addr("ret_addr", ptrauth_clear_pac(ret_addr));
+
+		unsafe_get_user(frame, (unsigned long __user *)frame, end);
+	}
+end:;
+}
+
 static int __kprobes do_page_fault(unsigned long far, unsigned int esr,
 				   struct pt_regs *regs)
 {
@@ -671,6 +703,7 @@  static int __kprobes do_page_fault(unsigned long far, unsigned int esr,
 		 * Something tried to access memory that isn't in our memory
 		 * map.
 		 */
+		symbolize_stack();
 		arm64_force_sig_fault(SIGSEGV,
 				      fault == VM_FAULT_BADACCESS ? SEGV_ACCERR : SEGV_MAPERR,
 				      far, inf->name);