Received: by 2002:a25:8b12:0:0:0:0:0 with SMTP id i18csp345053ybl; Wed, 21 Aug 2019 20:39:09 -0700 (PDT) X-Google-Smtp-Source: APXvYqyPjkMAzFkELH/WWJsGmCv/6neA4bDMU8nTS8u2Vxe3ctCik6RUHAm1P5GLK8jHTWL0GlYv X-Received: by 2002:a17:90a:9a90:: with SMTP id e16mr3293482pjp.71.1566445149257; Wed, 21 Aug 2019 20:39:09 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1566445149; cv=none; d=google.com; s=arc-20160816; b=sVGN2OOiEFaV2c7pSqkKz0uhgCvXZp74YpOkCXCKLeoyaMfUG16hgKDdU6FGXrVajk /13+mvAfY136d8bHcoh5IHkr2IJWN1bU6xdpEnQq68CmBH1o364qhEabABRGcSFFhE+B 8jw3cCmJ2ULrd5KbECoaaPRmsEYGa3ZlJ74vV3FuonnvGiMjpuojMGBge2xJeVF95h6L 8BGe+c8bfrW9MaL/o95uBab4FPG83b1PVTrbVDtKsr0o0SmCpom2NsuxcO5zL3ulTgzo FGMqaNc2tgswPOYE0/KdWuoN89x3hsw/toW38Mm0eZoW4nsxHzN/HVRu7mK4LVhRq+Wb a3SQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:dkim-signature; bh=MCCskUXcrLlS5LTvVhURJAIX531PoVJ3wIvkbzzRBQk=; b=LQWVNe87GF670BRMerTwbB+/9afi0/ZOpnuV3LPIcT6l3FRB5awnFvARnHUUCsC2kP PoP/YeqRWtCnKfkaEOzOjl3WOMeMN41Z/1Xtg7Obn9C2rRAQp4XGBhNe0YN4FSBzMg3N GX9lXEAcsJo4UUtmf8tO5KsccYnmDpXmiRBIcMKbkOKkJ+UlMn7JilqFHX64i1aIb4VN FH+OX+rax5ejM29SbLSXCFpLwH8NfzUAZvB1MPue4WzEWy24U8rE2WR4yRhY1JJpbXby Pm9q9qKXL9fiK03MCXsH0g0LxGI+p9GpYVleZuEhLnXRdh9FHopa4JKp71KncesBhrvl Uf4g== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20161025 header.b=Cf9CApzJ; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id u3si15420167pgm.122.2019.08.21.20.38.54; Wed, 21 Aug 2019 20:39:09 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20161025 header.b=Cf9CApzJ; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730287AbfHVD0h (ORCPT + 99 others); Wed, 21 Aug 2019 23:26:37 -0400 Received: from mail-pg1-f194.google.com ([209.85.215.194]:46977 "EHLO mail-pg1-f194.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727553AbfHVD0h (ORCPT ); Wed, 21 Aug 2019 23:26:37 -0400 Received: by mail-pg1-f194.google.com with SMTP id m3so2594311pgv.13 for ; Wed, 21 Aug 2019 20:26:36 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=mime-version:references:in-reply-to:from:date:message-id:subject:to :cc; bh=MCCskUXcrLlS5LTvVhURJAIX531PoVJ3wIvkbzzRBQk=; b=Cf9CApzJnmHgZO/G8erfps/1ZvmfBBRlVQePSnZaeLyc5NT/ek+5kg+4tXORFNlOVP xABL1S0jWhMNkF0vDkxMyMaHZa02dsBQOiIebT1xYkYdPhmu/IR8vzGB8HaYbRo2Demf gG/v5NuBJBWX1ddhi9rSh+9HSd40kf3VY7E+X/oXwrbhv5Zrx8I5EvXwwmsZNxFMLYxl Str4mHqzxaTA5ScfiKLIieFPaVS6g3IjgJ1FF7nG/zV5fzSKe1h2YcZwITppAbte7Kl8 KPv8HZehE4T3IBDkvkRJ9MnjUS6jvMrA0jUHCHfNOfLU792kDMnl6lZP29KLPWl8YJJm iVXw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to:cc; bh=MCCskUXcrLlS5LTvVhURJAIX531PoVJ3wIvkbzzRBQk=; b=giAxN797NTHAj+qeBDFUxBweaWZLbCBBSBqtf4x+H8b47PmvlV8wIXif2rUfjpA1Lr U+COucH7Th55vhu7dKjBGwgAOgvJDwZE0+hT8aVDwvbZzauMvZfRndG+93ldhKzO8qRx N/ZEUxtH4B7L9T/PlyYyook2EoT5PqBJK8MzTAokzwneZXJI7zhpcX2hvf2Yr6jTekb9 0gQ25nO7NF6EBpkhDglxCg5G7Id393JpwFwPvIh1GpShQAl6u8uvt6aOiDnt1wMtdj/X /6ykqouhYBe9VmiCrDt4kvhmWguXNNdqUS049FZ+TndrZUHA9m83bSfbJUoOi1oh29qb GjZA== X-Gm-Message-State: APjAAAXA4MbaMXuc/kYuLmYGGRZ36mJD50lQoEIOYbVbF2VtW1dnJPd9 gOXfFp0gl6XKzLj7FSuFzGnRKvBSpgEguubTQVx6wQ== X-Received: by 2002:a65:690b:: with SMTP id s11mr27819692pgq.10.1566444395734; Wed, 21 Aug 2019 20:26:35 -0700 (PDT) MIME-Version: 1.0 References: <20190821174619.21935-1-nhuck@google.com> In-Reply-To: <20190821174619.21935-1-nhuck@google.com> From: Nick Desaulniers Date: Wed, 21 Aug 2019 20:26:23 -0700 Message-ID: Subject: Re: [PATCH v2] ARM: UNWINDER_FRAME_POINTER implementation for Clang To: Nathan Huckleberry Cc: Russell King , Linux ARM , LKML , clang-built-linux , =?UTF-8?B?TWlsZXMgQ2hlbiAo6Zmz5rCR5qi6KQ==?= , Tri Vo , Arnd Bergmann , Ard Biesheuvel Content-Type: text/plain; charset="UTF-8" Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On Wed, Aug 21, 2019 at 10:46 AM Nathan Huckleberry wrote: > > The stackframe setup when compiled with clang is different. > Since the stack unwinder expects the gcc stackframe setup it > fails to print backtraces. This patch adds support for the > clang stackframe setup. > > Link: https://github.com/ClangBuiltLinux/linux/issues/35 > Cc: clang-built-linux@googlegroups.com > Suggested-by: Tri Vo > Signed-off-by: Nathan Huckleberry > --- > Changes from v1->v2 > * Fix indentation in various files > * Swap spaces for tabs > * Rename Ldsi to Lopcode > * Remove unused Ldsi entry > > arch/arm/Kconfig.debug | 2 +- > arch/arm/Makefile | 5 +- > arch/arm/lib/Makefile | 8 +- > arch/arm/lib/backtrace-clang.S | 229 +++++++++++++++++++++++++++++++++ > 4 files changed, 241 insertions(+), 3 deletions(-) > create mode 100644 arch/arm/lib/backtrace-clang.S > > diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug > index 85710e078afb..b9c674ec19e0 100644 > --- a/arch/arm/Kconfig.debug > +++ b/arch/arm/Kconfig.debug > @@ -56,7 +56,7 @@ choice > > config UNWINDER_FRAME_POINTER > bool "Frame pointer unwinder" > - depends on !THUMB2_KERNEL && !CC_IS_CLANG > + depends on !THUMB2_KERNEL > select ARCH_WANT_FRAME_POINTERS > select FRAME_POINTER > help > diff --git a/arch/arm/Makefile b/arch/arm/Makefile > index c3624ca6c0bc..6f251c201db0 100644 > --- a/arch/arm/Makefile > +++ b/arch/arm/Makefile > @@ -36,7 +36,10 @@ KBUILD_CFLAGS += $(call cc-option,-mno-unaligned-access) > endif > > ifeq ($(CONFIG_FRAME_POINTER),y) > -KBUILD_CFLAGS +=-fno-omit-frame-pointer -mapcs -mno-sched-prolog > +KBUILD_CFLAGS +=-fno-omit-frame-pointer > +ifeq ($(CONFIG_CC_IS_GCC),y) > +KBUILD_CFLAGS += -mapcs -mno-sched-prolog > +endif > endif > > ifeq ($(CONFIG_CPU_BIG_ENDIAN),y) > diff --git a/arch/arm/lib/Makefile b/arch/arm/lib/Makefile > index b25c54585048..6d2ba454f25b 100644 > --- a/arch/arm/lib/Makefile > +++ b/arch/arm/lib/Makefile > @@ -5,7 +5,7 @@ > # Copyright (C) 1995-2000 Russell King > # > > -lib-y := backtrace.o changebit.o csumipv6.o csumpartial.o \ > +lib-y := changebit.o csumipv6.o csumpartial.o \ > csumpartialcopy.o csumpartialcopyuser.o clearbit.o \ > delay.o delay-loop.o findbit.o memchr.o memcpy.o \ > memmove.o memset.o setbit.o \ > @@ -19,6 +19,12 @@ lib-y := backtrace.o changebit.o csumipv6.o csumpartial.o \ > mmu-y := clear_user.o copy_page.o getuser.o putuser.o \ > copy_from_user.o copy_to_user.o > > +ifdef CONFIG_CC_IS_CLANG > + lib-y += backtrace-clang.o > +else > + lib-y += backtrace.o > +endif > + > # using lib_ here won't override already available weak symbols > obj-$(CONFIG_UACCESS_WITH_MEMCPY) += uaccess_with_memcpy.o > > diff --git a/arch/arm/lib/backtrace-clang.S b/arch/arm/lib/backtrace-clang.S > new file mode 100644 > index 000000000000..6f2a8a57d0fb > --- /dev/null > +++ b/arch/arm/lib/backtrace-clang.S > @@ -0,0 +1,229 @@ > +/* SPDX-License-Identifier: GPL-2.0-only */ > +/* > + * linux/arch/arm/lib/backtrace-clang.S > + * > + * Copyright (C) 2019 Nathan Huckleberry > + * > + */ > +#include > +#include > +#include > + .text > + > +/* fp is 0 or stack frame */ > + > +#define frame r4 > +#define sv_fp r5 > +#define sv_pc r6 > +#define mask r7 > +#define sv_lr r8 > + > +ENTRY(c_backtrace) > + > +#if !defined(CONFIG_FRAME_POINTER) || !defined(CONFIG_PRINTK) > + ret lr > +ENDPROC(c_backtrace) > +#else > + > + > +/* > + * Clang does not store pc or sp in function prologues > + * so we don't know exactly where the function > + * starts. To quickly re-wrap text (if you're using vim) such as with comments like these: shift+v (VISUAL LINE MODE) j or k to highlight lines gq (to rewrap) You may need `set cc=80` (not sure). > + * > + * We can treat the current frame's lr as the saved pc and the > + * preceding frame's lr as the current frame's lr, > + * but we can't trace the most recent call. > + * Inserting a false stack frame allows us to reference the > + * function called last in the stacktrace. > + * > + * If the call instruction was a bl we can look at the callers > + * branch instruction to calculate the saved pc. > + * We can recover the pc in most cases, but in cases such as > + * calling function pointers we cannot. In this > + * case, default to using the lr. This will be > + * some address in the function, but will not > + * be the function start. > + * > + * Unfortunately due to the stack frame layout we can't dump > + * r0 - r3, but these are less frequently saved. I guess if they were spilled, but I'm ok with this; I'd rather have a working unwinder than disabled config. The printing is a debug feature that's nice to have, but the main focus should be unwinding. We can always revisit improving support. > + * > + * Stack frame layout: > + * > + * saved lr > + * frame=> saved fp > + * optionally saved caller registers (r4 - r10) > + * optionally saved arguments (r0 - r3) > + * > + * > + * > + * Functions start with the following code sequence: > + * corrected pc => stmfd sp!, {..., fp, lr} > + * add fp, sp, #x > + * stmfd sp!, {r0 - r3} (optional) > + * > + * > + * > + * > + * > + * > + * The diagram below shows an example stack setup > + * for dump_stack. > + * > + * The frame for c_backtrace has pointers to the > + * code of dump_stack. This is why the frame of > + * c_backtrace is used to for the pc calculation > + * of dump_stack. This is why we must move back > + * a frame to print dump_stack. > + * > + * The stored locals for dump_stack are in dump_stack's > + * frame. This means that to fully print dump_stack's frame > + * we need both the frame for dump_stack (for locals) and the > + * frame that was called by dump_stack (for pc). > + * > + * To print locals we must know where the function start is. If > + * we read the function prologue opcodes we can determine > + * which variables are stored in the stack frame. > + * > + * To find the function start of dump_stack we can look at the > + * stored LR of show_stack. It points at the instruction > + * directly after the bl dump_stack. We can then read the > + * offset from the bl opcode to determine where the branch takes us. > + * The address calculated must be the start of dump_stack. > + * > + * c_backtrace frame dump_stack: > + * {[LR] } ============| ... > + * {[FP] } =======| | bl c_backtrace > + * | |=> ... > + * {[R4-R10]} | > + * {[R0-R3] } | show_stack: > + * dump_stack frame | ... > + * {[LR] } =============| bl dump_stack > + * {[FP] } <=======| |=> ... > + * {[R4-R10]} > + * {[R0-R3] } > + */ > + ===> > +stmfd sp!, {r4 - r9, fp, lr} @ Save an extra register > + @ to ensure 8 byte alignment > +movs frame, r0 @ if frame pointer is zero > +beq no_frame @ we have no stack frames > + > +tst r1, #0x10 @ 26 or 32-bit mode? > +moveq mask, #0xfc000003 > +movne mask, #0 @ mask for 32-bit <== this section of the patch has weird indentation. The rest uses 2 tabs, this has none. > + > +/* > + * Switches the current frame to be the frame for dump_stack. > + */ > + add frame, sp, #24 @ switch to false frame > +for_each_frame: tst frame, mask @ Check for address exceptions > + bne no_frame > + > +/* > + * sv_fp is the stack frame with the locals for the current considered > + * function. > + * > + * sv_pc is the saved lr frame the frame above. This is a pointer to a > + * code address within the current considered function, but > + * it is not the function start. This value gets updated to be > + * the function start later if it is possible. > + */ > +1001: ldr sv_pc, [frame, #4] @ get saved 'pc' > +1002: ldr sv_fp, [frame, #0] @ get saved fp > + > + teq sv_fp, mask @ make sure next frame exists > + beq no_frame > + > +/* > + * sv_lr is the lr from the function that called the current function. This > + * is a pointer to a code address in the current function's caller. > + * sv_lr-4 is the instruction used to call the current function. > + * > + * This sv_lr can be used to calculate the function start if the function > + * was called using a bl instruction. If the function start > + * can be recovered sv_pc is overwritten with the function start. > + * > + * If the current function was called using a function pointer we cannot > + * recover the function start and instead continue with sv_pc as > + * an arbitrary value within the current function. If this is the case > + * we cannot print registers for the current function, but the stacktrace > + * is still printed properly. > + */ > +1003: ldr sv_lr, [sv_fp, #4] @ get saved lr from next frame > + > + ldr r0, [sv_lr, #-4] @ get call instruction > + ldr r3, .Lopcode+4 > + and r2, r3, r0 @ is this a bl call > + teq r2, r3 > + bne finished_setup @ give up if it's not > + and r0, #0xffffff @ get call offset 24-bit int > + lsl r0, r0, #8 @ sign extend offset > + asr r0, r0, #8 > + ldr sv_pc, [sv_fp, #4] @ get lr address > + add sv_pc, sv_pc, #-4 @ get call instruction address > + add sv_pc, sv_pc, #8 @ take care of prefetch > + add sv_pc, sv_pc, r0, lsl #2@ find function start > + > +finished_setup: > + > + bic sv_pc, sv_pc, mask @ mask PC/LR for the mode > + > +/* > + * Print the function (sv_pc) and where it was called > + * from (sv_lr). > + */ > +1004: mov r0, sv_pc > + > + mov r1, sv_lr > + mov r2, frame > + bic r1, r1, mask @ mask PC/LR for the mode > + bl dump_backtrace_entry > + > +/* > + * Test if the function start is a stmfd instruction > + * to determine which registers were stored in the function > + * prologue. > + * > + * If we could not recover the sv_pc because we were called through > + * a function pointer the comparison will fail and no registers > + * will print. Will we still unwind though? > + */ > +1005: ldr r1, [sv_pc, #0] @ if stmfd sp!, {..., fp, lr} > + ldr r3, .Lopcode @ instruction exists, > + teq r3, r1, lsr #11 > + ldr r0, [frame] @ locals are stored in > + @ the preceding frame > + subeq r0, r0, #4 > + bleq dump_backtrace_stm @ dump saved registers > + > +/* > + * If we are out of frames or if the next frame is invalid. > + */ > + teq sv_fp, #0 @ zero saved fp means > + beq no_frame @ no further frames > + > + cmp sv_fp, frame @ next frame must be > + mov frame, sv_fp @ above the current frame > + bhi for_each_frame > + > +1006: adr r0, .Lbad > + mov r1, frame > + bl printk > +no_frame: ldmfd sp!, {r4 - r9, fp, pc} > +ENDPROC(c_backtrace) > + .pushsection __ex_table,"a" > + .align 3 > + .long 1001b, 1006b > + .long 1002b, 1006b > + .long 1003b, 1006b > + .long 1004b, 1006b > + .long 1005b, 1006b > + .popsection > + > +.Lbad: .asciz "Backtrace aborted due to bad frame pointer <%p>\n" > + .align > +.Lopcode: .word 0xe92d4800 >> 11 @ stmfd sp!, {... fp, lr} > + .word 0x0b000000 @ bl if these bits are set > + > +#endif > -- > 2.23.0.rc1.153.gdeed80330f-goog > OK, with you patch applied on today's Linux next, CONFIG_UNWINDER_FRAME_POINTER, and ToT Clang: $ qemu-system-arm -kernel arch/arm/boot/zImage -nographic -m 2048 --append "console=ttyAMA0 root=/dev/ram0" -machine virt [ 0.000000] Linux version 5.3.0-rc5-07709-gac2d7d4a10c1-dirty (ndesaulniers@ndesaulniers1.mtv.corp.google.com) (clang version 10.0.0 (https://github.com/llvm/llvm-project.git da648ab8de3638ff82d6b9349c603b854a0224d6)) #53 SMP Wed Aug 21 20:05:15 PDT 2019 ... [ 0.957046] Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(1,0) [ 0.957490] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 5.3.0-rc5-07709-gac2d7d4a10c1-dirty #53 [ 0.957808] Hardware name: Generic DT based system [ 0.958046] Backtrace: [ 0.958504] [] (dump_backtrace) from [] (show_stack+0x14/0x18) [ 0.958844] r10:c16f585c r6:00000000 r5:c198c7e4 r4:600000d3 [ 0.959085] [] (show_stack) from [] (dump_stack+0xac/0xd8) [ 0.959358] [] (dump_stack) from [] (panic+0x118/0x354) [ 0.959568] r5:c19a61b5 r4:c1427ce5 [ 0.959722] [] (panic) from [] (mount_block_root+0x13c/0x1f0) [ 0.959947] [] (mount_block_root) from [] (mount_root+0xb0/0xb4) [ 0.960210] r10:00000000 r9:00000000 r8:00000000 r7:00000000 r6:00000000 r5:00100000 [ 0.960492] r4:c1427d49 [ 0.960600] [] (mount_root) from [] (prepare_namespace+0x1ec/0x1f0) [ 0.960886] r5:c19a3d30 r4:c16f5868 [ 0.961021] [] (prepare_namespace) from [] (kernel_init_freeable+0xe0/0xf4) [ 0.961330] r5:00000000 r4:c19a3d1c [ 0.961468] [] (kernel_init_freeable) from [] (kernel_init+0xc/0x2ac) [ 0.961761] r5:c10868cc r4:00000000 [ 0.961913] [] (kernel_init) from [] (ret_from_fork+0x14/0x2c) [ 0.962210] Exception stack(0xea09bf94 to 0xea09bfdc) [ 0.962490] bf80: c10868d8 00000000 c10868cc [ 0.962883] bfa0: 00000000 00000000 00000000 c03010e8 00000000 00000000 00000000 00000000 [ 0.963202] bfc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 [ 0.963936] ---[ end Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(1,0) ]--- For comparison, the reference implementation: [ 0.000000] Linux version 5.3.0-rc5-07709-gac2d7d4a10c1-dirty (ndesaulniers@ndesaulniers1.mtv.corp.google.com) (gcc version 8.2.0 (Debian 8.2.0-14+build1)) #54 SMP Wed Aug 21 20:15:27 PDT 2019 ... [ 1.048134] Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(1,0) [ 1.048617] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 5.3.0-rc5-07709-gac2d7d4a10c1-dirty #54 [ 1.048935] Hardware name: Generic DT based system [ 1.049191] Backtrace: [ 1.049663] [] (dump_backtrace) from [] (show_stack+0x18/0x1c) [ 1.050038] r7:c16ed85c r6:600000d3 r5:00000000 r4:c198f804 [ 1.050292] [] (show_stack) from [] (dump_stack+0xbc/0xd0) [ 1.050581] [] (dump_stack) from [] (panic+0x118/0x330) [ 1.050834] r7:c16ed85c r6:c13404fc r5:00000000 r4:c19a5870 [ 1.051078] [] (panic) from [] (mount_block_root+0x264/0x284) [ 1.051344] r3:0ed1c175 r2:0ed1c175 r1:ea09be84 r0:c13404fc [ 1.051553] r7:c16ed85c [ 1.051661] [] (mount_block_root) from [] (mount_root+0x124/0x140) [ 1.051936] r10:ffffe000 r9:c16ed858 r8:c19a3400 r7:c1809100 r6:00000008 r5:c1804c48 [ 1.052238] r4:00100000 [ 1.052351] [] (mount_root) from [] (prepare_namespace+0x184/0x1cc) [ 1.052638] r10:ffffe000 r9:c16ed858 r8:c19a3400 r7:c19a3400 r6:00000008 r5:c19a3430 [ 1.052915] r4:c16ed85c [ 1.053025] [] (prepare_namespace) from [] (kernel_init_freeable+0x2f8/0x308) [ 1.053337] r6:00000008 r5:c177b7c0 r4:c16ed838 [ 1.053507] [] (kernel_init_freeable) from [] (kernel_init+0x10/0x118) [ 1.053798] r10:00000000 r9:00000000 r8:00000000 r7:00000000 r6:00000000 r5:c0f6cea0 [ 1.054083] r4:00000000 [ 1.054190] [] (kernel_init) from [] (ret_from_fork+0x14/0x2c) [ 1.054501] Exception stack(0xea09bfb0 to 0xea09bff8) [ 1.054792] bfa0: 00000000 00000000 00000000 00000000 [ 1.055169] bfc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 [ 1.055526] bfe0: 00000000 00000000 00000000 00000000 00000013 00000000 [ 1.055795] r5:c0f6cea0 r4:00000000 [ 1.056410] ---[ end Kernel panic - not syncing: VFS: Unable to mount root fs on unknown-block(1,0) ]--- So the stack traces look comparable (same unwind "path"). Looks like GCC spilled r0-r3 in panic(), but not much else. I guess Clang could have spilled these anywhere and we simply wont be able to print them. Maybe making the comment about this in you patch ALL CAPS might draw attention to it in case someone ever notices a difference between the unwind printout and the disassembly, but I assume that's unlikely, but I also don't know if this functionality is relied upon heavily for debugging. In that sense: Tested-by: Nick Desaulniers (you can carry that on to v3) With the above suggestions, I'd be happy to then add my reviewed by tag. Thanks for all of the work that went into this. -- Thanks, ~Nick Desaulniers