mbox series

[0/8] unwind, arm64: add sframe unwinder for kernel

Message ID 20250127213310.2496133-1-wnliu@google.com (mailing list archive)
Headers show
Series unwind, arm64: add sframe unwinder for kernel | expand

Message

Weinan Liu Jan. 27, 2025, 9:33 p.m. UTC
This patchset implements a generic kernel sframe-based [1] unwinder.
The main goal is to support reliable stacktraces on arm64.

On x86 orc unwinder provides reliable stacktraces. But arm64 misses the
required support from objtool: it cannot generate orc unwind tables for
arm64.

Currently, there's already a sframe unwinder proposed for userspace: [2].
Since the sframe unwind table algorithm is similar, these two proposal
could integrate common functionality in the future.

There are some incomplete features or challenges:
  - The unwinder doesn't yet work with kernel modules. The `start_addr` of
    FRE from kernel modules doesn't appear correct, preventing us from
    unwinding functions from kernel modules.
  - Currently, only GCC supports sframe.

Ref:
[1]: https://sourceware.org/binutils/docs/sframe-spec.html
[2]: https://lore.kernel.org/lkml/cover.1730150953.git.jpoimboe@kernel.org/

Madhavan T. Venkataraman (1):
  arm64: Define TIF_PATCH_PENDING for livepatch

Weinan Liu (7):
  unwind: build kernel with sframe info
  arm64: entry: add unwind info for various kernel entries
  unwind: add sframe v2 header
  unwind: Implement generic sframe unwinder library
  unwind: arm64: Add sframe unwinder on arm64
  unwind: arm64: add reliable stacktrace support for arm64
  arm64: Enable livepatch for ARM64

 Makefile                                   |   6 +
 arch/Kconfig                               |   8 +
 arch/arm64/Kconfig                         |   3 +
 arch/arm64/Kconfig.debug                   |  10 +
 arch/arm64/include/asm/stacktrace/common.h |   6 +
 arch/arm64/include/asm/thread_info.h       |   4 +-
 arch/arm64/kernel/entry-common.c           |   4 +
 arch/arm64/kernel/entry.S                  |  10 +
 arch/arm64/kernel/setup.c                  |   2 +
 arch/arm64/kernel/stacktrace.c             | 102 ++++++++++
 include/asm-generic/vmlinux.lds.h          |  12 ++
 include/linux/sframe_lookup.h              |  43 +++++
 kernel/Makefile                            |   1 +
 kernel/sframe.h                            | 215 +++++++++++++++++++++
 kernel/sframe_lookup.c                     | 196 +++++++++++++++++++
 15 files changed, 621 insertions(+), 1 deletion(-)
 create mode 100644 include/linux/sframe_lookup.h
 create mode 100644 kernel/sframe.h
 create mode 100644 kernel/sframe_lookup.c

Comments

Indu Bhagat Jan. 28, 2025, 3:35 p.m. UTC | #1
On 1/27/25 1:33 PM, Weinan Liu wrote:
> This patchset implements a generic kernel sframe-based [1] unwinder.
> The main goal is to support reliable stacktraces on arm64.
> 
> On x86 orc unwinder provides reliable stacktraces. But arm64 misses the
> required support from objtool: it cannot generate orc unwind tables for
> arm64.
> 
> Currently, there's already a sframe unwinder proposed for userspace: [2].
> Since the sframe unwind table algorithm is similar, these two proposal
> could integrate common functionality in the future.
> 
> There are some incomplete features or challenges:
>    - The unwinder doesn't yet work with kernel modules. The `start_addr` of
>      FRE from kernel modules doesn't appear correct, preventing us from
>      unwinding functions from kernel modules.

I did file https://sourceware.org/bugzilla/show_bug.cgi?id=32589 
earlier.  It is misleading (and inconvenient) to see all 0s in the dump 
of non-relocated SFrame section.

I get the sense that while issue 32589 may be causing confusion that the 
SFrame data is not correct, the problem is elsewhere ?

I can share a fix for 32589 so atleast we can verify that the starting 
point is sane.

>    - Currently, only GCC supports sframe.
> 
> Ref:
> [1]: https://sourceware.org/binutils/docs/sframe-spec.html
> [2]: https://lore.kernel.org/lkml/cover.1730150953.git.jpoimboe@kernel.org/
> 
> Madhavan T. Venkataraman (1):
>    arm64: Define TIF_PATCH_PENDING for livepatch
> 
> Weinan Liu (7):
>    unwind: build kernel with sframe info
>    arm64: entry: add unwind info for various kernel entries
>    unwind: add sframe v2 header
>    unwind: Implement generic sframe unwinder library
>    unwind: arm64: Add sframe unwinder on arm64
>    unwind: arm64: add reliable stacktrace support for arm64
>    arm64: Enable livepatch for ARM64
> 
>   Makefile                                   |   6 +
>   arch/Kconfig                               |   8 +
>   arch/arm64/Kconfig                         |   3 +
>   arch/arm64/Kconfig.debug                   |  10 +
>   arch/arm64/include/asm/stacktrace/common.h |   6 +
>   arch/arm64/include/asm/thread_info.h       |   4 +-
>   arch/arm64/kernel/entry-common.c           |   4 +
>   arch/arm64/kernel/entry.S                  |  10 +
>   arch/arm64/kernel/setup.c                  |   2 +
>   arch/arm64/kernel/stacktrace.c             | 102 ++++++++++
>   include/asm-generic/vmlinux.lds.h          |  12 ++
>   include/linux/sframe_lookup.h              |  43 +++++
>   kernel/Makefile                            |   1 +
>   kernel/sframe.h                            | 215 +++++++++++++++++++++
>   kernel/sframe_lookup.c                     | 196 +++++++++++++++++++
>   15 files changed, 621 insertions(+), 1 deletion(-)
>   create mode 100644 include/linux/sframe_lookup.h
>   create mode 100644 kernel/sframe.h
>   create mode 100644 kernel/sframe_lookup.c
>
Weinan Liu Jan. 29, 2025, 7:23 a.m. UTC | #2
Not only does objdump show that func_start_addr all 0s, but the
func_start_addr in the kernel module's sframe table is also incorrect. I'll
prepare a repro so we can investigate this.

>
> I can share a fix for 32589 so atleast we can verify that the starting
> point is sane.
>

Great! Thanks.
This will be helpful for comparing the values from the sframe table with
the values we obtain at runtime
Song Liu Jan. 30, 2025, 5:59 p.m. UTC | #3
I missed this set before sending my RFC set. If this set works well, we
won't need the other set. I will give this one a try.

Thanks,
Song

On Mon, Jan 27, 2025 at 1:33 PM Weinan Liu <wnliu@google.com> wrote:
>
> This patchset implements a generic kernel sframe-based [1] unwinder.
> The main goal is to support reliable stacktraces on arm64.
>
> On x86 orc unwinder provides reliable stacktraces. But arm64 misses the
> required support from objtool: it cannot generate orc unwind tables for
> arm64.
>
> Currently, there's already a sframe unwinder proposed for userspace: [2].
> Since the sframe unwind table algorithm is similar, these two proposal
> could integrate common functionality in the future.
>
> There are some incomplete features or challenges:
>   - The unwinder doesn't yet work with kernel modules. The `start_addr` of
>     FRE from kernel modules doesn't appear correct, preventing us from
>     unwinding functions from kernel modules.
>   - Currently, only GCC supports sframe.
>
> Ref:
> [1]: https://sourceware.org/binutils/docs/sframe-spec.html
> [2]: https://lore.kernel.org/lkml/cover.1730150953.git.jpoimboe@kernel.org/
>
> Madhavan T. Venkataraman (1):
>   arm64: Define TIF_PATCH_PENDING for livepatch
>
> Weinan Liu (7):
>   unwind: build kernel with sframe info
>   arm64: entry: add unwind info for various kernel entries
>   unwind: add sframe v2 header
>   unwind: Implement generic sframe unwinder library
>   unwind: arm64: Add sframe unwinder on arm64
>   unwind: arm64: add reliable stacktrace support for arm64
>   arm64: Enable livepatch for ARM64
>
>  Makefile                                   |   6 +
>  arch/Kconfig                               |   8 +
>  arch/arm64/Kconfig                         |   3 +
>  arch/arm64/Kconfig.debug                   |  10 +
>  arch/arm64/include/asm/stacktrace/common.h |   6 +
>  arch/arm64/include/asm/thread_info.h       |   4 +-
>  arch/arm64/kernel/entry-common.c           |   4 +
>  arch/arm64/kernel/entry.S                  |  10 +
>  arch/arm64/kernel/setup.c                  |   2 +
>  arch/arm64/kernel/stacktrace.c             | 102 ++++++++++
>  include/asm-generic/vmlinux.lds.h          |  12 ++
>  include/linux/sframe_lookup.h              |  43 +++++
>  kernel/Makefile                            |   1 +
>  kernel/sframe.h                            | 215 +++++++++++++++++++++
>  kernel/sframe_lookup.c                     | 196 +++++++++++++++++++
>  15 files changed, 621 insertions(+), 1 deletion(-)
>  create mode 100644 include/linux/sframe_lookup.h
>  create mode 100644 kernel/sframe.h
>  create mode 100644 kernel/sframe_lookup.c
>
> --
> 2.48.1.262.g85cc9f2d1e-goog
>
>
Song Liu Jan. 30, 2025, 6:34 p.m. UTC | #4
On Thu, Jan 30, 2025 at 9:59 AM Song Liu <song@kernel.org> wrote:
>
> I missed this set before sending my RFC set. If this set works well, we
> won't need the other set. I will give this one a try.

I just realized that llvm doesn't support sframe yet. So we (Meta) still
need some sframe-less approach before llvm supports sframe.

IIRC, Google also uses llvm to compile the kernel. Weinan, would
you mind share your thoughts on how we can adopt this before
llvm supports sframe? (compile arm64 kernel with gcc?)

Thanks,
Song
Roman Gushchin Jan. 30, 2025, 7:01 p.m. UTC | #5
On Thu, Jan 30, 2025 at 10:34:09AM -0800, Song Liu wrote:
> On Thu, Jan 30, 2025 at 9:59 AM Song Liu <song@kernel.org> wrote:
> >
> > I missed this set before sending my RFC set. If this set works well, we
> > won't need the other set. I will give this one a try.
> 
> I just realized that llvm doesn't support sframe yet. So we (Meta) still
> need some sframe-less approach before llvm supports sframe.
> 
> IIRC, Google also uses llvm to compile the kernel. Weinan, would
> you mind share your thoughts on how we can adopt this before
> llvm supports sframe? (compile arm64 kernel with gcc?)

Hi Song,

the plan is to start the work on adding sframe support to llvm
in parallel to landing these changes upstream. From the initial
assessment it shouldn't be too hard.

Thanks
Song Liu Jan. 30, 2025, 7:18 p.m. UTC | #6
Hi Roman,

On Thu, Jan 30, 2025 at 11:01 AM Roman Gushchin
<roman.gushchin@linux.dev> wrote:
>
> On Thu, Jan 30, 2025 at 10:34:09AM -0800, Song Liu wrote:
> > On Thu, Jan 30, 2025 at 9:59 AM Song Liu <song@kernel.org> wrote:
> > >
> > > I missed this set before sending my RFC set. If this set works well, we
> > > won't need the other set. I will give this one a try.
> >
> > I just realized that llvm doesn't support sframe yet. So we (Meta) still
> > need some sframe-less approach before llvm supports sframe.
> >
> > IIRC, Google also uses llvm to compile the kernel. Weinan, would
> > you mind share your thoughts on how we can adopt this before
> > llvm supports sframe? (compile arm64 kernel with gcc?)
>
> Hi Song,
>
> the plan is to start the work on adding sframe support to llvm
> in parallel to landing these changes upstream. From the initial
> assessment it shouldn't be too hard.

Thanks for the information!

Song
Puranjay Mohan Feb. 4, 2025, 2:49 p.m. UTC | #7
Weinan Liu <wnliu@google.com> writes:

> This patchset implements a generic kernel sframe-based [1] unwinder.
> The main goal is to support reliable stacktraces on arm64.
>
> On x86 orc unwinder provides reliable stacktraces. But arm64 misses the
> required support from objtool: it cannot generate orc unwind tables for
> arm64.
>
> Currently, there's already a sframe unwinder proposed for userspace: [2].
> Since the sframe unwind table algorithm is similar, these two proposal
> could integrate common functionality in the future.
>
> There are some incomplete features or challenges:
>   - The unwinder doesn't yet work with kernel modules. The `start_addr` of
>     FRE from kernel modules doesn't appear correct, preventing us from
>     unwinding functions from kernel modules.
>   - Currently, only GCC supports sframe.
>
> Ref:
> [1]: https://sourceware.org/binutils/docs/sframe-spec.html
> [2]: https://lore.kernel.org/lkml/cover.1730150953.git.jpoimboe@kernel.org/
>

Hi Weinan,
Thanks for working on this.

I tested this set on my setup and faced some issues, here are the
details:

Here is my setup [on AWS c6gd.16xlarge instance]:
-------------------------------------------------

[root@ip-172-31-32-86 linux-upstream]# uname -a
Linux ip-172-31-32-86.ec2.internal 6.14.0-rc1+ #1 SMP Tue Feb  4 14:15:55 UTC 2025 aarch64 aarch64 aarch64 GNU/Linux

[root@ip-172-31-32-86 linux-upstream]# git log --oneline
e9a702365 (HEAD -> master) arm64: Enable livepatch for ARM64
5dedc956e arm64: Define TIF_PATCH_PENDING for livepatch
ba563b31a unwind: arm64: add reliable stacktrace support for arm64
d807d392d unwind: arm64: Add sframe unwinder on arm64
7872f050b unwind: Implement generic sframe unwinder library
03d2ad003 unwind: add sframe v2 header
5e95cc051 arm64: entry: add unwind info for various kernel entries
faff6cbc3 unwind: build kernel with sframe info
0de63bb7d (origin/master, origin/HEAD) Merge tag 'pull-fix' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
902e09c8a fix braino in "9p: fix ->rename_sem exclusion"
f286757b6 Merge tag 'timers-urgent-2025-02-03' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
a360f3ffd (grafted) Merge tag 'irq-urgent-2025-02-03' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
bb2784d9a (grafted) jiffies: Cast to unsigned long in secs_to_jiffies() conversion
30d61efe1 (grafted) 9p: fix ->rename_sem exclusion

[root@ip-172-31-32-86 linux-upstream]# grep SFRAME .config
CONFIG_AS_HAS_SFRAME_SUPPORT=y
CONFIG_SFRAME_UNWIND_TABLE=y
CONFIG_SFRAME_UNWINDER=y
[root@ip-172-31-32-86 linux-upstream]# grep LIVEPATCH .config
CONFIG_HAVE_LIVEPATCH=y
CONFIG_LIVEPATCH=y
CONFIG_SAMPLE_LIVEPATCH=m

[root@ip-172-31-32-86 linux-upstream]# as --version
GNU assembler version 2.41-50.al2023.0.2
Copyright (C) 2023 Free Software Foundation, Inc.
This program is free software; you may redistribute it under the terms of
the GNU General Public License version 3 or later.
This program has absolutely no warranty.
This assembler was configured for a target of `aarch64-amazon-linux'.

[root@ip-172-31-32-86 linux-upstream]# gcc --version
gcc (GCC) 11.4.1 20230605 (Red Hat 11.4.1-2)
Copyright (C) 2021 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Loading the livepatch-sameple module:
-------------------------------------

[root@ip-172-31-32-86 linux-upstream]# kpatch load /lib/modules/6.14.0-rc1+/kernel/samples/livepatch/livepatch-sample.ko
loading patch module: /lib/modules/6.14.0-rc1+/kernel/samples/livepatch/livepatch-sample.ko
waiting (up to 15 seconds) for patch transition to complete...
patch transition has stalled!
<4>kpatch: Livepatch process signaling is performed automatically on your system.
<4>kpatch: Skipping manual process signaling.
waiting (up to 60 seconds) for patch transition to complete...

Stalled processes:
340 kdevtmpfs
stack:
[<0>] devtmpfs_work_loop+0x2cc/0x2d8
[<0>] devtmpfsd+0x4c/0x58
[<0>] kthread+0xf0/0x100
[<0>] ret_from_fork+0x10/0x20
module livepatch_sample did not complete its transition, unloading...
disabling patch module: livepatch_sample
waiting (up to 15 seconds) for patch transition to complete...
transition complete (3 seconds)
unloading patch module: livepatch_sample
<4>kpatch: error: failed to load module livepatch_sample (transition stalled)

Useful messages from kernel log [pr_debug enabled]:
---------------------------------------------------

 livepatch: enabling patch 'livepatch_sample'
 livepatch: 'livepatch_sample': initializing patching transition
 livepatch: 'livepatch_sample': starting patching transition
 livepatch: klp_try_switch_task: kdevtmpfs:340 has an unreliable stack
 livepatch: klp_try_switch_task: insmod:9226 has an unreliable stack
 livepatch: klp_try_switch_task: swapper/63:0 is running
 [......SNIP.......]
 livepatch: klp_try_switch_task: kdevtmpfs:340 has an unreliable stack
 [......SNIP.......]
 livepatch: signaling remaining tasks
 livepatch: klp_try_switch_task: kdevtmpfs:340 has an unreliable stack
 livepatch: 'livepatch_sample': reversing transition from patching to unpatching
 livepatch: 'livepatch_sample': starting unpatching transition
 livepatch: klp_try_switch_task: swapper/45:0 is running
 livepatch: 'livepatch_sample': completing unpatching transition
 livepatch: 'livepatch_sample': unpatching complete

Please let me know if you are aware of this already or if this is
expected behaviour with this version. I will try to debug this from my
side as well. Also let me know if you need more details for debugging
this.

P.S. - I also saw multiple build warning like:
ld: warning: orphan section `.eh_frame' from `arch/arm64/kernel/entry.o' being placed in section `.eh_frame'
ld: warning: orphan section `.init.sframe' from `arch/arm64/kernel/pi/lib-fdt.pi.o' being placed in section `.init.sframe'


Thanks,
Puranjay
Puranjay Mohan Feb. 4, 2025, 11:52 p.m. UTC | #8
Puranjay Mohan <puranjay@kernel.org> writes:

> Weinan Liu <wnliu@google.com> writes:
>
>> This patchset implements a generic kernel sframe-based [1] unwinder.
>> The main goal is to support reliable stacktraces on arm64.
>>
>> On x86 orc unwinder provides reliable stacktraces. But arm64 misses the
>> required support from objtool: it cannot generate orc unwind tables for
>> arm64.
>>
>> Currently, there's already a sframe unwinder proposed for userspace: [2].
>> Since the sframe unwind table algorithm is similar, these two proposal
>> could integrate common functionality in the future.
>>
>> There are some incomplete features or challenges:
>>   - The unwinder doesn't yet work with kernel modules. The `start_addr` of
>>     FRE from kernel modules doesn't appear correct, preventing us from
>>     unwinding functions from kernel modules.
>>   - Currently, only GCC supports sframe.
>>
>> Ref:
>> [1]: https://sourceware.org/binutils/docs/sframe-spec.html
>> [2]: https://lore.kernel.org/lkml/cover.1730150953.git.jpoimboe@kernel.org/
>>
>
> Hi Weinan,
> Thanks for working on this.
>
> I tested this set on my setup and faced some issues, here are the
> details:
>
> Here is my setup [on AWS c6gd.16xlarge instance]:
> -------------------------------------------------
>
> [root@ip-172-31-32-86 linux-upstream]# uname -a
> Linux ip-172-31-32-86.ec2.internal 6.14.0-rc1+ #1 SMP Tue Feb  4 14:15:55 UTC 2025 aarch64 aarch64 aarch64 GNU/Linux
>
> [root@ip-172-31-32-86 linux-upstream]# git log --oneline
> e9a702365 (HEAD -> master) arm64: Enable livepatch for ARM64
> 5dedc956e arm64: Define TIF_PATCH_PENDING for livepatch
> ba563b31a unwind: arm64: add reliable stacktrace support for arm64
> d807d392d unwind: arm64: Add sframe unwinder on arm64
> 7872f050b unwind: Implement generic sframe unwinder library
> 03d2ad003 unwind: add sframe v2 header
> 5e95cc051 arm64: entry: add unwind info for various kernel entries
> faff6cbc3 unwind: build kernel with sframe info
> 0de63bb7d (origin/master, origin/HEAD) Merge tag 'pull-fix' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
> 902e09c8a fix braino in "9p: fix ->rename_sem exclusion"
> f286757b6 Merge tag 'timers-urgent-2025-02-03' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
> a360f3ffd (grafted) Merge tag 'irq-urgent-2025-02-03' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
> bb2784d9a (grafted) jiffies: Cast to unsigned long in secs_to_jiffies() conversion
> 30d61efe1 (grafted) 9p: fix ->rename_sem exclusion
>
> [root@ip-172-31-32-86 linux-upstream]# grep SFRAME .config
> CONFIG_AS_HAS_SFRAME_SUPPORT=y
> CONFIG_SFRAME_UNWIND_TABLE=y
> CONFIG_SFRAME_UNWINDER=y
> [root@ip-172-31-32-86 linux-upstream]# grep LIVEPATCH .config
> CONFIG_HAVE_LIVEPATCH=y
> CONFIG_LIVEPATCH=y
> CONFIG_SAMPLE_LIVEPATCH=m
>
> [root@ip-172-31-32-86 linux-upstream]# as --version
> GNU assembler version 2.41-50.al2023.0.2
> Copyright (C) 2023 Free Software Foundation, Inc.
> This program is free software; you may redistribute it under the terms of
> the GNU General Public License version 3 or later.
> This program has absolutely no warranty.
> This assembler was configured for a target of `aarch64-amazon-linux'.
>
> [root@ip-172-31-32-86 linux-upstream]# gcc --version
> gcc (GCC) 11.4.1 20230605 (Red Hat 11.4.1-2)
> Copyright (C) 2021 Free Software Foundation, Inc.
> This is free software; see the source for copying conditions.  There is NO
> warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
>
> Loading the livepatch-sameple module:
> -------------------------------------
>
> [root@ip-172-31-32-86 linux-upstream]# kpatch load /lib/modules/6.14.0-rc1+/kernel/samples/livepatch/livepatch-sample.ko
> loading patch module: /lib/modules/6.14.0-rc1+/kernel/samples/livepatch/livepatch-sample.ko
> waiting (up to 15 seconds) for patch transition to complete...
> patch transition has stalled!
> <4>kpatch: Livepatch process signaling is performed automatically on your system.
> <4>kpatch: Skipping manual process signaling.
> waiting (up to 60 seconds) for patch transition to complete...
>
> Stalled processes:
> 340 kdevtmpfs
> stack:
> [<0>] devtmpfs_work_loop+0x2cc/0x2d8
> [<0>] devtmpfsd+0x4c/0x58
> [<0>] kthread+0xf0/0x100
> [<0>] ret_from_fork+0x10/0x20
> module livepatch_sample did not complete its transition, unloading...
> disabling patch module: livepatch_sample
> waiting (up to 15 seconds) for patch transition to complete...
> transition complete (3 seconds)
> unloading patch module: livepatch_sample
> <4>kpatch: error: failed to load module livepatch_sample (transition stalled)

After some debugging this is what I found:

devtmpfsd() calls devtmpfs_work_loop() which is marked '__noreturn' and has an
infinite loop. The compiler puts the `bl` to devtmpfs_work_loop() as the the
last instruction in devtmpfsd() and therefore on entry to devtmpfs_work_loop(),
LR points to an instruction beyond devtmpfsd() and this consfuses the unwinder.

ffff800080d9a070 <devtmpfsd>:
ffff800080d9a070:       d503201f        nop
ffff800080d9a074:       d503201f        nop
ffff800080d9a078:       d503233f        paciasp
ffff800080d9a07c:       a9be7bfd        stp     x29, x30, [sp, #-32]!
ffff800080d9a080:       910003fd        mov     x29, sp
ffff800080d9a084:       f9000bf3        str     x19, [sp, #16]
ffff800080d9a088:       943378e8        bl      ffff800081a78428 <devtmpfs_setup>
ffff800080d9a08c:       90006ca1        adrp    x1, ffff800081b2e000 <unique_processor_ids+0x3758>
ffff800080d9a090:       2a0003f3        mov     w19, w0
ffff800080d9a094:       912de021        add     x1, x1, #0xb78
ffff800080d9a098:       91002020        add     x0, x1, #0x8
ffff800080d9a09c:       97cd2a43        bl      ffff8000800e49a8 <complete>
ffff800080d9a0a0:       340000d3        cbz     w19, ffff800080d9a0b8 <devtmpfsd+0x48>
ffff800080d9a0a4:       2a1303e0        mov     w0, w19
ffff800080d9a0a8:       f9400bf3        ldr     x19, [sp, #16]
ffff800080d9a0ac:       a8c27bfd        ldp     x29, x30, [sp], #32
ffff800080d9a0b0:       d50323bf        autiasp
ffff800080d9a0b4:       d65f03c0        ret
ffff800080d9a0b8:       97f06526        bl      ffff8000809b3550 <devtmpfs_work_loop>
ffff800080d9a0bc:       00000000        udf     #0
ffff800080d9a0c0:       d503201f        nop
ffff800080d9a0c4:       d503201f        nop

find_fde() got pc=0xffff800080d9a0bc which is not in [sfde_func_start_address, sfde_func_size)

output for readelf --sframe for devtmpfsd()

func idx [51825]: pc = 0xffff800080d9a070, size = 76 bytes
    STARTPC           CFA       FP        RA
    ffff800080d9a070  sp+0      u         u
    ffff800080d9a07c  sp+0      u         u[s]
    ffff800080d9a080  sp+32     c-32      c-24[s]
    ffff800080d9a0b0  sp+0      u         u[s]
    ffff800080d9a0b4  sp+0      u         u
    ffff800080d9a0b8  sp+32     c-32      c-24[s]

The unwinder and all the related infra is assuming that the return address
will be part of a valid function which is not the case here.

I am not sure which component needs to be fixed here, but the following
patch(which is a hack) fixes the issue by considering the return address as
part of the function descriptor entry.

-- 8< --

diff --git a/kernel/sframe_lookup.c b/kernel/sframe_lookup.c
index 846f1da95..28bec5064 100644
--- a/kernel/sframe_lookup.c
+++ b/kernel/sframe_lookup.c
@@ -82,7 +82,7 @@ static struct sframe_fde *find_fde(const struct sframe_table *tbl, unsigned long
        if (f >= tbl->sfhdr_p->num_fdes || f < 0)
                return NULL;
        fdep = tbl->fde_p + f;
-       if (ip < fdep->start_addr || ip >= fdep->start_addr + fdep->size)
+       if (ip < fdep->start_addr || ip > fdep->start_addr + fdep->size)
                return NULL;

        return fdep;
@@ -106,7 +106,7 @@ static int find_fre(const struct sframe_table *tbl, unsigned long pc,
        else
                ip_off = (int32_t)(pc - (unsigned long)tbl->sfhdr_p) - fdep->start_addr;

-       if (ip_off < 0 || ip_off >= fdep->size)
+       if (ip_off < 0 || ip_off > fdep->size)
                return -EINVAL;

        /*

-- >8 --

Thanks,
Puranjay
Weinan Liu Feb. 6, 2025, 3:02 p.m. UTC | #9
> After some debugging this is what I found:
> 
> devtmpfsd() calls devtmpfs_work_loop() which is marked '__noreturn' and has an
> infinite loop. The compiler puts the `bl` to devtmpfs_work_loop() as the the
> last instruction in devtmpfsd() and therefore on entry to devtmpfs_work_loop(),
> LR points to an instruction beyond devtmpfsd() and this consfuses the unwinder.
> 
> ffff800080d9a070 <devtmpfsd>:
> ffff800080d9a070:       d503201f        nop
> ffff800080d9a074:       d503201f        nop
> ffff800080d9a078:       d503233f        paciasp
> ffff800080d9a07c:       a9be7bfd        stp     x29, x30, [sp, #-32]!
> ffff800080d9a080:       910003fd        mov     x29, sp
> ffff800080d9a084:       f9000bf3        str     x19, [sp, #16]
> ffff800080d9a088:       943378e8        bl      ffff800081a78428 <devtmpfs_setup>
> ffff800080d9a08c:       90006ca1        adrp    x1, ffff800081b2e000 <unique_processor_ids+0x3758>
> ffff800080d9a090:       2a0003f3        mov     w19, w0
> ffff800080d9a094:       912de021        add     x1, x1, #0xb78
> ffff800080d9a098:       91002020        add     x0, x1, #0x8
> ffff800080d9a09c:       97cd2a43        bl      ffff8000800e49a8 <complete>
> ffff800080d9a0a0:       340000d3        cbz     w19, ffff800080d9a0b8 <devtmpfsd+0x48>
> ffff800080d9a0a4:       2a1303e0        mov     w0, w19
> ffff800080d9a0a8:       f9400bf3        ldr     x19, [sp, #16]
> ffff800080d9a0ac:       a8c27bfd        ldp     x29, x30, [sp], #32
> ffff800080d9a0b0:       d50323bf        autiasp
> ffff800080d9a0b4:       d65f03c0        ret
> ffff800080d9a0b8:       97f06526        bl      ffff8000809b3550 <devtmpfs_work_loop>
> ffff800080d9a0bc:       00000000        udf     #0
> ffff800080d9a0c0:       d503201f        nop
> ffff800080d9a0c4:       d503201f        nop
> 
> find_fde() got pc=0xffff800080d9a0bc which is not in [sfde_func_start_address, sfde_func_size)
> 
> output for readelf --sframe for devtmpfsd()
> 
> func idx [51825]: pc = 0xffff800080d9a070, size = 76 bytes
>     STARTPC           CFA       FP        RA
>     ffff800080d9a070  sp+0      u         u
>     ffff800080d9a07c  sp+0      u         u[s]
>     ffff800080d9a080  sp+32     c-32      c-24[s]
>     ffff800080d9a0b0  sp+0      u         u[s]
>     ffff800080d9a0b4  sp+0      u         u
>     ffff800080d9a0b8  sp+32     c-32      c-24[s]
> 
> The unwinder and all the related infra is assuming that the return address
> will be part of a valid function which is not the case here.
> 
> I am not sure which component needs to be fixed here, but the following
> patch(which is a hack) fixes the issue by considering the return address as
> part of the function descriptor entry.
> 
> -- 8< --
> 
> diff --git a/kernel/sframe_lookup.c b/kernel/sframe_lookup.c
> index 846f1da95..28bec5064 100644
> --- a/kernel/sframe_lookup.c
> +++ b/kernel/sframe_lookup.c
> @@ -82,7 +82,7 @@ static struct sframe_fde *find_fde(const struct sframe_table *tbl, unsigned long
>         if (f >= tbl->sfhdr_p->num_fdes || f < 0)
>                 return NULL;
>         fdep = tbl->fde_p + f;
> -       if (ip < fdep->start_addr || ip >= fdep->start_addr + fdep->size)
> +       if (ip < fdep->start_addr || ip > fdep->start_addr + fdep->size)
>                 return NULL;
> 
>         return fdep;
> @@ -106,7 +106,7 @@ static int find_fre(const struct sframe_table *tbl, unsigned long pc,
>         else
>                 ip_off = (int32_t)(pc - (unsigned long)tbl->sfhdr_p) - fdep->start_addr;
> 
> -       if (ip_off < 0 || ip_off >= fdep->size)
> +       if (ip_off < 0 || ip_off > fdep->size)
>                 return -EINVAL;
> 
>         /*
> 
> -- >8 --
> 
> Thanks,
> Puranjay

Thank you for reporting this issue.
I just found out that Josh also intentionally uses '>' instead of '>=' for the same reason
https://lore.kernel.org/lkml/20250122225257.h64ftfnorofe7cb4@jpoimboe/T/#m6d70a20ed9f5b3bbe5b24b24b8c5dcc603a79101

QQ, do we need to care the stacktrace after '__noreturn' function?
Puranjay Mohan Feb. 7, 2025, 12:16 p.m. UTC | #10
Weinan Liu <wnliu@google.com> writes:

>> After some debugging this is what I found:
>> 
>> devtmpfsd() calls devtmpfs_work_loop() which is marked '__noreturn' and has an
>> infinite loop. The compiler puts the `bl` to devtmpfs_work_loop() as the the
>> last instruction in devtmpfsd() and therefore on entry to devtmpfs_work_loop(),
>> LR points to an instruction beyond devtmpfsd() and this consfuses the unwinder.
>> 
>> ffff800080d9a070 <devtmpfsd>:
>> ffff800080d9a070:       d503201f        nop
>> ffff800080d9a074:       d503201f        nop
>> ffff800080d9a078:       d503233f        paciasp
>> ffff800080d9a07c:       a9be7bfd        stp     x29, x30, [sp, #-32]!
>> ffff800080d9a080:       910003fd        mov     x29, sp
>> ffff800080d9a084:       f9000bf3        str     x19, [sp, #16]
>> ffff800080d9a088:       943378e8        bl      ffff800081a78428 <devtmpfs_setup>
>> ffff800080d9a08c:       90006ca1        adrp    x1, ffff800081b2e000 <unique_processor_ids+0x3758>
>> ffff800080d9a090:       2a0003f3        mov     w19, w0
>> ffff800080d9a094:       912de021        add     x1, x1, #0xb78
>> ffff800080d9a098:       91002020        add     x0, x1, #0x8
>> ffff800080d9a09c:       97cd2a43        bl      ffff8000800e49a8 <complete>
>> ffff800080d9a0a0:       340000d3        cbz     w19, ffff800080d9a0b8 <devtmpfsd+0x48>
>> ffff800080d9a0a4:       2a1303e0        mov     w0, w19
>> ffff800080d9a0a8:       f9400bf3        ldr     x19, [sp, #16]
>> ffff800080d9a0ac:       a8c27bfd        ldp     x29, x30, [sp], #32
>> ffff800080d9a0b0:       d50323bf        autiasp
>> ffff800080d9a0b4:       d65f03c0        ret
>> ffff800080d9a0b8:       97f06526        bl      ffff8000809b3550 <devtmpfs_work_loop>
>> ffff800080d9a0bc:       00000000        udf     #0
>> ffff800080d9a0c0:       d503201f        nop
>> ffff800080d9a0c4:       d503201f        nop
>> 
>> find_fde() got pc=0xffff800080d9a0bc which is not in [sfde_func_start_address, sfde_func_size)
>> 
>> output for readelf --sframe for devtmpfsd()
>> 
>> func idx [51825]: pc = 0xffff800080d9a070, size = 76 bytes
>>     STARTPC           CFA       FP        RA
>>     ffff800080d9a070  sp+0      u         u
>>     ffff800080d9a07c  sp+0      u         u[s]
>>     ffff800080d9a080  sp+32     c-32      c-24[s]
>>     ffff800080d9a0b0  sp+0      u         u[s]
>>     ffff800080d9a0b4  sp+0      u         u
>>     ffff800080d9a0b8  sp+32     c-32      c-24[s]
>> 
>> The unwinder and all the related infra is assuming that the return address
>> will be part of a valid function which is not the case here.
>> 
>> I am not sure which component needs to be fixed here, but the following
>> patch(which is a hack) fixes the issue by considering the return address as
>> part of the function descriptor entry.
>> 
>> -- 8< --
>> 
>> diff --git a/kernel/sframe_lookup.c b/kernel/sframe_lookup.c
>> index 846f1da95..28bec5064 100644
>> --- a/kernel/sframe_lookup.c
>> +++ b/kernel/sframe_lookup.c
>> @@ -82,7 +82,7 @@ static struct sframe_fde *find_fde(const struct sframe_table *tbl, unsigned long
>>         if (f >= tbl->sfhdr_p->num_fdes || f < 0)
>>                 return NULL;
>>         fdep = tbl->fde_p + f;
>> -       if (ip < fdep->start_addr || ip >= fdep->start_addr + fdep->size)
>> +       if (ip < fdep->start_addr || ip > fdep->start_addr + fdep->size)
>>                 return NULL;
>> 
>>         return fdep;
>> @@ -106,7 +106,7 @@ static int find_fre(const struct sframe_table *tbl, unsigned long pc,
>>         else
>>                 ip_off = (int32_t)(pc - (unsigned long)tbl->sfhdr_p) - fdep->start_addr;
>> 
>> -       if (ip_off < 0 || ip_off >= fdep->size)
>> +       if (ip_off < 0 || ip_off > fdep->size)
>>                 return -EINVAL;
>> 
>>         /*
>> 
>> -- >8 --
>> 
>> Thanks,
>> Puranjay
>
> Thank you for reporting this issue.
> I just found out that Josh also intentionally uses '>' instead of '>=' for the same reason
> https://lore.kernel.org/lkml/20250122225257.h64ftfnorofe7cb4@jpoimboe/T/#m6d70a20ed9f5b3bbe5b24b24b8c5dcc603a79101
>
> QQ, do we need to care the stacktrace after '__noreturn' function?

Yes, I think we should, but others people could add more to this.

I have been testing this series with Kpatch and created a PR that works
with this unwinder: https://github.com/dynup/kpatch/pull/1439

For the modules, I think we need per module sframe tables that are
initialised when the module is loaded. And the unwinder should use the
module specific table if the IP is in a module's code.

Have you already started working on it? if not I would like to help and
work on that.

Thanks,
Puranjay
Josh Poimboeuf Feb. 7, 2025, 5:52 p.m. UTC | #11
On Fri, Feb 07, 2025 at 12:16:29PM +0000, Puranjay Mohan wrote:
> Weinan Liu <wnliu@google.com> writes:
> > Thank you for reporting this issue.
> > I just found out that Josh also intentionally uses '>' instead of '>=' for the same reason
> > https://lore.kernel.org/lkml/20250122225257.h64ftfnorofe7cb4@jpoimboe/T/#m6d70a20ed9f5b3bbe5b24b24b8c5dcc603a79101
> >
> > QQ, do we need to care the stacktrace after '__noreturn' function?
> 
> Yes, I think we should, but others people could add more to this.

FYI, here's how ORC handles this:

	/*
	 * Find the orc_entry associated with the text address.
	 *
	 * For a call frame (as opposed to a signal frame), state->ip points to
	 * the instruction after the call.  That instruction's stack layout
	 * could be different from the call instruction's layout, for example
	 * if the call was to a noreturn function.  So get the ORC data for the
	 * call instruction itself.
	 */
	orc = orc_find(state->signal ? state->ip : state->ip - 1);

and state->signal is only set for exceptions/interrupts (including
preemption and page faults) and newly forked tasks which haven't run
yet.
Weinan Liu Feb. 10, 2025, 8:30 a.m. UTC | #12
On Fri, Feb 7, 2025 at 4:16 AM Puranjay Mohan <puranjay@kernel.org> wrote:
>
> Yes, I think we should, but others people could add more to this.
> 
> I have been testing this series with Kpatch and created a PR that works
> with this unwinder: https://github.com/dynup/kpatch/pull/1439
> 
> For the modules, I think we need per module sframe tables that are
> initialised when the module is loaded. And the unwinder should use the
> module specific table if the IP is in a module's code.
> 
> Have you already started working on it? if not I would like to help and
> work on that.
> 
> Thanks,
> Puranjay

Thanks for updating the arm64 kpatch PR so quickly.
So we can use kpatch to test this proposal.

I already have a WIP patch to add sframe support to the kernel module.
However, it is not yet working. I had trouble unwinding frames for the 
kernel module using the current algorithm.

Indu has likely identified the issue and will be addressing it from the
toolchain side.

https://sourceware.org/bugzilla/show_bug.cgi?id=32666
Song Liu Feb. 12, 2025, 11:32 p.m. UTC | #13
I run some tests with this set and my RFC set [1]. Most of
the test is done with kpatch-build. I tested both Puranjay's
version [3] and my version [4].

For gcc 14.2.1, I have seen the following issue with this
test [2]. This happens with both upstream and 6.13.2.
The livepatch loaded fine, but the system spilled out the
following warning quickly.

On the other hand, the same test works with LLVM and
my RFC set (LLVM doesn't support SFRAME, and thus
doesn't work with this set yet).

Thanks,
Song


[   81.250437] ------------[ cut here ]------------
[   81.250818] refcount_t: saturated; leaking memory.
[   81.251201] WARNING: CPU: 0 PID: 95 at lib/refcount.c:22
refcount_warn_saturate+0x6c/0x140
[   81.251841] Modules linked in: livepatch_special_static(OEK)
[   81.252277] CPU: 0 UID: 0 PID: 95 Comm: bash Tainted: G
OE K    6.13.2-00321-g52d2813b4b07 #49
[   81.253003] Tainted: [O]=OOT_MODULE, [E]=UNSIGNED_MODULE, [K]=LIVEPATCH
[   81.253503] Hardware name: linux,dummy-virt (DT)
[   81.253856] pstate: 634000c5 (nZCv daIF +PAN -UAO +TCO +DIT -SSBS BTYPE=--)
[   81.254383] pc : refcount_warn_saturate+0x6c/0x140
[   81.254748] lr : refcount_warn_saturate+0x6c/0x140
[   81.255114] sp : ffff800085a6fc00
[   81.255371] x29: ffff800085a6fc00 x28: 0000000001200000 x27: ffff0000c2966180
[   81.255918] x26: 0000000000000000 x25: ffff8000829c0000 x24: ffff0000c2e9b608
[   81.256462] x23: ffff800083351000 x22: ffff0000c2e9af80 x21: ffff0000c062e140
[   81.257006] x20: ffff0000c1c10c00 x19: ffff800085a6fd80 x18: ffffffffffffffff
[   81.257544] x17: 0000000000000001 x16: ffffffffffffffff x15: 0000000000000006
[   81.258083] x14: 0000000000000000 x13: 2e79726f6d656d20 x12: 676e696b61656c20
[   81.258625] x11: ffff8000829f7d70 x10: 0000000000000147 x9 : ffff8000801546b4
[   81.259165] x8 : 00000000fffeffff x7 : 00000000ffff0000 x6 : ffff800082f77d70
[   81.259709] x5 : 80000000ffff0000 x4 : 0000000000000000 x3 : 0000000000000001
[   81.260257] x2 : ffff8000829f7a88 x1 : ffff8000829f7a88 x0 : 0000000000000026
[   81.260824] Call trace:
[   81.261015]  refcount_warn_saturate+0x6c/0x140 (P)
[   81.261387]  __refcount_add.constprop.0+0x60/0x70
[   81.261748]  copy_process+0xfdc/0xfd58 [livepatch_special_static]
[   81.262217]  kernel_clone+0x80/0x3e0
[   81.262499]  __do_sys_clone+0x5c/0x88
[   81.262786]  __arm64_sys_clone+0x24/0x38
[   81.263085]  invoke_syscall+0x4c/0x108
[   81.263378]  el0_svc_common.constprop.0+0x44/0xe8
[   81.263734]  do_el0_svc+0x20/0x30
[   81.263993]  el0_svc+0x34/0xf8
[   81.264231]  el0t_64_sync_handler+0x104/0x130
[   81.264561]  el0t_64_sync+0x184/0x188
[   81.264846] ---[ end trace 0000000000000000 ]---
[   82.335559] ------------[ cut here ]------------
[   82.335931] refcount_t: underflow; use-after-free.
[   82.336307] WARNING: CPU: 1 PID: 0 at lib/refcount.c:28
refcount_warn_saturate+0xec/0x140
[   82.336949] Modules linked in: livepatch_special_static(OEK)
[   82.337389] CPU: 1 UID: 0 PID: 0 Comm: swapper/1 Tainted: G
W  OE K    6.13.2-00321-g52d2813b4b07 #49
[   82.338148] Tainted: [W]=WARN, [O]=OOT_MODULE, [E]=UNSIGNED_MODULE,
[K]=LIVEPATCH
[   82.338721] Hardware name: linux,dummy-virt (DT)
[   82.339083] pstate: 63400005 (nZCv daif +PAN -UAO +TCO +DIT -SSBS BTYPE=--)
[   82.339617] pc : refcount_warn_saturate+0xec/0x140
[   82.340007] lr : refcount_warn_saturate+0xec/0x140
[   82.340378] sp : ffff80008370fe40
[   82.340637] x29: ffff80008370fe40 x28: 0000000000000000 x27: 0000000000000000
[   82.341188] x26: 000000000000000a x25: ffff0000fdaf7ab8 x24: 0000000000000014
[   82.341737] x23: ffff8000829c8d30 x22: ffff80008370ff28 x21: ffff0000fe020000
[   82.342286] x20: ffff0000c062e140 x19: ffff0000c2e9af80 x18: ffffffffffffffff
[   82.342839] x17: ffff80007b7a0000 x16: ffff800083700000 x15: 0000000000000006
[   82.343389] x14: 0000000000000000 x13: 2e656572662d7265 x12: 7466612d65737520
[   82.343944] x11: ffff8000829f7d70 x10: 000000000000016a x9 : ffff8000801546b4
[   82.344499] x8 : 00000000fffeffff x7 : 00000000ffff0000 x6 : ffff800082f77d70
[   82.345051] x5 : 80000000ffff0000 x4 : 0000000000000000 x3 : 0000000000000001
[   82.345604] x2 : ffff8000829f7a88 x1 : ffff8000829f7a88 x0 : 0000000000000026
[   82.346163] Call trace:
[   82.346359]  refcount_warn_saturate+0xec/0x140 (P)
[   82.346736]  __put_task_struct+0x130/0x170
[   82.347063]  delayed_put_task_struct+0xbc/0xe8
[   82.347411]  rcu_core+0x20c/0x5f8
[   82.347680]  rcu_core_si+0x14/0x28
[   82.347952]  handle_softirqs+0x124/0x308
[   82.348260]  __do_softirq+0x18/0x20
[   82.348536]  ____do_softirq+0x14/0x28
[   82.348828]  call_on_irq_stack+0x24/0x30
[   82.349137]  do_softirq_own_stack+0x20/0x38
[   82.349465]  __irq_exit_rcu+0xcc/0x108
[   82.349764]  irq_exit_rcu+0x14/0x28
[   82.350038]  el1_interrupt+0x34/0x50
[   82.350321]  el1h_64_irq_handler+0x14/0x20
[   82.350642]  el1h_64_irq+0x6c/0x70
[   82.350911]  default_idle_call+0x30/0xd0 (P)
[   82.351248]  do_idle+0x1d0/0x200
[   82.351506]  cpu_startup_entry+0x38/0x48
[   82.351818]  secondary_start_kernel+0x124/0x150
[   82.352176]  __secondary_switched+0xac/0xb0
[   82.352505] ---[ end trace 0000000000000000 ]---



[1] SFRAME-less livepatch RFC
https://lore.kernel.org/live-patching/20250129232936.1795412-1-song@kernel.org/
[2] special-static test from kpatch
https://github.com/dynup/kpatch/blob/master/test/integration/linux-6.2.0/special-static.patch
[3] Puranjay's kpatch with arm64 support
https://github.com/puranjaymohan/kpatch/tree/arm64
[4] My version of kpatch with arm64 and LTO support
https://github.com/liu-song-6/kpatch/tree/fb-6.13-v2

On Mon, Jan 27, 2025 at 1:33 PM Weinan Liu <wnliu@google.com> wrote:
>
> This patchset implements a generic kernel sframe-based [1] unwinder.
> The main goal is to support reliable stacktraces on arm64.
>
> On x86 orc unwinder provides reliable stacktraces. But arm64 misses the
> required support from objtool: it cannot generate orc unwind tables for
> arm64.
>
> Currently, there's already a sframe unwinder proposed for userspace: [2].
> Since the sframe unwind table algorithm is similar, these two proposal
> could integrate common functionality in the future.
>
> There are some incomplete features or challenges:
>   - The unwinder doesn't yet work with kernel modules. The `start_addr` of
>     FRE from kernel modules doesn't appear correct, preventing us from
>     unwinding functions from kernel modules.
>   - Currently, only GCC supports sframe.
>
> Ref:
> [1]: https://sourceware.org/binutils/docs/sframe-spec.html
> [2]: https://lore.kernel.org/lkml/cover.1730150953.git.jpoimboe@kernel.org/
>
> Madhavan T. Venkataraman (1):
>   arm64: Define TIF_PATCH_PENDING for livepatch
>
> Weinan Liu (7):
>   unwind: build kernel with sframe info
>   arm64: entry: add unwind info for various kernel entries
>   unwind: add sframe v2 header
>   unwind: Implement generic sframe unwinder library
>   unwind: arm64: Add sframe unwinder on arm64
>   unwind: arm64: add reliable stacktrace support for arm64
>   arm64: Enable livepatch for ARM64
>
>  Makefile                                   |   6 +
>  arch/Kconfig                               |   8 +
>  arch/arm64/Kconfig                         |   3 +
>  arch/arm64/Kconfig.debug                   |  10 +
>  arch/arm64/include/asm/stacktrace/common.h |   6 +
>  arch/arm64/include/asm/thread_info.h       |   4 +-
>  arch/arm64/kernel/entry-common.c           |   4 +
>  arch/arm64/kernel/entry.S                  |  10 +
>  arch/arm64/kernel/setup.c                  |   2 +
>  arch/arm64/kernel/stacktrace.c             | 102 ++++++++++
>  include/asm-generic/vmlinux.lds.h          |  12 ++
>  include/linux/sframe_lookup.h              |  43 +++++
>  kernel/Makefile                            |   1 +
>  kernel/sframe.h                            | 215 +++++++++++++++++++++
>  kernel/sframe_lookup.c                     | 196 +++++++++++++++++++
>  15 files changed, 621 insertions(+), 1 deletion(-)
>  create mode 100644 include/linux/sframe_lookup.h
>  create mode 100644 kernel/sframe.h
>  create mode 100644 kernel/sframe_lookup.c
>
> --
> 2.48.1.262.g85cc9f2d1e-goog
>
>
Josh Poimboeuf Feb. 12, 2025, 11:49 p.m. UTC | #14
On Wed, Feb 12, 2025 at 03:32:40PM -0800, Song Liu wrote:
> [   81.250437] ------------[ cut here ]------------
> [   81.250818] refcount_t: saturated; leaking memory.
> [   81.251201] WARNING: CPU: 0 PID: 95 at lib/refcount.c:22
> refcount_warn_saturate+0x6c/0x140
> [   81.251841] Modules linked in: livepatch_special_static(OEK)
> [   81.252277] CPU: 0 UID: 0 PID: 95 Comm: bash Tainted: G
> OE K    6.13.2-00321-g52d2813b4b07 #49
> [   81.253003] Tainted: [O]=OOT_MODULE, [E]=UNSIGNED_MODULE, [K]=LIVEPATCH
> [   81.253503] Hardware name: linux,dummy-virt (DT)
> [   81.253856] pstate: 634000c5 (nZCv daIF +PAN -UAO +TCO +DIT -SSBS BTYPE=--)
> [   81.254383] pc : refcount_warn_saturate+0x6c/0x140
> [   81.254748] lr : refcount_warn_saturate+0x6c/0x140
> [   81.255114] sp : ffff800085a6fc00
> [   81.255371] x29: ffff800085a6fc00 x28: 0000000001200000 x27: ffff0000c2966180
> [   81.255918] x26: 0000000000000000 x25: ffff8000829c0000 x24: ffff0000c2e9b608
> [   81.256462] x23: ffff800083351000 x22: ffff0000c2e9af80 x21: ffff0000c062e140
> [   81.257006] x20: ffff0000c1c10c00 x19: ffff800085a6fd80 x18: ffffffffffffffff
> [   81.257544] x17: 0000000000000001 x16: ffffffffffffffff x15: 0000000000000006
> [   81.258083] x14: 0000000000000000 x13: 2e79726f6d656d20 x12: 676e696b61656c20
> [   81.258625] x11: ffff8000829f7d70 x10: 0000000000000147 x9 : ffff8000801546b4
> [   81.259165] x8 : 00000000fffeffff x7 : 00000000ffff0000 x6 : ffff800082f77d70
> [   81.259709] x5 : 80000000ffff0000 x4 : 0000000000000000 x3 : 0000000000000001
> [   81.260257] x2 : ffff8000829f7a88 x1 : ffff8000829f7a88 x0 : 0000000000000026
> [   81.260824] Call trace:
> [   81.261015]  refcount_warn_saturate+0x6c/0x140 (P)
> [   81.261387]  __refcount_add.constprop.0+0x60/0x70
> [   81.261748]  copy_process+0xfdc/0xfd58 [livepatch_special_static]

Does that copy_process+0xfdc/0xfd58 resolve to this line in
copy_process()?

			refcount_inc(&current->signal->sigcnt);

Maybe the klp rela reference to 'current' is bogus, or resolving to the
wrong address somehow?
Indu Bhagat Feb. 13, 2025, 12:09 a.m. UTC | #15
On 2/12/25 3:32 PM, Song Liu wrote:
> I run some tests with this set and my RFC set [1]. Most of
> the test is done with kpatch-build. I tested both Puranjay's
> version [3] and my version [4].
> 
> For gcc 14.2.1, I have seen the following issue with this
> test [2]. This happens with both upstream and 6.13.2.
> The livepatch loaded fine, but the system spilled out the
> following warning quickly.
> 

In presence of the issue 
https://sourceware.org/bugzilla/show_bug.cgi?id=32666, I'd expect bad 
data in SFrame section.  Which may be causing this symptom?

To be clear, the issue affects loaded kernel modules.  I cannot tell for 
certain - is there module loading involved in your test ?

> On the other hand, the same test works with LLVM and
> my RFC set (LLVM doesn't support SFRAME, and thus
> doesn't work with this set yet).
> 
> Thanks,
> Song
> 
> 
> [   81.250437] ------------[ cut here ]------------
> [   81.250818] refcount_t: saturated; leaking memory.
> [   81.251201] WARNING: CPU: 0 PID: 95 at lib/refcount.c:22
> refcount_warn_saturate+0x6c/0x140
> [   81.251841] Modules linked in: livepatch_special_static(OEK)
> [   81.252277] CPU: 0 UID: 0 PID: 95 Comm: bash Tainted: G
> OE K    6.13.2-00321-g52d2813b4b07 #49
> [   81.253003] Tainted: [O]=OOT_MODULE, [E]=UNSIGNED_MODULE, [K]=LIVEPATCH
> [   81.253503] Hardware name: linux,dummy-virt (DT)
> [   81.253856] pstate: 634000c5 (nZCv daIF +PAN -UAO +TCO +DIT -SSBS BTYPE=--)
> [   81.254383] pc : refcount_warn_saturate+0x6c/0x140
> [   81.254748] lr : refcount_warn_saturate+0x6c/0x140
> [   81.255114] sp : ffff800085a6fc00
> [   81.255371] x29: ffff800085a6fc00 x28: 0000000001200000 x27: ffff0000c2966180
> [   81.255918] x26: 0000000000000000 x25: ffff8000829c0000 x24: ffff0000c2e9b608
> [   81.256462] x23: ffff800083351000 x22: ffff0000c2e9af80 x21: ffff0000c062e140
> [   81.257006] x20: ffff0000c1c10c00 x19: ffff800085a6fd80 x18: ffffffffffffffff
> [   81.257544] x17: 0000000000000001 x16: ffffffffffffffff x15: 0000000000000006
> [   81.258083] x14: 0000000000000000 x13: 2e79726f6d656d20 x12: 676e696b61656c20
> [   81.258625] x11: ffff8000829f7d70 x10: 0000000000000147 x9 : ffff8000801546b4
> [   81.259165] x8 : 00000000fffeffff x7 : 00000000ffff0000 x6 : ffff800082f77d70
> [   81.259709] x5 : 80000000ffff0000 x4 : 0000000000000000 x3 : 0000000000000001
> [   81.260257] x2 : ffff8000829f7a88 x1 : ffff8000829f7a88 x0 : 0000000000000026
> [   81.260824] Call trace:
> [   81.261015]  refcount_warn_saturate+0x6c/0x140 (P)
> [   81.261387]  __refcount_add.constprop.0+0x60/0x70
> [   81.261748]  copy_process+0xfdc/0xfd58 [livepatch_special_static]
> [   81.262217]  kernel_clone+0x80/0x3e0
> [   81.262499]  __do_sys_clone+0x5c/0x88
> [   81.262786]  __arm64_sys_clone+0x24/0x38
> [   81.263085]  invoke_syscall+0x4c/0x108
> [   81.263378]  el0_svc_common.constprop.0+0x44/0xe8
> [   81.263734]  do_el0_svc+0x20/0x30
> [   81.263993]  el0_svc+0x34/0xf8
> [   81.264231]  el0t_64_sync_handler+0x104/0x130
> [   81.264561]  el0t_64_sync+0x184/0x188
> [   81.264846] ---[ end trace 0000000000000000 ]---
> [   82.335559] ------------[ cut here ]------------
> [   82.335931] refcount_t: underflow; use-after-free.
> [   82.336307] WARNING: CPU: 1 PID: 0 at lib/refcount.c:28
> refcount_warn_saturate+0xec/0x140
> [   82.336949] Modules linked in: livepatch_special_static(OEK)
> [   82.337389] CPU: 1 UID: 0 PID: 0 Comm: swapper/1 Tainted: G
> W  OE K    6.13.2-00321-g52d2813b4b07 #49
> [   82.338148] Tainted: [W]=WARN, [O]=OOT_MODULE, [E]=UNSIGNED_MODULE,
> [K]=LIVEPATCH
> [   82.338721] Hardware name: linux,dummy-virt (DT)
> [   82.339083] pstate: 63400005 (nZCv daif +PAN -UAO +TCO +DIT -SSBS BTYPE=--)
> [   82.339617] pc : refcount_warn_saturate+0xec/0x140
> [   82.340007] lr : refcount_warn_saturate+0xec/0x140
> [   82.340378] sp : ffff80008370fe40
> [   82.340637] x29: ffff80008370fe40 x28: 0000000000000000 x27: 0000000000000000
> [   82.341188] x26: 000000000000000a x25: ffff0000fdaf7ab8 x24: 0000000000000014
> [   82.341737] x23: ffff8000829c8d30 x22: ffff80008370ff28 x21: ffff0000fe020000
> [   82.342286] x20: ffff0000c062e140 x19: ffff0000c2e9af80 x18: ffffffffffffffff
> [   82.342839] x17: ffff80007b7a0000 x16: ffff800083700000 x15: 0000000000000006
> [   82.343389] x14: 0000000000000000 x13: 2e656572662d7265 x12: 7466612d65737520
> [   82.343944] x11: ffff8000829f7d70 x10: 000000000000016a x9 : ffff8000801546b4
> [   82.344499] x8 : 00000000fffeffff x7 : 00000000ffff0000 x6 : ffff800082f77d70
> [   82.345051] x5 : 80000000ffff0000 x4 : 0000000000000000 x3 : 0000000000000001
> [   82.345604] x2 : ffff8000829f7a88 x1 : ffff8000829f7a88 x0 : 0000000000000026
> [   82.346163] Call trace:
> [   82.346359]  refcount_warn_saturate+0xec/0x140 (P)
> [   82.346736]  __put_task_struct+0x130/0x170
> [   82.347063]  delayed_put_task_struct+0xbc/0xe8
> [   82.347411]  rcu_core+0x20c/0x5f8
> [   82.347680]  rcu_core_si+0x14/0x28
> [   82.347952]  handle_softirqs+0x124/0x308
> [   82.348260]  __do_softirq+0x18/0x20
> [   82.348536]  ____do_softirq+0x14/0x28
> [   82.348828]  call_on_irq_stack+0x24/0x30
> [   82.349137]  do_softirq_own_stack+0x20/0x38
> [   82.349465]  __irq_exit_rcu+0xcc/0x108
> [   82.349764]  irq_exit_rcu+0x14/0x28
> [   82.350038]  el1_interrupt+0x34/0x50
> [   82.350321]  el1h_64_irq_handler+0x14/0x20
> [   82.350642]  el1h_64_irq+0x6c/0x70
> [   82.350911]  default_idle_call+0x30/0xd0 (P)
> [   82.351248]  do_idle+0x1d0/0x200
> [   82.351506]  cpu_startup_entry+0x38/0x48
> [   82.351818]  secondary_start_kernel+0x124/0x150
> [   82.352176]  __secondary_switched+0xac/0xb0
> [   82.352505] ---[ end trace 0000000000000000 ]---
> 
> 
> 
> [1] SFRAME-less livepatch RFC
> https://lore.kernel.org/live-patching/20250129232936.1795412-1-song@kernel.org/
> [2] special-static test from kpatch
> https://github.com/dynup/kpatch/blob/master/test/integration/linux-6.2.0/special-static.patch
> [3] Puranjay's kpatch with arm64 support
> https://github.com/puranjaymohan/kpatch/tree/arm64
> [4] My version of kpatch with arm64 and LTO support
> https://github.com/liu-song-6/kpatch/tree/fb-6.13-v2
> 
> On Mon, Jan 27, 2025 at 1:33 PM Weinan Liu <wnliu@google.com> wrote:
>>
>> This patchset implements a generic kernel sframe-based [1] unwinder.
>> The main goal is to support reliable stacktraces on arm64.
>>
>> On x86 orc unwinder provides reliable stacktraces. But arm64 misses the
>> required support from objtool: it cannot generate orc unwind tables for
>> arm64.
>>
>> Currently, there's already a sframe unwinder proposed for userspace: [2].
>> Since the sframe unwind table algorithm is similar, these two proposal
>> could integrate common functionality in the future.
>>
>> There are some incomplete features or challenges:
>>    - The unwinder doesn't yet work with kernel modules. The `start_addr` of
>>      FRE from kernel modules doesn't appear correct, preventing us from
>>      unwinding functions from kernel modules.
>>    - Currently, only GCC supports sframe.
>>
>> Ref:
>> [1]: https://sourceware.org/binutils/docs/sframe-spec.html
>> [2]: https://lore.kernel.org/lkml/cover.1730150953.git.jpoimboe@kernel.org/
>>
>> Madhavan T. Venkataraman (1):
>>    arm64: Define TIF_PATCH_PENDING for livepatch
>>
>> Weinan Liu (7):
>>    unwind: build kernel with sframe info
>>    arm64: entry: add unwind info for various kernel entries
>>    unwind: add sframe v2 header
>>    unwind: Implement generic sframe unwinder library
>>    unwind: arm64: Add sframe unwinder on arm64
>>    unwind: arm64: add reliable stacktrace support for arm64
>>    arm64: Enable livepatch for ARM64
>>
>>   Makefile                                   |   6 +
>>   arch/Kconfig                               |   8 +
>>   arch/arm64/Kconfig                         |   3 +
>>   arch/arm64/Kconfig.debug                   |  10 +
>>   arch/arm64/include/asm/stacktrace/common.h |   6 +
>>   arch/arm64/include/asm/thread_info.h       |   4 +-
>>   arch/arm64/kernel/entry-common.c           |   4 +
>>   arch/arm64/kernel/entry.S                  |  10 +
>>   arch/arm64/kernel/setup.c                  |   2 +
>>   arch/arm64/kernel/stacktrace.c             | 102 ++++++++++
>>   include/asm-generic/vmlinux.lds.h          |  12 ++
>>   include/linux/sframe_lookup.h              |  43 +++++
>>   kernel/Makefile                            |   1 +
>>   kernel/sframe.h                            | 215 +++++++++++++++++++++
>>   kernel/sframe_lookup.c                     | 196 +++++++++++++++++++
>>   15 files changed, 621 insertions(+), 1 deletion(-)
>>   create mode 100644 include/linux/sframe_lookup.h
>>   create mode 100644 kernel/sframe.h
>>   create mode 100644 kernel/sframe_lookup.c
>>
>> --
>> 2.48.1.262.g85cc9f2d1e-goog
>>
>>
Song Liu Feb. 13, 2025, 2:36 a.m. UTC | #16
On Wed, Feb 12, 2025 at 3:49 PM Josh Poimboeuf <jpoimboe@kernel.org> wrote:
>
> On Wed, Feb 12, 2025 at 03:32:40PM -0800, Song Liu wrote:
> > [   81.250437] ------------[ cut here ]------------
> > [   81.250818] refcount_t: saturated; leaking memory.
> > [   81.251201] WARNING: CPU: 0 PID: 95 at lib/refcount.c:22
> > refcount_warn_saturate+0x6c/0x140
> > [   81.251841] Modules linked in: livepatch_special_static(OEK)
> > [   81.252277] CPU: 0 UID: 0 PID: 95 Comm: bash Tainted: G
> > OE K    6.13.2-00321-g52d2813b4b07 #49
> > [   81.253003] Tainted: [O]=OOT_MODULE, [E]=UNSIGNED_MODULE, [K]=LIVEPATCH
> > [   81.253503] Hardware name: linux,dummy-virt (DT)
> > [   81.253856] pstate: 634000c5 (nZCv daIF +PAN -UAO +TCO +DIT -SSBS BTYPE=--)
> > [   81.254383] pc : refcount_warn_saturate+0x6c/0x140
> > [   81.254748] lr : refcount_warn_saturate+0x6c/0x140
> > [   81.255114] sp : ffff800085a6fc00
> > [   81.255371] x29: ffff800085a6fc00 x28: 0000000001200000 x27: ffff0000c2966180
> > [   81.255918] x26: 0000000000000000 x25: ffff8000829c0000 x24: ffff0000c2e9b608
> > [   81.256462] x23: ffff800083351000 x22: ffff0000c2e9af80 x21: ffff0000c062e140
> > [   81.257006] x20: ffff0000c1c10c00 x19: ffff800085a6fd80 x18: ffffffffffffffff
> > [   81.257544] x17: 0000000000000001 x16: ffffffffffffffff x15: 0000000000000006
> > [   81.258083] x14: 0000000000000000 x13: 2e79726f6d656d20 x12: 676e696b61656c20
> > [   81.258625] x11: ffff8000829f7d70 x10: 0000000000000147 x9 : ffff8000801546b4
> > [   81.259165] x8 : 00000000fffeffff x7 : 00000000ffff0000 x6 : ffff800082f77d70
> > [   81.259709] x5 : 80000000ffff0000 x4 : 0000000000000000 x3 : 0000000000000001
> > [   81.260257] x2 : ffff8000829f7a88 x1 : ffff8000829f7a88 x0 : 0000000000000026
> > [   81.260824] Call trace:
> > [   81.261015]  refcount_warn_saturate+0x6c/0x140 (P)
> > [   81.261387]  __refcount_add.constprop.0+0x60/0x70
> > [   81.261748]  copy_process+0xfdc/0xfd58 [livepatch_special_static]
>
> Does that copy_process+0xfdc/0xfd58 resolve to this line in
> copy_process()?
>
>                         refcount_inc(&current->signal->sigcnt);
>
> Maybe the klp rela reference to 'current' is bogus, or resolving to the
> wrong address somehow?

It resolves the following line.

p->signal->tty = tty_kref_get(current->signal->tty);

I am not quite sure how 'current' should be resolved.

The size of copy_process (0xfd58) is wrong. It is only about
5.5kB in size. Also, the copy_process function in the .ko file
looks very broken. I will try a few more things.

Thanks,
Song
Song Liu Feb. 13, 2025, 2:40 a.m. UTC | #17
On Wed, Feb 12, 2025 at 4:10 PM Indu Bhagat <indu.bhagat@oracle.com> wrote:
>
> On 2/12/25 3:32 PM, Song Liu wrote:
> > I run some tests with this set and my RFC set [1]. Most of
> > the test is done with kpatch-build. I tested both Puranjay's
> > version [3] and my version [4].
> >
> > For gcc 14.2.1, I have seen the following issue with this
> > test [2]. This happens with both upstream and 6.13.2.
> > The livepatch loaded fine, but the system spilled out the
> > following warning quickly.
> >
>
> In presence of the issue
> https://sourceware.org/bugzilla/show_bug.cgi?id=32666, I'd expect bad
> data in SFrame section.  Which may be causing this symptom?
>
> To be clear, the issue affects loaded kernel modules.  I cannot tell for
> certain - is there module loading involved in your test ?

The KLP is a module, I guess that is also affected?

During kpatch-build, we added some logic to drop the .sframe section.
I guess this is wrong, as we need the .sframe section when we apply
the next KLP. However, I don't think the issue is caused by missing
.sframe section.

Thanks,
Song
Josh Poimboeuf Feb. 13, 2025, 2:45 a.m. UTC | #18
On Wed, Feb 12, 2025 at 06:36:04PM -0800, Song Liu wrote:
> > > [   81.261748]  copy_process+0xfdc/0xfd58 [livepatch_special_static]
> >
> > Does that copy_process+0xfdc/0xfd58 resolve to this line in
> > copy_process()?
> >
> >                         refcount_inc(&current->signal->sigcnt);
> >
> > Maybe the klp rela reference to 'current' is bogus, or resolving to the
> > wrong address somehow?
> 
> It resolves the following line.
> 
> p->signal->tty = tty_kref_get(current->signal->tty);
> 
> I am not quite sure how 'current' should be resolved.

Hm, on arm64 it looks like the value of 'current' is stored in the
SP_EL0 register.  So I guess that shouldn't need any relocations.

> The size of copy_process (0xfd58) is wrong. It is only about
> 5.5kB in size. Also, the copy_process function in the .ko file
> looks very broken. I will try a few more things.

Ah ok, sounds like it's pretty borked.
Josh Poimboeuf Feb. 13, 2025, 2:52 a.m. UTC | #19
On Wed, Feb 12, 2025 at 06:40:33PM -0800, Song Liu wrote:
> On Wed, Feb 12, 2025 at 4:10 PM Indu Bhagat <indu.bhagat@oracle.com> wrote:
> >
> > On 2/12/25 3:32 PM, Song Liu wrote:
> > > I run some tests with this set and my RFC set [1]. Most of
> > > the test is done with kpatch-build. I tested both Puranjay's
> > > version [3] and my version [4].
> > >
> > > For gcc 14.2.1, I have seen the following issue with this
> > > test [2]. This happens with both upstream and 6.13.2.
> > > The livepatch loaded fine, but the system spilled out the
> > > following warning quickly.
> > >
> >
> > In presence of the issue
> > https://sourceware.org/bugzilla/show_bug.cgi?id=32666, I'd expect bad
> > data in SFrame section.  Which may be causing this symptom?
> >
> > To be clear, the issue affects loaded kernel modules.  I cannot tell for
> > certain - is there module loading involved in your test ?
> 
> The KLP is a module, I guess that is also affected?
> 
> During kpatch-build, we added some logic to drop the .sframe section.
> I guess this is wrong, as we need the .sframe section when we apply
> the next KLP. However, I don't think the issue is caused by missing
> .sframe section.

Right, it looks like it unwound through the patch module just fine.
Puranjay Mohan Feb. 13, 2025, 7:26 a.m. UTC | #20
Song Liu <song@kernel.org> writes:

> On Wed, Feb 12, 2025 at 4:10 PM Indu Bhagat <indu.bhagat@oracle.com> wrote:
>>
>> On 2/12/25 3:32 PM, Song Liu wrote:
>> > I run some tests with this set and my RFC set [1]. Most of
>> > the test is done with kpatch-build. I tested both Puranjay's
>> > version [3] and my version [4].
>> >
>> > For gcc 14.2.1, I have seen the following issue with this
>> > test [2]. This happens with both upstream and 6.13.2.
>> > The livepatch loaded fine, but the system spilled out the
>> > following warning quickly.
>> >
>>
>> In presence of the issue
>> https://sourceware.org/bugzilla/show_bug.cgi?id=32666, I'd expect bad
>> data in SFrame section.  Which may be causing this symptom?
>>
>> To be clear, the issue affects loaded kernel modules.  I cannot tell for
>> certain - is there module loading involved in your test ?
>
> The KLP is a module, I guess that is also affected?
>
> During kpatch-build, we added some logic to drop the .sframe section.
> I guess this is wrong, as we need the .sframe section when we apply
> the next KLP. However, I don't think the issue is caused by missing
> .sframe section.

Hi, I did the same testing and did not get the Warning.

I am testing on the 6.12.11 kernel with GCC 11.4.1.

Just to verify, the patch we are testing is:

--- >8 ---

diff -Nupr src.orig/kernel/fork.c src/kernel/fork.c
--- src.orig/kernel/fork.c      2023-01-12 11:20:05.408700033 -0500
+++ src/kernel/fork.c   2023-01-12 11:21:19.186137466 -0500
@@ -1700,10 +1700,18 @@ static void posix_cpu_timers_init_group(
        posix_cputimers_group_init(pct, cpu_limit);
 }

+void kpatch_foo(void)
+{
+       if (!jiffies)
+               printk("kpatch copy signal\n");
+}
+
 static int copy_signal(unsigned long clone_flags, struct task_struct *tsk)
 {
        struct signal_struct *sig;

+       kpatch_foo();
+
        if (clone_flags & CLONE_THREAD)
                return 0;
--- 8< ---

P.S. - I have a downstream patch for create-diff-object to generate .sframe sections for
livepatch module, will add it to the PR after some cleanups.

Thanks,
Puranjay
Song Liu Feb. 13, 2025, 7:37 a.m. UTC | #21
On Wed, Feb 12, 2025 at 11:26 PM Puranjay Mohan <puranjay@kernel.org> wrote:
>
> Song Liu <song@kernel.org> writes:
>
> > On Wed, Feb 12, 2025 at 4:10 PM Indu Bhagat <indu.bhagat@oracle.com> wrote:
> >>
> >> On 2/12/25 3:32 PM, Song Liu wrote:
> >> > I run some tests with this set and my RFC set [1]. Most of
> >> > the test is done with kpatch-build. I tested both Puranjay's
> >> > version [3] and my version [4].
> >> >
> >> > For gcc 14.2.1, I have seen the following issue with this
> >> > test [2]. This happens with both upstream and 6.13.2.
> >> > The livepatch loaded fine, but the system spilled out the
> >> > following warning quickly.
> >> >
> >>
> >> In presence of the issue
> >> https://sourceware.org/bugzilla/show_bug.cgi?id=32666, I'd expect bad
> >> data in SFrame section.  Which may be causing this symptom?
> >>
> >> To be clear, the issue affects loaded kernel modules.  I cannot tell for
> >> certain - is there module loading involved in your test ?
> >
> > The KLP is a module, I guess that is also affected?
> >
> > During kpatch-build, we added some logic to drop the .sframe section.
> > I guess this is wrong, as we need the .sframe section when we apply
> > the next KLP. However, I don't think the issue is caused by missing
> > .sframe section.
>
> Hi, I did the same testing and did not get the Warning.
>
> I am testing on the 6.12.11 kernel with GCC 11.4.1.

Could you please also try kernel 6.13.2?

> Just to verify, the patch we are testing is:

Yes, this is the test patch.
>
> --- >8 ---
[...]
> --- 8< ---
>
> P.S. - I have a downstream patch for create-diff-object to generate .sframe sections for
> livepatch module, will add it to the PR after some cleanups.

Yeah, I think the .sframe section is still needed.

Thanks,
Song
Puranjay Mohan Feb. 13, 2025, 7:46 a.m. UTC | #22
Song Liu <song@kernel.org> writes:

> On Wed, Feb 12, 2025 at 6:45 PM Josh Poimboeuf <jpoimboe@kernel.org> wrote:
>>
>> On Wed, Feb 12, 2025 at 06:36:04PM -0800, Song Liu wrote:
>> > > > [   81.261748]  copy_process+0xfdc/0xfd58 [livepatch_special_static]
>> > >
>> > > Does that copy_process+0xfdc/0xfd58 resolve to this line in
>> > > copy_process()?
>> > >
>> > >                         refcount_inc(&current->signal->sigcnt);
>> > >
>> > > Maybe the klp rela reference to 'current' is bogus, or resolving to the
>> > > wrong address somehow?
>> >
>> > It resolves the following line.
>> >
>> > p->signal->tty = tty_kref_get(current->signal->tty);
>> >
>> > I am not quite sure how 'current' should be resolved.
>>
>> Hm, on arm64 it looks like the value of 'current' is stored in the
>> SP_EL0 register.  So I guess that shouldn't need any relocations.
>>
>> > The size of copy_process (0xfd58) is wrong. It is only about
>> > 5.5kB in size. Also, the copy_process function in the .ko file
>> > looks very broken. I will try a few more things.
>
> When I try each step of kpatch-build, the copy_process function
> looks reasonable (according to gdb-disassemble) in fork.o and
> output.o. However, copy_process looks weird in livepatch-special-static.o,
> which is generated by ld:
>
> ld -EL  -maarch64linux -z norelro -z noexecstack
> --no-warn-rwx-segments -T ././kpatch.lds  -r -o
> livepatch-special-static.o ./patch-hook.o ./output.o
>
> I have attached these files to the email. I am not sure whether
> the email server will let them through.

I think, I am missing something here,

I did :

objdump -Dr livepatch-special-static.o | less

and

objdump -Dr output.o | less

and the disassembly of copy_process() looks exactly same.

> Indu, does this look like an issue with ld?
>
> Thanks,
> Song
Puranjay Mohan Feb. 13, 2025, 7:53 a.m. UTC | #23
Song Liu <song@kernel.org> writes:

> On Wed, Feb 12, 2025 at 11:26 PM Puranjay Mohan <puranjay@kernel.org> wrote:
>>
>> Song Liu <song@kernel.org> writes:
>>
>> > On Wed, Feb 12, 2025 at 4:10 PM Indu Bhagat <indu.bhagat@oracle.com> wrote:
>> >>
>> >> On 2/12/25 3:32 PM, Song Liu wrote:
>> >> > I run some tests with this set and my RFC set [1]. Most of
>> >> > the test is done with kpatch-build. I tested both Puranjay's
>> >> > version [3] and my version [4].
>> >> >
>> >> > For gcc 14.2.1, I have seen the following issue with this
>> >> > test [2]. This happens with both upstream and 6.13.2.
>> >> > The livepatch loaded fine, but the system spilled out the
>> >> > following warning quickly.
>> >> >
>> >>
>> >> In presence of the issue
>> >> https://sourceware.org/bugzilla/show_bug.cgi?id=32666, I'd expect bad
>> >> data in SFrame section.  Which may be causing this symptom?
>> >>
>> >> To be clear, the issue affects loaded kernel modules.  I cannot tell for
>> >> certain - is there module loading involved in your test ?
>> >
>> > The KLP is a module, I guess that is also affected?
>> >
>> > During kpatch-build, we added some logic to drop the .sframe section.
>> > I guess this is wrong, as we need the .sframe section when we apply
>> > the next KLP. However, I don't think the issue is caused by missing
>> > .sframe section.
>>
>> Hi, I did the same testing and did not get the Warning.
>>
>> I am testing on the 6.12.11 kernel with GCC 11.4.1.
>
> Could you please also try kernel 6.13.2?
>
>> Just to verify, the patch we are testing is:
>
> Yes, this is the test patch.
>>
>> --- >8 ---
> [...]
>> --- 8< ---
>>
>> P.S. - I have a downstream patch for create-diff-object to generate .sframe sections for
>> livepatch module, will add it to the PR after some cleanups.
>
> Yeah, I think the .sframe section is still needed.
>

Hi Song,

Can you try with this:
https://github.com/puranjaymohan/kpatch/tree/arm64_wip

This has the .sframe logic patch, but it looks as if I wrote that code
in a 30 minute leetcode interview. I need to refactor it before I send
it for review with the main PR.

Can you test with this branch with your setup?

Thanks,
Puranjay
Puranjay Mohan Feb. 13, 2025, 8:37 a.m. UTC | #24
Song Liu <song@kernel.org> writes:

> On Wed, Feb 12, 2025 at 11:26 PM Puranjay Mohan <puranjay@kernel.org> wrote:
>>
>> Song Liu <song@kernel.org> writes:
>>
>> > On Wed, Feb 12, 2025 at 4:10 PM Indu Bhagat <indu.bhagat@oracle.com> wrote:
>> >>
>> >> On 2/12/25 3:32 PM, Song Liu wrote:
>> >> > I run some tests with this set and my RFC set [1]. Most of
>> >> > the test is done with kpatch-build. I tested both Puranjay's
>> >> > version [3] and my version [4].
>> >> >
>> >> > For gcc 14.2.1, I have seen the following issue with this
>> >> > test [2]. This happens with both upstream and 6.13.2.
>> >> > The livepatch loaded fine, but the system spilled out the
>> >> > following warning quickly.
>> >> >
>> >>
>> >> In presence of the issue
>> >> https://sourceware.org/bugzilla/show_bug.cgi?id=32666, I'd expect bad
>> >> data in SFrame section.  Which may be causing this symptom?
>> >>
>> >> To be clear, the issue affects loaded kernel modules.  I cannot tell for
>> >> certain - is there module loading involved in your test ?
>> >
>> > The KLP is a module, I guess that is also affected?
>> >
>> > During kpatch-build, we added some logic to drop the .sframe section.
>> > I guess this is wrong, as we need the .sframe section when we apply
>> > the next KLP. However, I don't think the issue is caused by missing
>> > .sframe section.
>>
>> Hi, I did the same testing and did not get the Warning.
>>
>> I am testing on the 6.12.11 kernel with GCC 11.4.1.
>
> Could you please also try kernel 6.13.2?
>

I have tested with 6.13.2, here are the results:

[ec2-user@ip-172-31-32-86 ~]$ uname -r
6.13.2+

My tree looks like:

[ec2-user@ip-172-31-32-86 linux-upstream]$ git log --oneline
bdf4086dd (HEAD) arm64: Enable livepatch for ARM64
3904c7058 arm64: Define TIF_PATCH_PENDING for livepatch
b5de442a9 unwind: arm64: add reliable stacktrace support for arm64
fdc243fa8 unwind: arm64: Add sframe unwinder on arm64
87681b7c0 unwind: Implement generic sframe unwinder library
c8833ba50 unwind: add sframe v2 header
f3f3863cf arm64: entry: add unwind info for various kernel entries
57ab97f05 unwind: build kernel with sframe info
0da4b4b84 Linux 6.13.2

I have also fixed the 87681b7c0 ("unwind: Implement generic sframe
unwinder library")

with:

--- >8 ---

diff --git a/kernel/sframe_lookup.c b/kernel/sframe_lookup.c
index 846f1da95d89..28bec5064dc7 100644
--- a/kernel/sframe_lookup.c
+++ b/kernel/sframe_lookup.c
@@ -82,7 +82,7 @@ static struct sframe_fde *find_fde(const struct sframe_table *tbl, unsigned long
        if (f >= tbl->sfhdr_p->num_fdes || f < 0)
                return NULL;
        fdep = tbl->fde_p + f;
-       if (ip < fdep->start_addr || ip >= fdep->start_addr + fdep->size)
+       if (ip < fdep->start_addr || ip > fdep->start_addr + fdep->size)
                return NULL;

        return fdep;
@@ -106,7 +106,7 @@ static int find_fre(const struct sframe_table *tbl, unsigned long pc,
        else
                ip_off = (int32_t)(pc - (unsigned long)tbl->sfhdr_p) - fdep->start_addr;

-       if (ip_off < 0 || ip_off >= fdep->size)
+       if (ip_off < 0 || ip_off > fdep->size)
                return -EINVAL;

        /*

--- 8< ---

GCC is gcc (GCC) 11.4.1 20230605 (Red Hat 11.4.1-2)

kpatch is from https://github.com/puranjaymohan/kpatch/tree/arm64_wip

I run the with following:

./kpatch/kpatch-build/kpatch-build --non-replace -d -v \
linux-upstream/vmlinux -s linux-upstream/ -c linux-upstream/.config \
kpatch/test/integration/linux-6.2.0/special-static.patch

and my dmesg output is:

[ec2-user@ip-172-31-32-86 ~]$ sudo dmesg
[  167.202596] livepatch_special_static: loading out-of-tree module taints kernel.
[  167.203217] livepatch_special_static: tainting kernel with TAINT_LIVEPATCH
[  167.203760] livepatch_special_static: module verification failed: signature and/or required key missing - tainting kernel
[  167.205659] livepatch: enabling patch 'livepatch_special_static'
[  167.207358] livepatch: 'livepatch_special_static': starting patching transition
[  168.264901] livepatch: 'livepatch_special_static': patching complete
[  410.641806] livepatch: 'livepatch_special_static': starting unpatching transition
[  412.389369] livepatch: 'livepatch_special_static': unpatching complete

I even ran stress-ng with the livepatch loaded to see if something
happens.


P.S. - The livepatch doesn't have copy_process() but only copy_signal(),
yours had copy_process() somehow.

Here is the symbol table of the .ko

Symbol table '.symtab' contains 169 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 0000000000000000     0 SECTION LOCAL  DEFAULT    1 .note.gnu.build-id
     2: 0000000000000000     0 SECTION LOCAL  DEFAULT    2 .note.Linux
     3: 0000000000000000     0 SECTION LOCAL  DEFAULT    3 .text
     4: 0000000000000000     0 SECTION LOCAL  DEFAULT    5 .exit.text
     5: 0000000000000000     0 SECTION LOCAL  DEFAULT    7 .init.text
     6: 0000000000000000     0 SECTION LOCAL  DEFAULT    9 .text.copy_signal
     7: 0000000000000000     0 SECTION LOCAL  DEFAULT   11 .text.kpatch_foo
     8: 0000000000000000     0 SECTION LOCAL  DEFAULT   13 .altinstructions
     9: 0000000000000000     0 SECTION LOCAL  DEFAULT   15 __patchable_function_entries
    10: 0000000000000000     0 SECTION LOCAL  DEFAULT   17 .codetag.alloc_tags
    11: 0000000000000000     0 SECTION LOCAL  DEFAULT   18 .plt
    12: 0000000000000000     0 SECTION LOCAL  DEFAULT   19 .init.plt
    13: 0000000000000000     0 SECTION LOCAL  DEFAULT   20 .text.ftrace_trampoline
    14: 0000000000000000     0 SECTION LOCAL  DEFAULT   21 .rodata.str1.8
    15: 0000000000000000     0 SECTION LOCAL  DEFAULT   22 .modinfo
    16: 0000000000000000     0 SECTION LOCAL  DEFAULT   23 .sframe
    17: 0000000000000000     0 SECTION LOCAL  DEFAULT   25 .rodata.trace_raw_output_task_newtask.str1.8
    18: 0000000000000000     0 SECTION LOCAL  DEFAULT   26 .rodata.trace_raw_output_task_rename.str1.8
    19: 0000000000000000     0 SECTION LOCAL  DEFAULT   27 .rodata.sighand_ctor.str1.8
    20: 0000000000000000     0 SECTION LOCAL  DEFAULT   28 .rodata.str
    21: 0000000000000000     0 SECTION LOCAL  DEFAULT   29 .rodata.__mmdrop.str1.8
    22: 0000000000000000     0 SECTION LOCAL  DEFAULT   30 .rodata.copy_signal.str1.8
    23: 0000000000000000     0 SECTION LOCAL  DEFAULT   31 .rodata.mm_init.str1.8
    24: 0000000000000000     0 SECTION LOCAL  DEFAULT   32 .rodata.vm_area_alloc.str1.8
    25: 0000000000000000     0 SECTION LOCAL  DEFAULT   33 .rodata.dup_mmap.str1.8
    26: 0000000000000000     0 SECTION LOCAL  DEFAULT   34 .rodata.copy_process.str1.8
    27: 0000000000000000     0 SECTION LOCAL  DEFAULT   35 .rodata.kernel_clone.str1.8
    28: 0000000000000000     0 SECTION LOCAL  DEFAULT   36 .rodata.str__task__trace_system_name
    29: 0000000000000000     0 SECTION LOCAL  DEFAULT   37 .kpatch.strings
    30: 0000000000000000     0 SECTION LOCAL  DEFAULT   38 .kpatch.funcs
    31: 0000000000000000     0 SECTION LOCAL  DEFAULT   40 __versions
    32: 0000000000000000     0 SECTION LOCAL  DEFAULT   41 .bss
    33: 0000000000000000     0 SECTION LOCAL  DEFAULT   42 .bss.__key.4
    34: 0000000000000000     0 SECTION LOCAL  DEFAULT   43 .bss.__key.5
    35: 0000000000000000     0 SECTION LOCAL  DEFAULT   44 .bss.__key.6
    36: 0000000000000000     0 SECTION LOCAL  DEFAULT   45 .note.GNU-stack
    37: 0000000000000000     0 SECTION LOCAL  DEFAULT   46 .comment
    38: 0000000000000000     0 SECTION LOCAL  DEFAULT   47 .data
    39: 0000000000000000     0 SECTION LOCAL  DEFAULT   49 .exit.data
    40: 0000000000000000     0 SECTION LOCAL  DEFAULT   51 .init.data
    41: 0000000000000000     0 SECTION LOCAL  DEFAULT   53 .kpatch.callbacks.pre_patch
    42: 0000000000000000     0 SECTION LOCAL  DEFAULT   54 .kpatch.callbacks.post_patch
    43: 0000000000000000     0 SECTION LOCAL  DEFAULT   55 .kpatch.callbacks.pre_unpatch
    44: 0000000000000000     0 SECTION LOCAL  DEFAULT   56 .kpatch.callbacks.post_unpatch
    45: 0000000000000000     0 SECTION LOCAL  DEFAULT   57 .kpatch.force
    46: 0000000000000000     0 SECTION LOCAL  DEFAULT   58 .gnu.linkonce.this_module
    47: 0000000000000000     0 SECTION LOCAL  DEFAULT   60 .debug_info
    48: 0000000000000000     0 SECTION LOCAL  DEFAULT   62 .debug_abbrev
    49: 0000000000000000     0 SECTION LOCAL  DEFAULT   63 .debug_loc
    50: 0000000000000000     0 SECTION LOCAL  DEFAULT   65 .debug_aranges
    51: 0000000000000000     0 SECTION LOCAL  DEFAULT   67 .debug_ranges
    52: 0000000000000000     0 SECTION LOCAL  DEFAULT   69 .debug_line
    53: 0000000000000000     0 SECTION LOCAL  DEFAULT   71 .debug_str
    54: 0000000000000000     0 SECTION LOCAL  DEFAULT   72 .debug_frame
    55: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS module-common.c
    56: 0000000000000062    52 OBJECT  LOCAL  DEFAULT   22 __UNIQUE_ID_vermagic547
    57: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT    2 $d
    58: 0000000000000000    24 OBJECT  LOCAL  DEFAULT    2 _note_19
    59: 0000000000000018    52 OBJECT  LOCAL  DEFAULT    2 _note_18
    60: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS patch-hook.c
    61: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT    3 $x
    62: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT   15 $d
    63: 0000000000000008   104 FUNC    LOCAL  DEFAULT    3 patch_free_livepatch
    64: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT    5 $x
    65: 0000000000000000    36 FUNC    LOCAL  DEFAULT    5 patch_exit
    66: 0000000000000078   260 FUNC    LOCAL  DEFAULT    3 patch_free_scaffold
    67: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT   21 $d
    68: 0000000000000188   280 FUNC    LOCAL  DEFAULT    3 patch_find_object_by_name
    69: 00000000000002a8   432 FUNC    LOCAL  DEFAULT    3 add_callbacks_to_patch_objects
    70: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT    7 $x
    71: 0000000000000008   584 FUNC    LOCAL  DEFAULT    7 patch_init
    72: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT   47 $d
    73: 0000000000000000    16 OBJECT  LOCAL  DEFAULT   47 patch_objects
    74: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT   41 $d
    75: 0000000000000000     8 OBJECT  LOCAL  DEFAULT   41 lpatch
    76: 0000000000000008     4 OBJECT  LOCAL  DEFAULT   41 patch_objects_nr
    77: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT   49 $d
    78: 0000000000000000     8 OBJECT  LOCAL  DEFAULT   49 __UNIQUE_ID___addressable_cleanup_module737
    79: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT   51 $d
    80: 0000000000000000     8 OBJECT  LOCAL  DEFAULT   51 __UNIQUE_ID___addressable_init_module736
    81: 0000000000000000    12 OBJECT  LOCAL  DEFAULT   22 __UNIQUE_ID_livepatch739
    82: 000000000000000c    12 OBJECT  LOCAL  DEFAULT   22 __UNIQUE_ID_license738
    83: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS fork.c
    84: 0000000000000008   496 FUNC    LOCAL  DEFAULT    9 copy_signal
    85: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT   25 $d
    86: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT   26 $d
    87: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT   27 $d
    88: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT   29 $d
    89: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT   30 $d
    90: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT   31 $d
    91: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT   32 $d
    92: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT   33 $d
    93: 0000000000000128     0 NOTYPE  LOCAL  DEFAULT   21 $d
    94: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT   34 $d
    95: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT   35 $d
    96: 0000000000000000     0 OBJECT  LOCAL  DEFAULT   42 __key.4
    97: 0000000000000000     0 OBJECT  LOCAL  DEFAULT   43 __key.5
    98: 0000000000000000     0 OBJECT  LOCAL  DEFAULT   44 __key.6
    99: 0000000000000000     5 OBJECT  LOCAL  DEFAULT   36 str__task__trace_system_name
   100: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT   36 $d
   101: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT   28 .L14472^B1
   102: 000000000000000e     0 NOTYPE  LOCAL  DEFAULT   28 .L14472^B2
   103: 000000000000001c     0 NOTYPE  LOCAL  DEFAULT   28 .L14472^B3
   104: 000000000000002a     0 NOTYPE  LOCAL  DEFAULT   28 .L14472^B4
   105: 0000000000000038     0 NOTYPE  LOCAL  DEFAULT   28 .L14472^B5
   106: 0000000000000046     0 NOTYPE  LOCAL  DEFAULT   28 .L14472^B6
   107: 0000000000000054     0 NOTYPE  LOCAL  DEFAULT   28 .L14472^B7
   108: 0000000000000062     0 NOTYPE  LOCAL  DEFAULT   28 .L14472^B8
   109: 0000000000000070     0 NOTYPE  LOCAL  DEFAULT   28 .L14472^B9
   110: 000000000000007e     0 NOTYPE  LOCAL  DEFAULT   28 .L14472^B10
   111: 000000000000008c     0 NOTYPE  LOCAL  DEFAULT   28 .L14472^B11
   112: 00000000000000a9     0 NOTYPE  LOCAL  DEFAULT   28 .L14472^B12
   113: 00000000000000c1     0 NOTYPE  LOCAL  DEFAULT   28 .L14472^B13
   114: 00000000000000d9     0 NOTYPE  LOCAL  DEFAULT   28 .L14472^B14
   115: 00000000000000f1     0 NOTYPE  LOCAL  DEFAULT   28 .L14472^B15
   116: 0000000000000109     0 NOTYPE  LOCAL  DEFAULT   28 .L14472^B16
   117: 0000000000000124     0 NOTYPE  LOCAL  DEFAULT   28 .L14472^B17
   118: 0000000000000132     0 NOTYPE  LOCAL  DEFAULT   28 .L14472^B18
   119: 000000000000014d     0 NOTYPE  LOCAL  DEFAULT   28 .L14472^B19
   120: 0000000000000168     0 NOTYPE  LOCAL  DEFAULT   28 .L14472^B20
   121: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS livepatch-special-static.mod.c
   122: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT   58 $d
   123: 0000000000000018    35 OBJECT  LOCAL  DEFAULT   22 __UNIQUE_ID_srcversion549
   124: 000000000000003b     9 OBJECT  LOCAL  DEFAULT   22 __UNIQUE_ID_depends548
   125: 0000000000000044    30 OBJECT  LOCAL  DEFAULT   22 __UNIQUE_ID_name547
   126: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT   40 $d
   127: 0000000000000000     0 OBJECT  LOCAL  DEFAULT OS [0xff20] .klp.sym.vmlinux.signal_cachep,1
   128: 0000000000000000  1216 OBJECT  LOCAL  DEFAULT   40 ____versions
   129: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT   55 __kpatch_callbacks_pre_unpatch_end
   130: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND __init_rwsem
   131: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND __list_add_valid_or_report
   132: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND __kmalloc_noprof
   133: 0000000000000000  1344 OBJECT  GLOBAL DEFAULT   58 __this_module
   134: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT   54 __kpatch_callbacks_post_patch
   135: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT   57 __kpatch_force_funcs
   136: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT   17 __stop_alloc_tags
   137: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND hrtimer_init
   138: 0000000000000000    36 FUNC    GLOBAL DEFAULT    5 cleanup_module
   139: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND memcpy
   140: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND klp_enable_patch
   141: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND kfree
   142: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT   53 __kpatch_callbacks_pre_patch
   143: 0000000000000008   584 FUNC    GLOBAL DEFAULT    7 init_module
   144: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT   55 __kpatch_callbacks_pre_unpatch
   145: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT   17 __start_alloc_tags
   146: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT   38 __kpatch_funcs
   147: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND _printk
   148: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT   57 __kpatch_force_funcs_end
   149: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND queued_spin_lock_slowpath
   150: 0000000000000038     0 NOTYPE  GLOBAL DEFAULT   38 __kpatch_funcs_end
   151: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT   54 __kpatch_callbacks_post_patch_end
   152: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT   53 __kpatch_callbacks_pre_patch_end
   153: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND __list_del_entry_valid_or_report
   154: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND __mutex_init
   155: 0000000000000008    60 FUNC    GLOBAL DEFAULT   11 kpatch_foo
   156: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT   56 __kpatch_callbacks_post_unpatch_end
   157: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND kmem_cache_alloc_noprof
   158: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND __init_waitqueue_head
   159: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND strcmp
   160: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND jiffies
   161: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT   56 __kpatch_callbacks_post_unpatch
   162: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND __kmalloc_cache_noprof
   163: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND alt_cb_patch_nops
   164: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND kmalloc_caches
   165: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT OS [0xff20] .klp.sym.vmlinux.it_real_fn,0
   166: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT OS [0xff20] .klp.sym.vmlinux.posix_cputimers_group_init,0
   167: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT OS [0xff20] .klp.sym.vmlinux.tty_audit_fork,0
   168: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT OS [0xff20] .klp.sym.vmlinux.sched_autogroup_fork,0

and Sections:

[ec2-user@ip-172-31-32-86 ~]$ readelf -WS livepatch-special-static.ko
There are 78 section headers, starting at offset 0x1727d8:

Section Headers:
  [Nr] Name              Type            Address          Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            0000000000000000 000000 000000 00      0   0  0
  [ 1] .note.gnu.build-id NOTE            0000000000000000 000040 000024 00   A  0   0  4
  [ 2] .note.Linux       NOTE            0000000000000000 000064 00004c 00   A  0   0  4
  [ 3] .text             PROGBITS        0000000000000000 0000c0 000458 00  AX  0   0 32
  [ 4] .rela.text        RELA            0000000000000000 000518 000570 18   I 74   3  8
  [ 5] .exit.text        PROGBITS        0000000000000000 000a88 000024 00  AX  0   0  8
  [ 6] .rela.exit.text   RELA            0000000000000000 000ab0 000048 18   I 74   5  8
  [ 7] .init.text        PROGBITS        0000000000000000 000b00 000250 00  AX  0   0 32
  [ 8] .rela.init.text   RELA            0000000000000000 000d50 000348 18   I 74   7  8
  [ 9] .text.copy_signal PROGBITS        0000000000000000 001098 0001f8 00  AX  0   0  8
  [10] .rela.text.copy_signal RELA            0000000000000000 001290 000240 18   I 74   9  8
  [11] .text.kpatch_foo  PROGBITS        0000000000000000 0014d0 000044 00  AX  0   0  8
  [12] .rela.text.kpatch_foo RELA            0000000000000000 001518 000078 18   I 74  11  8
  [13] .altinstructions  PROGBITS        0000000000000000 001590 00000c 00   A  0   0  8
  [14] .rela.altinstructions RELA            0000000000000000 0015a0 000030 18   I 74  13  8
  [15] __patchable_function_entries PROGBITS        0000000000000010 0015d0 000038 00 WAL  3   0  8
  [16] .rela__patchable_function_entries RELA            0000000000000000 001608 0000a8 18   I 74  15  8
  [17] .codetag.alloc_tags PROGBITS        0000000000000540 0016b0 000000 00   W  0   0  1
  [18] .plt              PROGBITS        0000000000000000 0016b0 000001 00  AX  0   0  1
  [19] .init.plt         PROGBITS        0000000000000000 0016b1 000001 00   A  0   0  1
  [20] .text.ftrace_trampoline PROGBITS        0000000000000000 0016b2 000001 00  AX  0   0  1
  [21] .rodata.str1.8    PROGBITS        0000000000000000 0016b8 000455 01 AMS  0   0  8
  [22] .modinfo          PROGBITS        0000000000000000 001b0d 000096 00   A  0   0  1
  [23] .sframe           PROGBITS        0000000000000000 001ba8 0001ad 00   A  0   0  8
  [24] .rela.sframe      RELA            0000000000000000 001d58 0000c0 18   I 74  23  8
  [25] .rodata.trace_raw_output_task_newtask.str1.8 PROGBITS        0000000000000000 001e18 000032 01 AMS  0   0  8
  [26] .rodata.trace_raw_output_task_rename.str1.8 PROGBITS        0000000000000000 001e50 000030 01 AMS  0   0  8
  [27] .rodata.sighand_ctor.str1.8 PROGBITS        0000000000000000 001e80 000017 01 AMS  0   0  8
  [28] .rodata.str       PROGBITS        0000000000000000 001e97 000180 01 AMS  0   0  1
  [29] .rodata.__mmdrop.str1.8 PROGBITS        0000000000000000 002018 00006b 01 AMS  0   0  8
  [30] .rodata.copy_signal.str1.8 PROGBITS        0000000000000000 002088 00005f 01 AMS  0   0  8
  [31] .rodata.mm_init.str1.8 PROGBITS        0000000000000000 0020e8 00000f 01 AMS  0   0  8
  [32] .rodata.vm_area_alloc.str1.8 PROGBITS        0000000000000000 0020f8 000014 01 AMS  0   0  8
  [33] .rodata.dup_mmap.str1.8 PROGBITS        0000000000000000 002110 000054 01 AMS  0   0  8
  [34] .rodata.copy_process.str1.8 PROGBITS        0000000000000000 002168 000017 01 AMS  0   0  8
  [35] .rodata.kernel_clone.str1.8 PROGBITS        0000000000000000 002180 000009 01 AMS  0   0  8
  [36] .rodata.str__task__trace_system_name PROGBITS        0000000000000000 002190 000005 00   A  0   0  8
  [37] .kpatch.strings   PROGBITS        0000000000000000 002195 00006c 00   A  0   0  1
  [38] .kpatch.funcs     PROGBITS        0000000000000000 002208 000038 00   A  0   0  8
  [39] .rela.kpatch.funcs RELA            0000000000000000 002240 000048 18   I 74  38  8
  [40] __versions        PROGBITS        0000000000000000 002288 0004c0 00   A  0   0  8
  [41] .bss              NOBITS          0000000000000000 002748 00000c 00  WA  0   0  8
  [42] .bss.__key.4      NOBITS          0000000000000000 002748 000000 00  WA  0   0  8
  [43] .bss.__key.5      NOBITS          0000000000000000 002748 000000 00  WA  0   0  8
  [44] .bss.__key.6      NOBITS          0000000000000000 002748 000000 00  WA  0   0  8
  [45] .note.GNU-stack   PROGBITS        0000000000000000 002748 000000 00      0   0  1
  [46] .comment          PROGBITS        0000000000000000 002748 00008d 01  MS  0   0  1
  [47] .data             PROGBITS        0000000000000048 0027d8 000010 00  WA  0   0  8
  [48] .rela.data        RELA            0000000000000000 0027e8 000030 18   I 74  47  8
  [49] .exit.data        PROGBITS        0000000000000000 002818 000008 00  WA  0   0  8
  [50] .rela.exit.data   RELA            0000000000000000 002820 000018 18   I 74  49  8
  [51] .init.data        PROGBITS        0000000000000000 002838 000008 00  WA  0   0  8
  [52] .rela.init.data   RELA            0000000000000000 002840 000018 18   I 74  51  8
  [53] .kpatch.callbacks.pre_patch PROGBITS        0000000000000000 002858 000008 00  WA  0   0  1
  [54] .kpatch.callbacks.post_patch PROGBITS        0000000000000000 002860 000008 00  WA  0   0  1
  [55] .kpatch.callbacks.pre_unpatch PROGBITS        0000000000000000 002868 000008 00  WA  0   0  1
  [56] .kpatch.callbacks.post_unpatch PROGBITS        0000000000000000 002870 000008 00  WA  0   0  1
  [57] .kpatch.force     PROGBITS        0000000000000000 002878 000008 00  WA  0   0  1
  [58] .gnu.linkonce.this_module PROGBITS        0000000000000000 002880 000540 00  WA  0   0 64
  [59] .rela.gnu.linkonce.this_module RELA            0000000000000000 002dc0 000030 18   I 74  58  8
  [60] .debug_info       PROGBITS        0000000000000000 002df0 06041d 00      0   0  1
  [61] .rela.debug_info  RELA            0000000000000000 063210 08a390 18   I 74  60  8
  [62] .debug_abbrev     PROGBITS        0000000000000000 0ed5a0 002392 00      0   0  1
  [63] .debug_loc        PROGBITS        0000000000000000 0ef932 031dd6 00      0   0  1
  [64] .rela.debug_loc   RELA            0000000000000000 121708 004e30 18   I 74  63  8
  [65] .debug_aranges    PROGBITS        0000000000000000 126538 000740 00      0   0  1
  [66] .rela.debug_aranges RELA            0000000000000000 126c78 0000d8 18   I 74  65  8
  [67] .debug_ranges     PROGBITS        0000000000000000 126d50 00a870 00      0   0  1
  [68] .rela.debug_ranges RELA            0000000000000000 1315c0 001320 18   I 74  67  8
  [69] .debug_line       PROGBITS        0000000000000000 1328e0 010623 00      0   0  1
  [70] .rela.debug_line  RELA            0000000000000000 142f08 000078 18   I 74  69  8
  [71] .debug_str        PROGBITS        0000000000000000 142f80 02b764 01  MS  0   0  1
  [72] .debug_frame      PROGBITS        0000000000000000 16e6e8 001900 00      0   0  8
  [73] .rela.debug_frame RELA            0000000000000000 16ffe8 000b28 18   I 74  72  8
  [74] .symtab           SYMTAB          0000000000000000 170b10 000fd8 18     75 129  8
  [75] .strtab           STRTAB          0000000000000000 171ae8 0006cc 00      0   0  1
  [76] .shstrtab         STRTAB          0000000000000000 1721b4 000576 00      0   0  1
  [77] .klp.rela.vmlinux..text.copy_signal RELA 0000000000000000 172730 0000a8 18 AIo 74   9  8
  

Thanks,
Puranjay
Song Liu Feb. 13, 2025, 7:40 p.m. UTC | #25
On Wed, Feb 12, 2025 at 11:46 PM Puranjay Mohan <puranjay@kernel.org> wrote:
>
> Song Liu <song@kernel.org> writes:
>
> > On Wed, Feb 12, 2025 at 6:45 PM Josh Poimboeuf <jpoimboe@kernel.org> wrote:
> >>
> >> On Wed, Feb 12, 2025 at 06:36:04PM -0800, Song Liu wrote:
> >> > > > [   81.261748]  copy_process+0xfdc/0xfd58 [livepatch_special_static]
> >> > >
> >> > > Does that copy_process+0xfdc/0xfd58 resolve to this line in
> >> > > copy_process()?
> >> > >
> >> > >                         refcount_inc(&current->signal->sigcnt);
> >> > >
> >> > > Maybe the klp rela reference to 'current' is bogus, or resolving to the
> >> > > wrong address somehow?
> >> >
> >> > It resolves the following line.
> >> >
> >> > p->signal->tty = tty_kref_get(current->signal->tty);
> >> >
> >> > I am not quite sure how 'current' should be resolved.
> >>
> >> Hm, on arm64 it looks like the value of 'current' is stored in the
> >> SP_EL0 register.  So I guess that shouldn't need any relocations.
> >>
> >> > The size of copy_process (0xfd58) is wrong. It is only about
> >> > 5.5kB in size. Also, the copy_process function in the .ko file
> >> > looks very broken. I will try a few more things.
> >
> > When I try each step of kpatch-build, the copy_process function
> > looks reasonable (according to gdb-disassemble) in fork.o and
> > output.o. However, copy_process looks weird in livepatch-special-static.o,
> > which is generated by ld:
> >
> > ld -EL  -maarch64linux -z norelro -z noexecstack
> > --no-warn-rwx-segments -T ././kpatch.lds  -r -o
> > livepatch-special-static.o ./patch-hook.o ./output.o
> >
> > I have attached these files to the email. I am not sure whether
> > the email server will let them through.
>
> I think, I am missing something here,
>
> I did :
>
> objdump -Dr livepatch-special-static.o | less
>
> and
>
> objdump -Dr output.o | less
>
> and the disassembly of copy_process() looks exactly same.

Yeah, objdump does show the same disassembly. However, if
I open the file with gdb, and do "disassemble copy_process",
the one in livepatch-special-static.o looks very weird.

Thanks,
Song
Song Liu Feb. 13, 2025, 7:42 p.m. UTC | #26
On Wed, Feb 12, 2025 at 11:53 PM Puranjay Mohan <puranjay@kernel.org> wrote:
>
> Song Liu <song@kernel.org> writes:
>
> > On Wed, Feb 12, 2025 at 11:26 PM Puranjay Mohan <puranjay@kernel.org> wrote:
> >>
> >> Song Liu <song@kernel.org> writes:
> >>
> >> > On Wed, Feb 12, 2025 at 4:10 PM Indu Bhagat <indu.bhagat@oracle.com> wrote:
> >> >>
> >> >> On 2/12/25 3:32 PM, Song Liu wrote:
> >> >> > I run some tests with this set and my RFC set [1]. Most of
> >> >> > the test is done with kpatch-build. I tested both Puranjay's
> >> >> > version [3] and my version [4].
> >> >> >
> >> >> > For gcc 14.2.1, I have seen the following issue with this
> >> >> > test [2]. This happens with both upstream and 6.13.2.
> >> >> > The livepatch loaded fine, but the system spilled out the
> >> >> > following warning quickly.
> >> >> >
> >> >>
> >> >> In presence of the issue
> >> >> https://sourceware.org/bugzilla/show_bug.cgi?id=32666, I'd expect bad
> >> >> data in SFrame section.  Which may be causing this symptom?
> >> >>
> >> >> To be clear, the issue affects loaded kernel modules.  I cannot tell for
> >> >> certain - is there module loading involved in your test ?
> >> >
> >> > The KLP is a module, I guess that is also affected?
> >> >
> >> > During kpatch-build, we added some logic to drop the .sframe section.
> >> > I guess this is wrong, as we need the .sframe section when we apply
> >> > the next KLP. However, I don't think the issue is caused by missing
> >> > .sframe section.
> >>
> >> Hi, I did the same testing and did not get the Warning.
> >>
> >> I am testing on the 6.12.11 kernel with GCC 11.4.1.
> >
> > Could you please also try kernel 6.13.2?
> >
> >> Just to verify, the patch we are testing is:
> >
> > Yes, this is the test patch.
> >>
> >> --- >8 ---
> > [...]
> >> --- 8< ---
> >>
> >> P.S. - I have a downstream patch for create-diff-object to generate .sframe sections for
> >> livepatch module, will add it to the PR after some cleanups.
> >
> > Yeah, I think the .sframe section is still needed.
> >
>
> Hi Song,
>
> Can you try with this:
> https://github.com/puranjaymohan/kpatch/tree/arm64_wip
>
> This has the .sframe logic patch, but it looks as if I wrote that code
> in a 30 minute leetcode interview. I need to refactor it before I send
> it for review with the main PR.
>
> Can you test with this branch with your setup?

This branch has the same issue as the other branch.

Song
Song Liu Feb. 13, 2025, 8:46 p.m. UTC | #27
On Thu, Feb 13, 2025 at 12:38 AM Puranjay Mohan <puranjay@kernel.org> wrote:
[...]
>
> P.S. - The livepatch doesn't have copy_process() but only copy_signal(),
> yours had copy_process() somehow.

In my build, copy_signal is inlined to copy_process, unless I add noinline.
If I do add noinline, the issue will not reproduce.

I tried more combinations. The issue doesn't reproduce if I either
1) add noinline to copy_signal, so we are not patching the whole
   copy_process function;
or
2) Switch compiler from gcc 14.2.1 to gcc 11.5.0.

So it appears something in gcc 14.2.1 is causing live patch to fail
for copy_process().

Thanks,
Song

[...]
Puranjay Mohan Feb. 13, 2025, 10:21 p.m. UTC | #28
Song Liu <song@kernel.org> writes:

> On Thu, Feb 13, 2025 at 12:38 AM Puranjay Mohan <puranjay@kernel.org> wrote:
> [...]
>>
>> P.S. - The livepatch doesn't have copy_process() but only copy_signal(),
>> yours had copy_process() somehow.
>
> In my build, copy_signal is inlined to copy_process, unless I add noinline.
> If I do add noinline, the issue will not reproduce.
>
> I tried more combinations. The issue doesn't reproduce if I either
> 1) add noinline to copy_signal, so we are not patching the whole
>    copy_process function;
> or
> 2) Switch compiler from gcc 14.2.1 to gcc 11.5.0.
>
> So it appears something in gcc 14.2.1 is causing live patch to fail
> for copy_process().

So, can you test your RFC set (without SFRAME) with gcc 14.2.1, so we
can be sure that it is not a sframe problem?

And about having the .sframe section in the livepatch module, I realised
that this set doesn't include support for reading/using sframe data from
any module(livepatches included), so the patch I added for generating
.sframe in kpatch is irrelevant because it is a no-op with the current setup.

Thanks,
Puranjay
Indu Bhagat Feb. 13, 2025, 11:22 p.m. UTC | #29
On 2/12/25 11:25 PM, Song Liu wrote:
> On Wed, Feb 12, 2025 at 6:45 PM Josh Poimboeuf <jpoimboe@kernel.org> wrote:
>>
>> On Wed, Feb 12, 2025 at 06:36:04PM -0800, Song Liu wrote:
>>>>> [   81.261748]  copy_process+0xfdc/0xfd58 [livepatch_special_static]
>>>>
>>>> Does that copy_process+0xfdc/0xfd58 resolve to this line in
>>>> copy_process()?
>>>>
>>>>                          refcount_inc(&current->signal->sigcnt);
>>>>
>>>> Maybe the klp rela reference to 'current' is bogus, or resolving to the
>>>> wrong address somehow?
>>>
>>> It resolves the following line.
>>>
>>> p->signal->tty = tty_kref_get(current->signal->tty);
>>>
>>> I am not quite sure how 'current' should be resolved.
>>
>> Hm, on arm64 it looks like the value of 'current' is stored in the
>> SP_EL0 register.  So I guess that shouldn't need any relocations.
>>
>>> The size of copy_process (0xfd58) is wrong. It is only about
>>> 5.5kB in size. Also, the copy_process function in the .ko file
>>> looks very broken. I will try a few more things.
> 
> When I try each step of kpatch-build, the copy_process function
> looks reasonable (according to gdb-disassemble) in fork.o and
> output.o. However, copy_process looks weird in livepatch-special-static.o,
> which is generated by ld:
> 
> ld -EL  -maarch64linux -z norelro -z noexecstack
> --no-warn-rwx-segments -T ././kpatch.lds  -r -o
> livepatch-special-static.o ./patch-hook.o ./output.o
> 
> I have attached these files to the email. I am not sure whether
> the email server will let them through.
> 
> Indu, does this look like an issue with ld?
> 

Sorry for the delay.

Looks like there has been progress since and issue may be elsewhere, but:

FWIW, I looked at the .sframe and .rela.sframe sections here, the data 
does look OK.  I noted that there is no .sframe for copy_process () in 
output.o... I will take a look into it.
Song Liu Feb. 13, 2025, 11:34 p.m. UTC | #30
On Thu, Feb 13, 2025 at 2:22 PM Puranjay Mohan <puranjay@kernel.org> wrote:
>
> Song Liu <song@kernel.org> writes:
>
> > On Thu, Feb 13, 2025 at 12:38 AM Puranjay Mohan <puranjay@kernel.org> wrote:
> > [...]
> >>
> >> P.S. - The livepatch doesn't have copy_process() but only copy_signal(),
> >> yours had copy_process() somehow.
> >
> > In my build, copy_signal is inlined to copy_process, unless I add noinline.
> > If I do add noinline, the issue will not reproduce.
> >
> > I tried more combinations. The issue doesn't reproduce if I either
> > 1) add noinline to copy_signal, so we are not patching the whole
> >    copy_process function;
> > or
> > 2) Switch compiler from gcc 14.2.1 to gcc 11.5.0.
> >
> > So it appears something in gcc 14.2.1 is causing live patch to fail
> > for copy_process().
>
> So, can you test your RFC set (without SFRAME) with gcc 14.2.1, so we
> can be sure that it is not a sframe problem?

My RFC set is the same. No issue with gcc 11.5.0; but hits the same
WARNING with gcc 14.2.1. My previous tests are all with clang. I didn't
see a similar issue there.

> And about having the .sframe section in the livepatch module, I realised
> that this set doesn't include support for reading/using sframe data from
> any module(livepatches included), so the patch I added for generating
> .sframe in kpatch is irrelevant because it is a no-op with the current setup.

Agreed, this issue should be irrelevant to the .sframe section in the .ko file.

Thanks,
Song
Song Liu Feb. 13, 2025, 11:47 p.m. UTC | #31
On Thu, Feb 13, 2025 at 3:23 PM Indu Bhagat <indu.bhagat@oracle.com> wrote:
>
> On 2/12/25 11:25 PM, Song Liu wrote:
> > On Wed, Feb 12, 2025 at 6:45 PM Josh Poimboeuf <jpoimboe@kernel.org> wrote:
> >>
> >> On Wed, Feb 12, 2025 at 06:36:04PM -0800, Song Liu wrote:
> >>>>> [   81.261748]  copy_process+0xfdc/0xfd58 [livepatch_special_static]
> >>>>
> >>>> Does that copy_process+0xfdc/0xfd58 resolve to this line in
> >>>> copy_process()?
> >>>>
> >>>>                          refcount_inc(&current->signal->sigcnt);
> >>>>
> >>>> Maybe the klp rela reference to 'current' is bogus, or resolving to the
> >>>> wrong address somehow?
> >>>
> >>> It resolves the following line.
> >>>
> >>> p->signal->tty = tty_kref_get(current->signal->tty);
> >>>
> >>> I am not quite sure how 'current' should be resolved.
> >>
> >> Hm, on arm64 it looks like the value of 'current' is stored in the
> >> SP_EL0 register.  So I guess that shouldn't need any relocations.
> >>
> >>> The size of copy_process (0xfd58) is wrong. It is only about
> >>> 5.5kB in size. Also, the copy_process function in the .ko file
> >>> looks very broken. I will try a few more things.
> >
> > When I try each step of kpatch-build, the copy_process function
> > looks reasonable (according to gdb-disassemble) in fork.o and
> > output.o. However, copy_process looks weird in livepatch-special-static.o,
> > which is generated by ld:
> >
> > ld -EL  -maarch64linux -z norelro -z noexecstack
> > --no-warn-rwx-segments -T ././kpatch.lds  -r -o
> > livepatch-special-static.o ./patch-hook.o ./output.o
> >
> > I have attached these files to the email. I am not sure whether
> > the email server will let them through.
> >
> > Indu, does this look like an issue with ld?
> >
>
> Sorry for the delay.
>
> Looks like there has been progress since and issue may be elsewhere, but:
>
> FWIW, I looked at the .sframe and .rela.sframe sections here, the data
> does look OK.  I noted that there is no .sframe for copy_process () in
> output.o... I will take a look into it.

That output.o was generated with a version of kpatch-build that blindly
removes all .sframe sections.

Thanks,
Song
Song Liu Feb. 14, 2025, 1:58 a.m. UTC | #32
On Thu, Feb 13, 2025 at 2:22 PM Puranjay Mohan <puranjay@kernel.org> wrote:
>
> Song Liu <song@kernel.org> writes:
>
> > On Thu, Feb 13, 2025 at 12:38 AM Puranjay Mohan <puranjay@kernel.org> wrote:
> > [...]
> >>
> >> P.S. - The livepatch doesn't have copy_process() but only copy_signal(),
> >> yours had copy_process() somehow.
> >
> > In my build, copy_signal is inlined to copy_process, unless I add noinline.
> > If I do add noinline, the issue will not reproduce.
> >
> > I tried more combinations. The issue doesn't reproduce if I either
> > 1) add noinline to copy_signal, so we are not patching the whole
> >    copy_process function;
> > or
> > 2) Switch compiler from gcc 14.2.1 to gcc 11.5.0.
> >
> > So it appears something in gcc 14.2.1 is causing live patch to fail
> > for copy_process().
>
> So, can you test your RFC set (without SFRAME) with gcc 14.2.1, so we
> can be sure that it is not a sframe problem?
>
> And about having the .sframe section in the livepatch module, I realised
> that this set doesn't include support for reading/using sframe data from
> any module(livepatches included), so the patch I added for generating
> .sframe in kpatch is irrelevant because it is a no-op with the current setup.

Puranjay,

Could you please try the following?

1. Use gcc 11.4.1;
2. Add __always_inline to copy_signal();
3. Build kernel, and livepatch with the same test (we need to
    add __always_inline to the .patch file).
4. Run gdb livepatch-xxx.ko
5. In gdb do disassemble copy_process.

In my tests, both gcc-14.2.1 and gcc-11.5.0 generated a .ko file
that looks weird in gdb-disassemble. Specifically, readels shows
copy_process is about 5.5kB, but gdb-disassemble only shows
140 bytes or so for copy_process. clang doesn't seem to have
this problem.

I am really curious whether you have the same problem in your
setup.

Thanks,
Song
Puranjay Mohan Feb. 14, 2025, 7:57 a.m. UTC | #33
Indu Bhagat <indu.bhagat@oracle.com> writes:

> On 2/12/25 11:25 PM, Song Liu wrote:
>> On Wed, Feb 12, 2025 at 6:45 PM Josh Poimboeuf <jpoimboe@kernel.org> wrote:
>>>
>>> On Wed, Feb 12, 2025 at 06:36:04PM -0800, Song Liu wrote:
>>>>>> [   81.261748]  copy_process+0xfdc/0xfd58 [livepatch_special_static]
>>>>>
>>>>> Does that copy_process+0xfdc/0xfd58 resolve to this line in
>>>>> copy_process()?
>>>>>
>>>>>                          refcount_inc(&current->signal->sigcnt);
>>>>>
>>>>> Maybe the klp rela reference to 'current' is bogus, or resolving to the
>>>>> wrong address somehow?
>>>>
>>>> It resolves the following line.
>>>>
>>>> p->signal->tty = tty_kref_get(current->signal->tty);
>>>>
>>>> I am not quite sure how 'current' should be resolved.
>>>
>>> Hm, on arm64 it looks like the value of 'current' is stored in the
>>> SP_EL0 register.  So I guess that shouldn't need any relocations.
>>>
>>>> The size of copy_process (0xfd58) is wrong. It is only about
>>>> 5.5kB in size. Also, the copy_process function in the .ko file
>>>> looks very broken. I will try a few more things.
>> 
>> When I try each step of kpatch-build, the copy_process function
>> looks reasonable (according to gdb-disassemble) in fork.o and
>> output.o. However, copy_process looks weird in livepatch-special-static.o,
>> which is generated by ld:
>> 
>> ld -EL  -maarch64linux -z norelro -z noexecstack
>> --no-warn-rwx-segments -T ././kpatch.lds  -r -o
>> livepatch-special-static.o ./patch-hook.o ./output.o
>> 
>> I have attached these files to the email. I am not sure whether
>> the email server will let them through.
>> 
>> Indu, does this look like an issue with ld?
>> 
>
> Sorry for the delay.
>
> Looks like there has been progress since and issue may be elsewhere, but:
>
> FWIW, I looked at the .sframe and .rela.sframe sections here, the data 
> does look OK.  I noted that there is no .sframe for copy_process () in 
> output.o... I will take a look into it.

Hi Indu,

I saw another issue in my kernel build with sframes enabled (-Wa,--gsframe):

ld: warning: orphan section `.init.sframe' from `arch/arm64/kernel/pi/lib-fdt.pi.o' being placed in section `.init.sframe'
[... Many more similar warnings (.init.sframe) ...]

So, this orphan sections is generated in the build process.

I am using GNU ld version 2.41-50 and gcc (GCC) 11.4.1

Is this section needed for sframes to work? or can we discard
.init.sframe section with a patch like following to the linker script:

-- 8< --

diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index 6a437bd08..8e704c0a6 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -1044,9 +1044,16 @@ defined(CONFIG_AUTOFDO_CLANG) || defined(CONFIG_PROPELLER_CLANG)
 # define SANITIZER_DISCARDS
 #endif

+#if defined(CONFIG_SFRAME_UNWIND_TABLE)
+#define DISCARD_INIT_SFRAME *(.init.sframe)
+#else
+#define DISCARD_INIT_SFRAME
+#endif
+
 #define COMMON_DISCARDS                                                        \
        SANITIZER_DISCARDS                                              \
        PATCHABLE_DISCARDS                                              \
+       DISCARD_INIT_SFRAME                                             \
        *(.discard)                                                     \
        *(.discard.*)                                                   \
        *(.export_symbol)                                               \

-- >8 --

Thanks,
Puranjay
Josh Poimboeuf Feb. 14, 2025, 8:08 a.m. UTC | #34
On Thu, Feb 13, 2025 at 11:40:43AM -0800, Song Liu wrote:
> Yeah, objdump does show the same disassembly. However, if
> I open the file with gdb, and do "disassemble copy_process",
> the one in livepatch-special-static.o looks very weird.

The symbol table looks ok.  I'm not sure why gdb is getting confused,
but that could possibly be a red herring.  Maybe it doesn't like the
-ffunction-sections for some reason.

It's really weird the function length reported by kallsyms is so wrong.
Can you share the .ko?

The refcount warning might indicate it's passing some bogus memory to
tty_kref_get().  Any chance you have struct randomization enabled?

Are you sure there's no code or .config mismatch between the built
kernel and the running kernel?

Ignorant arm64 question: is the module's text further away from slab
memory than vmlinux text, thus requiring a different instruction (or
GOT/TOC) to access memory further away in the address space?
Puranjay Mohan Feb. 14, 2025, 8:56 a.m. UTC | #35
Song Liu <song@kernel.org> writes:

> On Thu, Feb 13, 2025 at 2:22 PM Puranjay Mohan <puranjay@kernel.org> wrote:
>>
>> Song Liu <song@kernel.org> writes:
>>
>> > On Thu, Feb 13, 2025 at 12:38 AM Puranjay Mohan <puranjay@kernel.org> wrote:
>> > [...]
>> >>
>> >> P.S. - The livepatch doesn't have copy_process() but only copy_signal(),
>> >> yours had copy_process() somehow.
>> >
>> > In my build, copy_signal is inlined to copy_process, unless I add noinline.
>> > If I do add noinline, the issue will not reproduce.
>> >
>> > I tried more combinations. The issue doesn't reproduce if I either
>> > 1) add noinline to copy_signal, so we are not patching the whole
>> >    copy_process function;
>> > or
>> > 2) Switch compiler from gcc 14.2.1 to gcc 11.5.0.
>> >
>> > So it appears something in gcc 14.2.1 is causing live patch to fail
>> > for copy_process().
>>
>> So, can you test your RFC set (without SFRAME) with gcc 14.2.1, so we
>> can be sure that it is not a sframe problem?
>>
>> And about having the .sframe section in the livepatch module, I realised
>> that this set doesn't include support for reading/using sframe data from
>> any module(livepatches included), so the patch I added for generating
>> .sframe in kpatch is irrelevant because it is a no-op with the current setup.
>
> Puranjay,
>
> Could you please try the following?
>
> 1. Use gcc 11.4.1;
> 2. Add __always_inline to copy_signal();
> 3. Build kernel, and livepatch with the same test (we need to
>     add __always_inline to the .patch file).
> 4. Run gdb livepatch-xxx.ko
> 5. In gdb do disassemble copy_process.
>
> In my tests, both gcc-14.2.1 and gcc-11.5.0 generated a .ko file
> that looks weird in gdb-disassemble. Specifically, readels shows
> copy_process is about 5.5kB, but gdb-disassemble only shows
> 140 bytes or so for copy_process. clang doesn't seem to have
> this problem.
>
> I am really curious whether you have the same problem in your
> setup.

Hi Song,

I did this test and found the same issue as you (gdb assembly broken),
but I can see this issue even without the inlining. I think GDB tried to
load the debuginfo and that is somehow broken therefore it fails to
disassemblt properly.

But even with inlining, I couldn't see the warning about the refcount
with my setup.

Thanks,
Puranjay
Indu Bhagat Feb. 14, 2025, 5:39 p.m. UTC | #36
On 2/13/25 11:57 PM, Puranjay Mohan wrote:
> Indu Bhagat <indu.bhagat@oracle.com> writes:
> 
>> On 2/12/25 11:25 PM, Song Liu wrote:
>>> On Wed, Feb 12, 2025 at 6:45 PM Josh Poimboeuf <jpoimboe@kernel.org> wrote:
>>>>
>>>> On Wed, Feb 12, 2025 at 06:36:04PM -0800, Song Liu wrote:
>>>>>>> [   81.261748]  copy_process+0xfdc/0xfd58 [livepatch_special_static]
>>>>>>
>>>>>> Does that copy_process+0xfdc/0xfd58 resolve to this line in
>>>>>> copy_process()?
>>>>>>
>>>>>>                           refcount_inc(&current->signal->sigcnt);
>>>>>>
>>>>>> Maybe the klp rela reference to 'current' is bogus, or resolving to the
>>>>>> wrong address somehow?
>>>>>
>>>>> It resolves the following line.
>>>>>
>>>>> p->signal->tty = tty_kref_get(current->signal->tty);
>>>>>
>>>>> I am not quite sure how 'current' should be resolved.
>>>>
>>>> Hm, on arm64 it looks like the value of 'current' is stored in the
>>>> SP_EL0 register.  So I guess that shouldn't need any relocations.
>>>>
>>>>> The size of copy_process (0xfd58) is wrong. It is only about
>>>>> 5.5kB in size. Also, the copy_process function in the .ko file
>>>>> looks very broken. I will try a few more things.
>>>
>>> When I try each step of kpatch-build, the copy_process function
>>> looks reasonable (according to gdb-disassemble) in fork.o and
>>> output.o. However, copy_process looks weird in livepatch-special-static.o,
>>> which is generated by ld:
>>>
>>> ld -EL  -maarch64linux -z norelro -z noexecstack
>>> --no-warn-rwx-segments -T ././kpatch.lds  -r -o
>>> livepatch-special-static.o ./patch-hook.o ./output.o
>>>
>>> I have attached these files to the email. I am not sure whether
>>> the email server will let them through.
>>>
>>> Indu, does this look like an issue with ld?
>>>
>>
>> Sorry for the delay.
>>
>> Looks like there has been progress since and issue may be elsewhere, but:
>>
>> FWIW, I looked at the .sframe and .rela.sframe sections here, the data
>> does look OK.  I noted that there is no .sframe for copy_process () in
>> output.o... I will take a look into it.
> 
> Hi Indu,
> 
> I saw another issue in my kernel build with sframes enabled (-Wa,--gsframe):
> 
> ld: warning: orphan section `.init.sframe' from `arch/arm64/kernel/pi/lib-fdt.pi.o' being placed in section `.init.sframe'
> [... Many more similar warnings (.init.sframe) ...]
> 
> So, this orphan sections is generated in the build process.
> 
> I am using GNU ld version 2.41-50 and gcc (GCC) 11.4.1
> 
> Is this section needed for sframes to work? or can we discard

No this should not be discarded.  This looks like a wrongly-named but 
valid SFrame section.

Once correctly named as .sframe, the linker should do the right thing. 
Let me check whats going on..

> .init.sframe section with a patch like following to the linker script:
> 
> -- 8< --
> 
> diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
> index 6a437bd08..8e704c0a6 100644
> --- a/include/asm-generic/vmlinux.lds.h
> +++ b/include/asm-generic/vmlinux.lds.h
> @@ -1044,9 +1044,16 @@ defined(CONFIG_AUTOFDO_CLANG) || defined(CONFIG_PROPELLER_CLANG)
>   # define SANITIZER_DISCARDS
>   #endif
> 
> +#if defined(CONFIG_SFRAME_UNWIND_TABLE)
> +#define DISCARD_INIT_SFRAME *(.init.sframe)
> +#else
> +#define DISCARD_INIT_SFRAME
> +#endif
> +
>   #define COMMON_DISCARDS                                                        \
>          SANITIZER_DISCARDS                                              \
>          PATCHABLE_DISCARDS                                              \
> +       DISCARD_INIT_SFRAME                                             \
>          *(.discard)                                                     \
>          *(.discard.*)                                                   \
>          *(.export_symbol)                                               \
> 
> -- >8 --
> 
> Thanks,
> Puranjay
Song Liu Feb. 14, 2025, 6:10 p.m. UTC | #37
Hi Puranjay,

Thanks for running the tests.

On Fri, Feb 14, 2025 at 12:56 AM Puranjay Mohan <puranjay@kernel.org> wrote:
[...]
> >
> > I am really curious whether you have the same problem in your
> > setup.
>
> Hi Song,
>
> I did this test and found the same issue as you (gdb assembly broken),
> but I can see this issue even without the inlining. I think GDB tried to
> load the debuginfo and that is somehow broken therefore it fails to
> disassemblt properly.

Yes, this matches my observations: gcc-11 generates the .ko that
confuses gdb.

I tested with two versions of gdb (10.2 and 14.2), both have the
problem. OTOH, lldb is able to disassemble copy_process from a
gcc-compiled .ko file properly.

> But even with inlining, I couldn't see the warning about the refcount
> with my setup.

This also matches my observations. gcc-11 compiled livepatch
works fine.

Thanks,
Song
Josh Poimboeuf Feb. 14, 2025, 6:24 p.m. UTC | #38
On Fri, Feb 14, 2025 at 08:56:45AM +0000, Puranjay Mohan wrote:
> I did this test and found the same issue as you (gdb assembly broken),
> but I can see this issue even without the inlining. I think GDB tried to
> load the debuginfo and that is somehow broken therefore it fails to
> disassemblt properly.

I had the same theory about the debuginfo, but I stripped debug sections
from that file and gdb still got confused.

Still, the symbol table looked normal, so the gdb issue might be
completely separate from the kernel runtime issues.
Indu Bhagat Feb. 14, 2025, 6:41 p.m. UTC | #39
On 2/14/25 9:39 AM, Indu Bhagat wrote:
> On 2/13/25 11:57 PM, Puranjay Mohan wrote:
>> Indu Bhagat <indu.bhagat@oracle.com> writes:
>>
>>> On 2/12/25 11:25 PM, Song Liu wrote:
>>>> On Wed, Feb 12, 2025 at 6:45 PM Josh Poimboeuf <jpoimboe@kernel.org> 
>>>> wrote:
>>>>>
>>>>> On Wed, Feb 12, 2025 at 06:36:04PM -0800, Song Liu wrote:
>>>>>>>> [   81.261748]  copy_process+0xfdc/0xfd58 
>>>>>>>> [livepatch_special_static]
>>>>>>>
>>>>>>> Does that copy_process+0xfdc/0xfd58 resolve to this line in
>>>>>>> copy_process()?
>>>>>>>
>>>>>>>                           refcount_inc(&current->signal->sigcnt);
>>>>>>>
>>>>>>> Maybe the klp rela reference to 'current' is bogus, or resolving 
>>>>>>> to the
>>>>>>> wrong address somehow?
>>>>>>
>>>>>> It resolves the following line.
>>>>>>
>>>>>> p->signal->tty = tty_kref_get(current->signal->tty);
>>>>>>
>>>>>> I am not quite sure how 'current' should be resolved.
>>>>>
>>>>> Hm, on arm64 it looks like the value of 'current' is stored in the
>>>>> SP_EL0 register.  So I guess that shouldn't need any relocations.
>>>>>
>>>>>> The size of copy_process (0xfd58) is wrong. It is only about
>>>>>> 5.5kB in size. Also, the copy_process function in the .ko file
>>>>>> looks very broken. I will try a few more things.
>>>>
>>>> When I try each step of kpatch-build, the copy_process function
>>>> looks reasonable (according to gdb-disassemble) in fork.o and
>>>> output.o. However, copy_process looks weird in livepatch-special- 
>>>> static.o,
>>>> which is generated by ld:
>>>>
>>>> ld -EL  -maarch64linux -z norelro -z noexecstack
>>>> --no-warn-rwx-segments -T ././kpatch.lds  -r -o
>>>> livepatch-special-static.o ./patch-hook.o ./output.o
>>>>
>>>> I have attached these files to the email. I am not sure whether
>>>> the email server will let them through.
>>>>
>>>> Indu, does this look like an issue with ld?
>>>>
>>>
>>> Sorry for the delay.
>>>
>>> Looks like there has been progress since and issue may be elsewhere, 
>>> but:
>>>
>>> FWIW, I looked at the .sframe and .rela.sframe sections here, the data
>>> does look OK.  I noted that there is no .sframe for copy_process () in
>>> output.o... I will take a look into it.
>>
>> Hi Indu,
>>
>> I saw another issue in my kernel build with sframes enabled (-Wa,-- 
>> gsframe):
>>
>> ld: warning: orphan section `.init.sframe' from `arch/arm64/kernel/pi/ 
>> lib-fdt.pi.o' being placed in section `.init.sframe'
>> [... Many more similar warnings (.init.sframe) ...]
>>
>> So, this orphan sections is generated in the build process.
>>
>> I am using GNU ld version 2.41-50 and gcc (GCC) 11.4.1
>>
>> Is this section needed for sframes to work? or can we discard
> 
> No this should not be discarded.  This looks like a wrongly-named but 
> valid SFrame section.
> 

Not wrongly named. --prefix-alloc-sections=.init is expected to do that 
as .sframe is an allocated section.

> Once correctly named as .sframe, the linker should do the right thing. 
> Let me check whats going on..
> 
>> .init.sframe section with a patch like following to the linker script:
>>
>> -- 8< --
>>
>> diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/ 
>> vmlinux.lds.h
>> index 6a437bd08..8e704c0a6 100644
>> --- a/include/asm-generic/vmlinux.lds.h
>> +++ b/include/asm-generic/vmlinux.lds.h
>> @@ -1044,9 +1044,16 @@ defined(CONFIG_AUTOFDO_CLANG) || 
>> defined(CONFIG_PROPELLER_CLANG)
>>   # define SANITIZER_DISCARDS
>>   #endif
>>
>> +#if defined(CONFIG_SFRAME_UNWIND_TABLE)
>> +#define DISCARD_INIT_SFRAME *(.init.sframe)
>> +#else
>> +#define DISCARD_INIT_SFRAME
>> +#endif
>> +
>>   #define 
>> COMMON_DISCARDS                                                        \
>>          
>> SANITIZER_DISCARDS                                              \
>>          
>> PATCHABLE_DISCARDS                                              \
>> +       DISCARD_INIT_SFRAME                                             \
>>          
>> *(.discard)                                                     \
>>          
>> *(.discard.*)                                                   \
>>          
>> *(.export_symbol)                                               \
>>
>> -- >8 --
>>
>> Thanks,
>> Puranjay
>
Puranjay Mohan Feb. 14, 2025, 6:58 p.m. UTC | #40
Indu Bhagat <indu.bhagat@oracle.com> writes:

> On 2/14/25 9:39 AM, Indu Bhagat wrote:
>> On 2/13/25 11:57 PM, Puranjay Mohan wrote:
>>> Indu Bhagat <indu.bhagat@oracle.com> writes:
>>>
>>>> On 2/12/25 11:25 PM, Song Liu wrote:
>>>>> On Wed, Feb 12, 2025 at 6:45 PM Josh Poimboeuf <jpoimboe@kernel.org> 
>>>>> wrote:
>>>>>>
>>>>>> On Wed, Feb 12, 2025 at 06:36:04PM -0800, Song Liu wrote:
>>>>>>>>> [   81.261748]  copy_process+0xfdc/0xfd58 
>>>>>>>>> [livepatch_special_static]
>>>>>>>>
>>>>>>>> Does that copy_process+0xfdc/0xfd58 resolve to this line in
>>>>>>>> copy_process()?
>>>>>>>>
>>>>>>>>                           refcount_inc(&current->signal->sigcnt);
>>>>>>>>
>>>>>>>> Maybe the klp rela reference to 'current' is bogus, or resolving 
>>>>>>>> to the
>>>>>>>> wrong address somehow?
>>>>>>>
>>>>>>> It resolves the following line.
>>>>>>>
>>>>>>> p->signal->tty = tty_kref_get(current->signal->tty);
>>>>>>>
>>>>>>> I am not quite sure how 'current' should be resolved.
>>>>>>
>>>>>> Hm, on arm64 it looks like the value of 'current' is stored in the
>>>>>> SP_EL0 register.  So I guess that shouldn't need any relocations.
>>>>>>
>>>>>>> The size of copy_process (0xfd58) is wrong. It is only about
>>>>>>> 5.5kB in size. Also, the copy_process function in the .ko file
>>>>>>> looks very broken. I will try a few more things.
>>>>>
>>>>> When I try each step of kpatch-build, the copy_process function
>>>>> looks reasonable (according to gdb-disassemble) in fork.o and
>>>>> output.o. However, copy_process looks weird in livepatch-special- 
>>>>> static.o,
>>>>> which is generated by ld:
>>>>>
>>>>> ld -EL  -maarch64linux -z norelro -z noexecstack
>>>>> --no-warn-rwx-segments -T ././kpatch.lds  -r -o
>>>>> livepatch-special-static.o ./patch-hook.o ./output.o
>>>>>
>>>>> I have attached these files to the email. I am not sure whether
>>>>> the email server will let them through.
>>>>>
>>>>> Indu, does this look like an issue with ld?
>>>>>
>>>>
>>>> Sorry for the delay.
>>>>
>>>> Looks like there has been progress since and issue may be elsewhere, 
>>>> but:
>>>>
>>>> FWIW, I looked at the .sframe and .rela.sframe sections here, the data
>>>> does look OK.  I noted that there is no .sframe for copy_process () in
>>>> output.o... I will take a look into it.
>>>
>>> Hi Indu,
>>>
>>> I saw another issue in my kernel build with sframes enabled (-Wa,-- 
>>> gsframe):
>>>
>>> ld: warning: orphan section `.init.sframe' from `arch/arm64/kernel/pi/ 
>>> lib-fdt.pi.o' being placed in section `.init.sframe'
>>> [... Many more similar warnings (.init.sframe) ...]
>>>
>>> So, this orphan sections is generated in the build process.
>>>
>>> I am using GNU ld version 2.41-50 and gcc (GCC) 11.4.1
>>>
>>> Is this section needed for sframes to work? or can we discard
>> 
>> No this should not be discarded.  This looks like a wrongly-named but 
>> valid SFrame section.
>> 
>
> Not wrongly named. --prefix-alloc-sections=.init is expected to do that 
> as .sframe is an allocated section.
>

So, these .init.sframe sections are then moved into .sframe by the
linker? (see linker script line below)

Here are some outputs from the build, do they look correct?

One of the objects that were emitting the warning
[ec2-user@ip-172-31-32-86 linux-upstream]$ readelf -SW arch/arm64/kernel/pi/lib-fdt.pi.o | grep sframe
  [47] .init.sframe      PROGBITS        0000000000000000 003c90 000226 00   A  0   0  8
  [48] .rela.init.sframe RELA            0000000000000000 008f08 000180 18   I 51  47  8

Final vmlinux ELF
[ec2-user@ip-172-31-32-86 linux-upstream]$ readelf -SW vmlinux | grep sframe
  [ 5] .init.sframe      PROGBITS        ffff80008118c298 119c298 002a88 00   A  0   0  8
  [ 6] .sframe           PROGBITS        ffff80008118ed20 119ed20 247c45 00   A  0   0  8

[ec2-user@ip-172-31-32-86 linux-upstream]$ readelf --sframe=.sframe vmlinux | head
Contents of the SFrame section .sframe:
  Header :

    Version: SFRAME_VERSION_2
    Flags: SFRAME_F_FDE_SORTED
    Num FDEs: 51842
    Num FREs: 321245

  Function Index :

Does this also look correct?
[ec2-user@ip-172-31-32-86 linux-upstream]$ readelf --sframe=.init.sframe vmlinux | head
Contents of the SFrame section .init.sframe:
  Header :

    Version: SFRAME_VERSION_2
    Flags: NONE
    Num FDEs: 16
    Num FREs: 50

  Function Index :


and the linker script has this line:

.sframe : AT(ADDR(.sframe) - 0) { __start_sframe_header = .; KEEP(*(.sframe)) __stop_sframe_header = .; }

So, do can you suggest the best way to fix these warnings?

Thanks,
Puranjay
Josh Poimboeuf Feb. 14, 2025, 7:34 p.m. UTC | #41
On Fri, Feb 14, 2025 at 09:51:41AM -0800, Song Liu wrote:
> > Ignorant arm64 question: is the module's text further away from slab
> > memory than vmlinux text, thus requiring a different instruction (or
> > GOT/TOC) to access memory further away in the address space?
> 
> It appears to me the module text is very close to vmlinux text:
> 
> vmlinux: ffff8000800b4b68 T copy_process
> module: ffff80007b0f06d0 t copy_process [livepatch_always_inline_special_static]

Hm... the only other thing I can think of is that the klp relas might be
wrong somewhere.  If you share patched.o and .ko files from the same
build I could take a look.

BTW, I realized the wrong function size shown in the WARNING stack trace
is probably just due to a kallsyms quirk.  It calculates a symbol's size
by subtracting its start address from the next symbol's start address.
It doesn't actually use the ELF symbol size.  So the next symbol after
copy_process() in the loaded module's address space might just be far
away.

That kallsyms issue has caused other headaches.  It really needs to be
fixed to use the actual ELF symbol size.
Josh Poimboeuf Feb. 14, 2025, 7:38 p.m. UTC | #42
On Fri, Feb 14, 2025 at 06:58:01PM +0000, Puranjay Mohan wrote:
> and the linker script has this line:
> 
> .sframe : AT(ADDR(.sframe) - 0) { __start_sframe_header = .; KEEP(*(.sframe)) __stop_sframe_header = .; }
> 
> So, do can you suggest the best way to fix these warnings?

Just add *(.init.sframe) like so:

.sframe : AT(ADDR(.sframe) - 0) { __start_sframe_header = .; KEEP(*(.sframe) *(.init.sframe)) __stop_sframe_header = .; }
Josh Poimboeuf Feb. 14, 2025, 7:42 p.m. UTC | #43
On Fri, Feb 14, 2025 at 11:38:22AM -0800, Josh Poimboeuf wrote:
> On Fri, Feb 14, 2025 at 06:58:01PM +0000, Puranjay Mohan wrote:
> > and the linker script has this line:
> > 
> > .sframe : AT(ADDR(.sframe) - 0) { __start_sframe_header = .; KEEP(*(.sframe)) __stop_sframe_header = .; }
> > 
> > So, do can you suggest the best way to fix these warnings?
> 
> Just add *(.init.sframe) like so:
> 
> .sframe : AT(ADDR(.sframe) - 0) { __start_sframe_header = .; KEEP(*(.sframe) *(.init.sframe)) __stop_sframe_header = .; }

Actually each probably needs its own KEEP:

...  KEEP(*(.sframe)) KEEP(*(.init.sframe)) ...

or so.
Song Liu Feb. 14, 2025, 10:04 p.m. UTC | #44
Hi Josh,

On Fri, Feb 14, 2025 at 11:34 AM Josh Poimboeuf <jpoimboe@kernel.org> wrote:
>
> On Fri, Feb 14, 2025 at 09:51:41AM -0800, Song Liu wrote:
> > > Ignorant arm64 question: is the module's text further away from slab
> > > memory than vmlinux text, thus requiring a different instruction (or
> > > GOT/TOC) to access memory further away in the address space?
> >
> > It appears to me the module text is very close to vmlinux text:
> >
> > vmlinux: ffff8000800b4b68 T copy_process
> > module: ffff80007b0f06d0 t copy_process [livepatch_always_inline_special_static]
>
> Hm... the only other thing I can think of is that the klp relas might be
> wrong somewhere.  If you share patched.o and .ko files from the same
> build I could take a look.

A tarball with these files is available here:

https://drive.google.com/file/d/1ONB1tC9oK-Z5ShmSXneqWLTjJgC5Xq-C/view?usp=drive_link

> BTW, I realized the wrong function size shown in the WARNING stack trace
> is probably just due to a kallsyms quirk.  It calculates a symbol's size
> by subtracting its start address from the next symbol's start address.
> It doesn't actually use the ELF symbol size.  So the next symbol after
> copy_process() in the loaded module's address space might just be far
> away.

Yeah, I also think kallsyms logic was the issue here. So it is not the same
as the gdb-disassembly issue.

> That kallsyms issue has caused other headaches.  It really needs to be
> fixed to use the actual ELF symbol size.

Maybe we should have a "module_text_end" symbol?

Thanks,
Song
Josh Poimboeuf Feb. 14, 2025, 10:33 p.m. UTC | #45
On Fri, Feb 14, 2025 at 02:04:17PM -0800, Song Liu wrote:
> Hi Josh,
> 
> On Fri, Feb 14, 2025 at 11:34 AM Josh Poimboeuf <jpoimboe@kernel.org> wrote:
> >
> > On Fri, Feb 14, 2025 at 09:51:41AM -0800, Song Liu wrote:
> > > > Ignorant arm64 question: is the module's text further away from slab
> > > > memory than vmlinux text, thus requiring a different instruction (or
> > > > GOT/TOC) to access memory further away in the address space?
> > >
> > > It appears to me the module text is very close to vmlinux text:
> > >
> > > vmlinux: ffff8000800b4b68 T copy_process
> > > module: ffff80007b0f06d0 t copy_process [livepatch_always_inline_special_static]
> >
> > Hm... the only other thing I can think of is that the klp relas might be
> > wrong somewhere.  If you share patched.o and .ko files from the same
> > build I could take a look.
> 
> A tarball with these files is available here:
> 
> https://drive.google.com/file/d/1ONB1tC9oK-Z5ShmSXneqWLTjJgC5Xq-C/view?usp=drive_link

Thanks, I'll take a look.

> > That kallsyms issue has caused other headaches.  It really needs to be
> > fixed to use the actual ELF symbol size.
> 
> Maybe we should have a "module_text_end" symbol?

Maybe, though it would be a lot cleaner for kallsyms to just use the
actual ELF sizes.  And actually I'm thinking that would be a pretty
trivial change.
Josh Poimboeuf Feb. 14, 2025, 11:23 p.m. UTC | #46
On Fri, Feb 14, 2025 at 02:04:17PM -0800, Song Liu wrote:
> Hi Josh,
> 
> On Fri, Feb 14, 2025 at 11:34 AM Josh Poimboeuf <jpoimboe@kernel.org> wrote:
> >
> > On Fri, Feb 14, 2025 at 09:51:41AM -0800, Song Liu wrote:
> > > > Ignorant arm64 question: is the module's text further away from slab
> > > > memory than vmlinux text, thus requiring a different instruction (or
> > > > GOT/TOC) to access memory further away in the address space?
> > >
> > > It appears to me the module text is very close to vmlinux text:
> > >
> > > vmlinux: ffff8000800b4b68 T copy_process
> > > module: ffff80007b0f06d0 t copy_process [livepatch_always_inline_special_static]
> >
> > Hm... the only other thing I can think of is that the klp relas might be
> > wrong somewhere.  If you share patched.o and .ko files from the same
> > build I could take a look.
> 
> A tarball with these files is available here:
> 
> https://drive.google.com/file/d/1ONB1tC9oK-Z5ShmSXneqWLTjJgC5Xq-C/view?usp=drive_link

Poking around the arm64 module code, arch/arm64/kernel/module-plts.c
is looking at all the relocations in order to set up the PLT.  That also
needs to be done for klp relas, or are your patches already doing that?
Song Liu Feb. 18, 2025, 4:38 a.m. UTC | #47
On Fri, Feb 14, 2025 at 3:23 PM Josh Poimboeuf <jpoimboe@kernel.org> wrote:
>
> On Fri, Feb 14, 2025 at 02:04:17PM -0800, Song Liu wrote:
> > Hi Josh,
> >
> > On Fri, Feb 14, 2025 at 11:34 AM Josh Poimboeuf <jpoimboe@kernel.org> wrote:
> > >
> > > On Fri, Feb 14, 2025 at 09:51:41AM -0800, Song Liu wrote:
> > > > > Ignorant arm64 question: is the module's text further away from slab
> > > > > memory than vmlinux text, thus requiring a different instruction (or
> > > > > GOT/TOC) to access memory further away in the address space?
> > > >
> > > > It appears to me the module text is very close to vmlinux text:
> > > >
> > > > vmlinux: ffff8000800b4b68 T copy_process
> > > > module: ffff80007b0f06d0 t copy_process [livepatch_always_inline_special_static]
> > >
> > > Hm... the only other thing I can think of is that the klp relas might be
> > > wrong somewhere.  If you share patched.o and .ko files from the same
> > > build I could take a look.
> >
> > A tarball with these files is available here:
> >
> > https://drive.google.com/file/d/1ONB1tC9oK-Z5ShmSXneqWLTjJgC5Xq-C/view?usp=drive_link
>
> Poking around the arm64 module code, arch/arm64/kernel/module-plts.c
> is looking at all the relocations in order to set up the PLT.  That also
> needs to be done for klp relas, or are your patches already doing that?

I don't think either version (this set and my RFC) added logic for PLT.
There is some rela logic on the kpatch-build side. But I am not sure
whether it is sufficient.

Thanks,
Song
Josh Poimboeuf Feb. 18, 2025, 6:37 a.m. UTC | #48
On Mon, Feb 17, 2025 at 08:38:22PM -0800, Song Liu wrote:
> On Fri, Feb 14, 2025 at 3:23 PM Josh Poimboeuf <jpoimboe@kernel.org> wrote:
> > Poking around the arm64 module code, arch/arm64/kernel/module-plts.c
> > is looking at all the relocations in order to set up the PLT.  That also
> > needs to be done for klp relas, or are your patches already doing that?
> 
> I don't think either version (this set and my RFC) added logic for PLT.
> There is some rela logic on the kpatch-build side. But I am not sure
> whether it is sufficient.

The klp relas looked ok.  I didn't see any signs of kpatch-build doing
anything wrong.  AFAICT the problem is that module-plts.c creates PLT
entries for regular relas but not klp relas.
Song Liu Feb. 18, 2025, 6:20 p.m. UTC | #49
Hi Josh,

On Mon, Feb 17, 2025 at 10:37 PM Josh Poimboeuf <jpoimboe@kernel.org> wrote:
>
> On Mon, Feb 17, 2025 at 08:38:22PM -0800, Song Liu wrote:
> > On Fri, Feb 14, 2025 at 3:23 PM Josh Poimboeuf <jpoimboe@kernel.org> wrote:
> > > Poking around the arm64 module code, arch/arm64/kernel/module-plts.c
> > > is looking at all the relocations in order to set up the PLT.  That also
> > > needs to be done for klp relas, or are your patches already doing that?
> >
> > I don't think either version (this set and my RFC) added logic for PLT.
> > There is some rela logic on the kpatch-build side. But I am not sure
> > whether it is sufficient.
>
> The klp relas looked ok.  I didn't see any signs of kpatch-build doing
> anything wrong.  AFAICT the problem is that module-plts.c creates PLT
> entries for regular relas but not klp relas.

In my tests (with printk) module-plts.c processes the .
klp.rela.vmlinux..text.copy_process section just like any other .rela.*
sections. Do we need special handling of the klp.rela.* sections?

Thanks,
Song
Josh Poimboeuf Feb. 18, 2025, 6:40 p.m. UTC | #50
On Tue, Feb 18, 2025 at 10:20:10AM -0800, Song Liu wrote:
> Hi Josh,
> 
> On Mon, Feb 17, 2025 at 10:37 PM Josh Poimboeuf <jpoimboe@kernel.org> wrote:
> >
> > On Mon, Feb 17, 2025 at 08:38:22PM -0800, Song Liu wrote:
> > > On Fri, Feb 14, 2025 at 3:23 PM Josh Poimboeuf <jpoimboe@kernel.org> wrote:
> > > > Poking around the arm64 module code, arch/arm64/kernel/module-plts.c
> > > > is looking at all the relocations in order to set up the PLT.  That also
> > > > needs to be done for klp relas, or are your patches already doing that?
> > >
> > > I don't think either version (this set and my RFC) added logic for PLT.
> > > There is some rela logic on the kpatch-build side. But I am not sure
> > > whether it is sufficient.
> >
> > The klp relas looked ok.  I didn't see any signs of kpatch-build doing
> > anything wrong.  AFAICT the problem is that module-plts.c creates PLT
> > entries for regular relas but not klp relas.
> 
> In my tests (with printk) module-plts.c processes the .
> klp.rela.vmlinux..text.copy_process section just like any other .rela.*
> sections. Do we need special handling of the klp.rela.* sections?

Ok, I see how it works now:

klp_write_section_relocs()
	apply_relocate_add()
		module_emit_plt_entry()
  
If that code is working correctly then I'm fresh out of ideas...
Song Liu Feb. 19, 2025, 5:44 p.m. UTC | #51
On Tue, Feb 18, 2025 at 10:41 AM Josh Poimboeuf <jpoimboe@kernel.org> wrote:
>
> On Tue, Feb 18, 2025 at 10:20:10AM -0800, Song Liu wrote:
> > Hi Josh,
> >
> > On Mon, Feb 17, 2025 at 10:37 PM Josh Poimboeuf <jpoimboe@kernel.org> wrote:
> > >
> > > On Mon, Feb 17, 2025 at 08:38:22PM -0800, Song Liu wrote:
> > > > On Fri, Feb 14, 2025 at 3:23 PM Josh Poimboeuf <jpoimboe@kernel.org> wrote:
> > > > > Poking around the arm64 module code, arch/arm64/kernel/module-plts.c
> > > > > is looking at all the relocations in order to set up the PLT.  That also
> > > > > needs to be done for klp relas, or are your patches already doing that?
> > > >
> > > > I don't think either version (this set and my RFC) added logic for PLT.
> > > > There is some rela logic on the kpatch-build side. But I am not sure
> > > > whether it is sufficient.
> > >
> > > The klp relas looked ok.  I didn't see any signs of kpatch-build doing
> > > anything wrong.  AFAICT the problem is that module-plts.c creates PLT
> > > entries for regular relas but not klp relas.
> >
> > In my tests (with printk) module-plts.c processes the .
> > klp.rela.vmlinux..text.copy_process section just like any other .rela.*
> > sections. Do we need special handling of the klp.rela.* sections?
>
> Ok, I see how it works now:
>
> klp_write_section_relocs()
>         apply_relocate_add()
>                 module_emit_plt_entry()
>
> If that code is working correctly then I'm fresh out of ideas...

I tried to dump assembly of copy_process, but couldn't find any
clue. I am wondering whether this is an issue with gcc-14.2.1.

Puranjay, could you please try with a different gcc, like some
version of gcc-14?

Thanks,
Song
Josh Poimboeuf Feb. 20, 2025, 6:22 p.m. UTC | #52
On Wed, Feb 19, 2025 at 08:50:09PM -0800, Song Liu wrote:
> Indu, is this behavior (symbols with same name are not in
> sorted order from readelf -s) expected? Or is this a bug?
> I am using this gcc:
> 
> $ gcc --version
> gcc (GCC) 14.2.1 20240801 (Red Hat 14.2.1-1)
> Copyright (C) 2024 Free Software Foundation, Inc.
> This is free software; see the source for copying conditions.  There is NO
> warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

Are you using different binutils versions as well?

It sounds like a linker "issue" to me.  I'm not sure if it qualifies as
a bug, the linker might be free to layout symbols how it wishes.
Song Liu Feb. 25, 2025, 12:13 a.m. UTC | #53
On Thu, Feb 20, 2025 at 10:33 AM Song Liu <song@kernel.org> wrote:
>
>
> On Thu, Feb 20, 2025 at 10:22 AM Josh Poimboeuf <jpoimboe@kernel.org> wrote:
>>
>> On Wed, Feb 19, 2025 at 08:50:09PM -0800, Song Liu wrote:
>> > Indu, is this behavior (symbols with same name are not in
>> > sorted order from readelf -s) expected? Or is this a bug?
>> > I am using this gcc:
>> >
>> > $ gcc --version
>> > gcc (GCC) 14.2.1 20240801 (Red Hat 14.2.1-1)
>> > Copyright (C) 2024 Free Software Foundation, Inc.
>> > This is free software; see the source for copying conditions.  There is NO
>> > warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
>>
>> Are you using different binutils versions as well?
>
>
> I am using binutil 2.41, for both gcc -11 and gcc-14.
>
>>
>> It sounds like a linker "issue" to me.  I'm not sure if it qualifies as
>> a bug, the linker might be free to layout symbols how it wishes.
>
>
> We can probably handle that in kpatch-build.

OK, something like the following gets the proper sympos for
gcc-14 built kernel.

Thanks,
Song


diff --git i/kpatch-build/lookup.c w/kpatch-build/lookup.c
index bd2b732de910..87ac127184c5 100644
--- i/kpatch-build/lookup.c
+++ w/kpatch-build/lookup.c
@@ -479,13 +479,10 @@ static bool lookup_local_symbol(struct
lookup_table *table,
        struct object_symbol *sym;
        unsigned long sympos = 0;
        int i, in_file = 0;
+       bool found = false;

        memset(result, 0, sizeof(*result));
        for_each_obj_symbol(i, sym, table) {
-               if (sym->bind == STB_LOCAL && !strcmp(sym->name,
-                                       lookup_sym->name))
-                       sympos++;
-
                if (lookup_sym->lookup_table_file_sym == sym) {
                        in_file = 1;
                        continue;
@@ -499,20 +496,29 @@ static bool lookup_local_symbol(struct
lookup_table *table,

                if (sym->bind == STB_LOCAL && !strcmp(sym->name,
                                        lookup_sym->name)) {
-                       if (result->objname)
+                       if (found)
                                ERROR("duplicate local symbol found for %s",
                                                lookup_sym->name);

                        result->objname         = table->objname;
                        result->addr            = sym->addr;
                        result->size            = sym->size;
-                       result->sympos          = sympos;
                        result->global          = false;
                        result->exported        = false;
+                       found = true;
                }
        }
+       if (!found)
+               return false;

-       return !!result->objname;
+       for_each_obj_symbol(i, sym, table) {
+               if (sym->bind == STB_LOCAL &&
+                   !strcmp(sym->name, lookup_sym->name) &&
+                   sym->addr < result->addr)
+                       sympos++;
+       }
+       result->sympos = sympos;
+       return true;
 }

 static bool lookup_exported_symbol(struct lookup_table *table, char *name,
Weinan Liu Feb. 25, 2025, 1:02 a.m. UTC | #54
On Mon, Feb 10, 2025 at 12:30 AM Weinan Liu <wnliu@google.com> wrote:
> I already have a WIP patch to add sframe support to the kernel module.
> However, it is not yet working. I had trouble unwinding frames for the
> kernel module using the current algorithm.
>
> Indu has likely identified the issue and will be addressing it from the
> toolchain side.
>
> https://sourceware.org/bugzilla/show_bug.cgi?id=32666


I have a working in progress patch that adds sframe support for kernel
module.
https://github.com/heuza/linux/tree/sframe_unwinder.rfc

According to the sframe table values I got during runtime testing, looks
like the offsets are not correct .

When unwind symbols init_module(0xffff80007b155048) from the kernel 
module(livepatch-sample.ko), the start_address of the FDE entries in the
sframe table of the kernel modules appear incorrect.
For instance, the first FDE's start_addr is reported as -20564. Adding
this offset to the module's sframe section address (0xffff80007b15a040)
yields 0xffff80007b154fec, which is not within the livepatch-sample.ko
memory region(It should be larger than 0xffff80007b155000).

Here are the sframe table values of the livepatch-samples.ko that I print
by qemu + gdb.

```
$ /usr/bin/aarch64-linux-gnu-objdump -L --sframe=.sframe ./samples/livepatch/livepatch-sample.ko
./samples/livepatch/livepatch-sample.ko:     file format elf64-littleaarch64

Contents of the SFrame section .sframe:
  Header :

    Version: SFRAME_VERSION_2
    Flags: SFRAME_F_FDE_SORTED
    Num FDEs: 3
    Num FREs: 11

  Function Index :

    func idx [0]: pc = 0x0, size = 12 bytes
    STARTPC         CFA       FP        RA
    0000000000000000  sp+0      u         u

    func idx [1]: pc = 0x0, size = 44 bytes
    STARTPC         CFA       FP        RA
    0000000000000000  sp+0      u         u
    000000000000000c  sp+0      u         u[s]
    0000000000000010  sp+16     c-16      c-8[s]
    0000000000000024  sp+0      u         u[s]
    0000000000000028  sp+0      u         u

    func idx [2]: pc = 0x0, size = 56 bytes
    STARTPC         CFA       FP        RA
    0000000000000000  sp+0      u         u
    000000000000000c  sp+0      u         u[s]
    0000000000000010  sp+16     c-16      c-8[s]
    0000000000000030  sp+0      u         u[s]
    0000000000000034  sp+0      u         u



(gdb) bt
#0  find_fde (tbl=0xffff80007b157708, pc=18446603338286190664) at kernel/sframe_lookup.c:75
#1  0xffff80008031e260 in sframe_find_pc (pc=18446603338286190664, entry=0xffff800086f83800) at kernel/sframe_lookup.c:175
#2  0xffff800080035a48 in unwind_next_frame_sframe (state=0xffff800086f83828) at arch/arm64/kernel/stacktrace.c:270
#3  kunwind_next (state=0xffff800086f83828) at arch/arm64/kernel/stacktrace.c:332
...

(gdb) lx-symbols
loading vmlinux
scanning for modules in /home/wnliu/kernel
loading @0xffff80007b155000: /home/wnliu/kernel/samples/livepatch/livepatch-sample.ko
loading @0xffff80007b14d000: /home/wnliu/kernel/fs/fat/vfat.ko
loading @0xffff80007b130000: /home/wnliu/kernel/fs/fat/fat.ko

(gdb) p/x *tbl->sfhdr_p
$5 = {preamble = {magic = 0xdee2, version = 0x2, flags = 0x1}, abi_arch = 0x2, cfa_fixed_fp_offset = 0x0, cfa_fixed_ra_offset = 0x0, auxhdr_len = 0x0, num_fdes = 0x3, num_fres = 0xb, fre_len = 0x25, fdes_off = 0x0, fres_off = 0x3c}

(gdb) p/x tbl->sfhdr_p
$6 = 0xffff80007b15a040

(gdb) p *tbl->fde_p
$7 = {start_addr = -20564, size = 12, fres_off = 0, fres_num = 1, info = 0 '\000', rep_size = 0 '\000', padding = 0}

(gdb) p *(tbl->fde_p + 1)
$11 = {start_addr = -20552, size = 44, fres_off = 3, fres_num = 5, info = 0 '\000', rep_size = 0 '\000', padding = 0}

(gdb) p *(tbl->fde_p + 2)
$12 = {start_addr = -20508, size = 56, fres_off = 20, fres_num = 5, info = 0 '\000', rep_size = 0 '\000', padding = 0}

/* -20564 + 0xffff80007b15a040 = 0xffff80007b154fec */
(gdb) info symbol 0xffff80007b154fec
No symbol matches 0xffff80007b154fec
```
Josh Poimboeuf Feb. 25, 2025, 6:13 p.m. UTC | #55
On Tue, Feb 25, 2025 at 01:02:24AM +0000, Weinan Liu wrote:
> On Mon, Feb 10, 2025 at 12:30 AM Weinan Liu <wnliu@google.com> wrote:
> > I already have a WIP patch to add sframe support to the kernel module.
> > However, it is not yet working. I had trouble unwinding frames for the
> > kernel module using the current algorithm.
> >
> > Indu has likely identified the issue and will be addressing it from the
> > toolchain side.
> >
> > https://sourceware.org/bugzilla/show_bug.cgi?id=32666
> 
> 
> I have a working in progress patch that adds sframe support for kernel
> module.
> https://github.com/heuza/linux/tree/sframe_unwinder.rfc
> 
> According to the sframe table values I got during runtime testing, looks
> like the offsets are not correct .
> 
> When unwind symbols init_module(0xffff80007b155048) from the kernel 
> module(livepatch-sample.ko), the start_address of the FDE entries in the
> sframe table of the kernel modules appear incorrect.
> For instance, the first FDE's start_addr is reported as -20564. Adding
> this offset to the module's sframe section address (0xffff80007b15a040)
> yields 0xffff80007b154fec, which is not within the livepatch-sample.ko
> memory region(It should be larger than 0xffff80007b155000).

I assume kpatch create-diff-object needs to copy over a subset of the
.sframe section.  Similar to what kpatch_regenerate_orc_sections() does.
Indu Bhagat Feb. 25, 2025, 7:38 p.m. UTC | #56
On Mon, Feb 10, 2025 at 12:30 AM Weinan Liu <wnliu@google.com> wrote:
>> I already have a WIP patch to add sframe support to the kernel module.
>> However, it is not yet working. I had trouble unwinding frames for the
>> kernel module using the current algorithm.
>>
>> Indu has likely identified the issue and will be addressing it from the
>> toolchain side.
>>
>> https://sourceware.org/bugzilla/show_bug.cgi?id=32666
> 
> I have a working in progress patch that adds sframe support for kernel
> module.
> https://github.com/heuza/linux/tree/sframe_unwinder.rfc
> 
> According to the sframe table values I got during runtime testing, looks
> like the offsets are not correct .
> 

I hope to sanitize the fix for 32666 and post upstream soon (I had to 
address other related issues).  Unless fixed, relocating .sframe 
sections using the .rela.sframe is expected to generate incorrect output.

> When unwind symbols init_module(0xffff80007b155048) from the kernel
> module(livepatch-sample.ko), the start_address of the FDE entries in the
> sframe table of the kernel modules appear incorrect.

init_module will apply the relocations on the .sframe section, isnt it ?

> For instance, the first FDE's start_addr is reported as -20564. Adding
> this offset to the module's sframe section address (0xffff80007b15a040)
> yields 0xffff80007b154fec, which is not within the livepatch-sample.ko
> memory region(It should be larger than 0xffff80007b155000).
> 

Hmm..something seems off here.  Having tested a potential fix for 32666 
locally, I do not expect the first FDE to show this symptom.

> Here are the sframe table values of the livepatch-samples.ko that I print
> by qemu + gdb.
> 
> ```
> $ /usr/bin/aarch64-linux-gnu-objdump -L --sframe=.sframe ./samples/livepatch/livepatch-sample.ko
> ./samples/livepatch/livepatch-sample.ko:     file format elf64-littleaarch64
> 
> Contents of the SFrame section .sframe:
>   Header :
> 
>     Version: SFRAME_VERSION_2
>     Flags: SFRAME_F_FDE_SORTED
>     Num FDEs: 3
>     Num FREs: 11
> 
>   Function Index :
> 
>     func idx [0]: pc = 0x0, size = 12 bytes
>     STARTPC         CFA       FP        RA
>     0000000000000000  sp+0      u         u
> 
>     func idx [1]: pc = 0x0, size = 44 bytes
>     STARTPC         CFA       FP        RA
>     0000000000000000  sp+0      u         u
>     000000000000000c  sp+0      u         u[s]
>     0000000000000010  sp+16     c-16      c-8[s]
>     0000000000000024  sp+0      u         u[s]
>     0000000000000028  sp+0      u         u
> 
>     func idx [2]: pc = 0x0, size = 56 bytes
>     STARTPC         CFA       FP        RA
>     0000000000000000  sp+0      u         u
>     000000000000000c  sp+0      u         u[s]
>     0000000000000010  sp+16     c-16      c-8[s]
>     0000000000000030  sp+0      u         u[s]
>     0000000000000034  sp+0      u         u
> 
> 
> 
> (gdb) bt
> #0  find_fde (tbl=0xffff80007b157708, pc=18446603338286190664) at kernel/sframe_lookup.c:75
> #1  0xffff80008031e260 in sframe_find_pc (pc=18446603338286190664, entry=0xffff800086f83800) at kernel/sframe_lookup.c:175
> #2  0xffff800080035a48 in unwind_next_frame_sframe (state=0xffff800086f83828) at arch/arm64/kernel/stacktrace.c:270
> #3  kunwind_next (state=0xffff800086f83828) at arch/arm64/kernel/stacktrace.c:332
> ...
> 
> (gdb) lx-symbols
> loading vmlinux
> scanning for modules in /home/wnliu/kernel
> loading @0xffff80007b155000: /home/wnliu/kernel/samples/livepatch/livepatch-sample.ko
> loading @0xffff80007b14d000: /home/wnliu/kernel/fs/fat/vfat.ko
> loading @0xffff80007b130000: /home/wnliu/kernel/fs/fat/fat.ko
> 
> (gdb) p/x *tbl->sfhdr_p
> $5 = {preamble = {magic = 0xdee2, version = 0x2, flags = 0x1}, abi_arch = 0x2, cfa_fixed_fp_offset = 0x0, cfa_fixed_ra_offset = 0x0, auxhdr_len = 0x0, num_fdes = 0x3, num_fres = 0xb, fre_len = 0x25, fdes_off = 0x0, fres_off = 0x3c}
> 
> (gdb) p/x tbl->sfhdr_p
> $6 = 0xffff80007b15a040
> 
> (gdb) p *tbl->fde_p
> $7 = {start_addr = -20564, size = 12, fres_off = 0, fres_num = 1, info = 0 '\000', rep_size = 0 '\000', padding = 0}
> 
> (gdb) p *(tbl->fde_p + 1)
> $11 = {start_addr = -20552, size = 44, fres_off = 3, fres_num = 5, info = 0 '\000', rep_size = 0 '\000', padding = 0}
> 
> (gdb) p *(tbl->fde_p + 2)
> $12 = {start_addr = -20508, size = 56, fres_off = 20, fres_num = 5, info = 0 '\000', rep_size = 0 '\000', padding = 0}
> 
> /* -20564 + 0xffff80007b15a040 = 0xffff80007b154fec */
> (gdb) info symbol 0xffff80007b154fec
> No symbol matches 0xffff80007b154fec
> ```
Weinan Liu Feb. 25, 2025, 11:01 p.m. UTC | #57
On Tue, Feb 25, 2025 at 10:13 AM Josh Poimboeuf <jpoimboe@kernel.org> wrote:
>
> On Tue, Feb 25, 2025 at 01:02:24AM +0000, Weinan Liu wrote:
> > On Mon, Feb 10, 2025 at 12:30 AM Weinan Liu <wnliu@google.com> wrote:
> > > I already have a WIP patch to add sframe support to the kernel module.
> > > However, it is not yet working. I had trouble unwinding frames for the
> > > kernel module using the current algorithm.
> > >
> > > Indu has likely identified the issue and will be addressing it from the
> > > toolchain side.
> > >
> > > https://sourceware.org/bugzilla/show_bug.cgi?id=32666
> >
> >
> > I have a working in progress patch that adds sframe support for kernel
> > module.
> > https://github.com/heuza/linux/tree/sframe_unwinder.rfc
> >
> > According to the sframe table values I got during runtime testing, looks
> > like the offsets are not correct .
> >
> > When unwind symbols init_module(0xffff80007b155048) from the kernel
> > module(livepatch-sample.ko), the start_address of the FDE entries in the
> > sframe table of the kernel modules appear incorrect.
> > For instance, the first FDE's start_addr is reported as -20564. Adding
> > this offset to the module's sframe section address (0xffff80007b15a040)
> > yields 0xffff80007b154fec, which is not within the livepatch-sample.ko
> > memory region(It should be larger than 0xffff80007b155000).
>
> I assume kpatch create-diff-object needs to copy over a subset of the
> .sframe section.  Similar to what kpatch_regenerate_orc_sections() does.


You're right that we need to process the sframe section like what
kpatch_regenerate_orc_sections() does when building livepatch by kpatch.

However, livepatch-sample.ko is not generated by kpatch. It is built
directly from samples/livepatch/livepatch-sample.c by gcc during the kernel
build
Weinan Liu Feb. 25, 2025, 11:54 p.m. UTC | #58
On Tue, Feb 25, 2025 at 11:38 AM Indu Bhagat <indu.bhagat@oracle.com> wrote:
>
> On Mon, Feb 10, 2025 at 12:30 AM Weinan Liu <wnliu@google.com> wrote:
> >> I already have a WIP patch to add sframe support to the kernel module.
> >> However, it is not yet working. I had trouble unwinding frames for the
> >> kernel module using the current algorithm.
> >>
> >> Indu has likely identified the issue and will be addressing it from the
> >> toolchain side.
> >>
> >> https://sourceware.org/bugzilla/show_bug.cgi?id=32666
> >
> > I have a working in progress patch that adds sframe support for kernel
> > module.
> > https://github.com/heuza/linux/tree/sframe_unwinder.rfc
> >
> > According to the sframe table values I got during runtime testing, looks
> > like the offsets are not correct .
> >
>
> I hope to sanitize the fix for 32666 and post upstream soon (I had to
> address other related issues).  Unless fixed, relocating .sframe
> sections using the .rela.sframe is expected to generate incorrect output.
>
> > When unwind symbols init_module(0xffff80007b155048) from the kernel
> > module(livepatch-sample.ko), the start_address of the FDE entries in the
> > sframe table of the kernel modules appear incorrect.
>
> init_module will apply the relocations on the .sframe section, isnt it ?
>
> > For instance, the first FDE's start_addr is reported as -20564. Adding
> > this offset to the module's sframe section address (0xffff80007b15a040)
> > yields 0xffff80007b154fec, which is not within the livepatch-sample.ko
> > memory region(It should be larger than 0xffff80007b155000).
> >
>
> Hmm..something seems off here.  Having tested a potential fix for 32666
> locally, I do not expect the first FDE to show this symptom.
>

Yes, I think init_module will apply the relocation as well.
To further investigate, here's the relevant relocation and symbol table
information for the kernel module:

Relocation section '.rela.sframe' at offset 0x28350 contains 3 entries:
  Offset          Info           Type           Sym. Value    Sym. Name + Addend
00000000001c  000100000105 R_AARCH64_PREL32  0000000000000000 .text + 8
000000000030  000100000105 R_AARCH64_PREL32  0000000000000000 .text + 28
000000000044  000100000105 R_AARCH64_PREL32  0000000000000000 .text + 68

Symbol table '.symtab' contains 68 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
     0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 0000000000000000     0 SECTION LOCAL  DEFAULT    1 .text
...
    32: 0000000000000008    12 FUNC    LOCAL  DEFAULT    1 livepatch_exit
    33: 0000000000000008     0 NOTYPE  LOCAL  DEFAULT    3 $d
    34: 0000000000000028    44 FUNC    LOCAL  DEFAULT    1 livepatch_init
    35: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT    9 $d
    36: 0000000000000010     0 NOTYPE  LOCAL  DEFAULT    3 $d
    37: 0000000000000068    56 FUNC    LOCAL  DEFAULT    1 livepatch_cmdlin[...]
...
    63: 0000000000000008    12 FUNC    GLOBAL DEFAULT    1 cleanup_module
    64: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND klp_enable_patch
    65: 0000000000000028    44 FUNC    GLOBAL DEFAULT    1 init_module
Indu Bhagat Feb. 26, 2025, 12:22 a.m. UTC | #59
On 2/25/25 3:54 PM, Weinan Liu wrote:
> On Tue, Feb 25, 2025 at 11:38 AM Indu Bhagat <indu.bhagat@oracle.com> wrote:
>>
>> On Mon, Feb 10, 2025 at 12:30 AM Weinan Liu <wnliu@google.com> wrote:
>>>> I already have a WIP patch to add sframe support to the kernel module.
>>>> However, it is not yet working. I had trouble unwinding frames for the
>>>> kernel module using the current algorithm.
>>>>
>>>> Indu has likely identified the issue and will be addressing it from the
>>>> toolchain side.
>>>>
>>>> https://sourceware.org/bugzilla/show_bug.cgi?id=32666
>>>
>>> I have a working in progress patch that adds sframe support for kernel
>>> module.
>>> https://github.com/heuza/linux/tree/sframe_unwinder.rfc
>>>
>>> According to the sframe table values I got during runtime testing, looks
>>> like the offsets are not correct .
>>>
>>
>> I hope to sanitize the fix for 32666 and post upstream soon (I had to
>> address other related issues).  Unless fixed, relocating .sframe
>> sections using the .rela.sframe is expected to generate incorrect output.
>>
>>> When unwind symbols init_module(0xffff80007b155048) from the kernel
>>> module(livepatch-sample.ko), the start_address of the FDE entries in the
>>> sframe table of the kernel modules appear incorrect.
>>
>> init_module will apply the relocations on the .sframe section, isnt it ?
>>
>>> For instance, the first FDE's start_addr is reported as -20564. Adding
>>> this offset to the module's sframe section address (0xffff80007b15a040)
>>> yields 0xffff80007b154fec, which is not within the livepatch-sample.ko
>>> memory region(It should be larger than 0xffff80007b155000).
>>>
>>
>> Hmm..something seems off here.  Having tested a potential fix for 32666
>> locally, I do not expect the first FDE to show this symptom.
>>
> 
> Yes, I think init_module will apply the relocation as well.
> To further investigate, here's the relevant relocation and symbol table
> information for the kernel module:
> 
> Relocation section '.rela.sframe' at offset 0x28350 contains 3 entries:
>    Offset          Info           Type           Sym. Value    Sym. Name + Addend
> 00000000001c  000100000105 R_AARCH64_PREL32  0000000000000000 .text + 8
> 000000000030  000100000105 R_AARCH64_PREL32  0000000000000000 .text + 28
> 000000000044  000100000105 R_AARCH64_PREL32  0000000000000000 .text + 68
> 

The offsets look OK..

> Symbol table '.symtab' contains 68 entries:
>     Num:    Value          Size Type    Bind   Vis      Ndx Name
>       0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND
>       1: 0000000000000000     0 SECTION LOCAL  DEFAULT    1 .text
> ...
>      32: 0000000000000008    12 FUNC    LOCAL  DEFAULT    1 livepatch_exit
>      33: 0000000000000008     0 NOTYPE  LOCAL  DEFAULT    3 $d
>      34: 0000000000000028    44 FUNC    LOCAL  DEFAULT    1 livepatch_init
>      35: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT    9 $d
>      36: 0000000000000010     0 NOTYPE  LOCAL  DEFAULT    3 $d
>      37: 0000000000000068    56 FUNC    LOCAL  DEFAULT    1 livepatch_cmdlin[...]
> ...
>      63: 0000000000000008    12 FUNC    GLOBAL DEFAULT    1 cleanup_module
>      64: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND klp_enable_patch
>      65: 0000000000000028    44 FUNC    GLOBAL DEFAULT    1 init_module
Puranjay Mohan Feb. 26, 2025, 10:23 a.m. UTC | #60
Indu Bhagat <indu.bhagat@oracle.com> writes:

> On 2/25/25 3:54 PM, Weinan Liu wrote:
>> On Tue, Feb 25, 2025 at 11:38 AM Indu Bhagat <indu.bhagat@oracle.com> wrote:
>>>
>>> On Mon, Feb 10, 2025 at 12:30 AM Weinan Liu <wnliu@google.com> wrote:
>>>>> I already have a WIP patch to add sframe support to the kernel module.
>>>>> However, it is not yet working. I had trouble unwinding frames for the
>>>>> kernel module using the current algorithm.
>>>>>
>>>>> Indu has likely identified the issue and will be addressing it from the
>>>>> toolchain side.
>>>>>
>>>>> https://sourceware.org/bugzilla/show_bug.cgi?id=32666
>>>>
>>>> I have a working in progress patch that adds sframe support for kernel
>>>> module.
>>>> https://github.com/heuza/linux/tree/sframe_unwinder.rfc
>>>>
>>>> According to the sframe table values I got during runtime testing, looks
>>>> like the offsets are not correct .
>>>>
>>>
>>> I hope to sanitize the fix for 32666 and post upstream soon (I had to
>>> address other related issues).  Unless fixed, relocating .sframe
>>> sections using the .rela.sframe is expected to generate incorrect output.
>>>
>>>> When unwind symbols init_module(0xffff80007b155048) from the kernel
>>>> module(livepatch-sample.ko), the start_address of the FDE entries in the
>>>> sframe table of the kernel modules appear incorrect.
>>>
>>> init_module will apply the relocations on the .sframe section, isnt it ?
>>>
>>>> For instance, the first FDE's start_addr is reported as -20564. Adding
>>>> this offset to the module's sframe section address (0xffff80007b15a040)
>>>> yields 0xffff80007b154fec, which is not within the livepatch-sample.ko
>>>> memory region(It should be larger than 0xffff80007b155000).
>>>>
>>>
>>> Hmm..something seems off here.  Having tested a potential fix for 32666
>>> locally, I do not expect the first FDE to show this symptom.
>>>
>> 

Hi,

Sorry for not responding in the past few days.  I was on PTO and was
trying to improve my snowboarding technique, I am back now!!

I think what we are seeing is expected behaviour:

 | For instance, the first FDE's start_addr is reported as -20564. Adding
 | this offset to the module's sframe section address (0xffff80007b15a040)
 | yields 0xffff80007b154fec, which is not within the livepatch-sample.ko
 | memory region(It should be larger than 0xffff80007b155000).


Let me explain using a __dummy__ example.

Assume Memory layout before relocation:

 | Address | Element                                 | Relocation
 |  ....   | ....                                    |
 |   60    | init_module (start address)             |
 |   72    | init_module (end address)               |
 |  ....   | .....                                   |
 |   100   | Sframe section header start address     |
 |   128   | First FDE's start address               | RELOC_OP_PREL -> Put init_module address (60) - current address (128)

So, after relocation First FDE's start address has value 60 - 128 = -68

Now, while doing unwinding we Try to add this value to the sframe
section header's start address which is in this example 100,

so 100 + (-68) = 32

So, 32 is not within [60, 72], i.e. within init_module.

You can see that it is possible for this value to be less than the start
address of the module's memory region when this function's address is
very close to the start of the memory region.

The crux is that the offset in the FDE's start address is calculated
based on the address of the FDE's start_address and not based on the
address of the sframe section.


Thanks,
Puranjay
Indu Bhagat Feb. 26, 2025, 5:40 p.m. UTC | #61
On 2/26/25 2:23 AM, Puranjay Mohan wrote:
> Indu Bhagat <indu.bhagat@oracle.com> writes:
> 
>> On 2/25/25 3:54 PM, Weinan Liu wrote:
>>> On Tue, Feb 25, 2025 at 11:38 AM Indu Bhagat <indu.bhagat@oracle.com> wrote:
>>>>
>>>> On Mon, Feb 10, 2025 at 12:30 AM Weinan Liu <wnliu@google.com> wrote:
>>>>>> I already have a WIP patch to add sframe support to the kernel module.
>>>>>> However, it is not yet working. I had trouble unwinding frames for the
>>>>>> kernel module using the current algorithm.
>>>>>>
>>>>>> Indu has likely identified the issue and will be addressing it from the
>>>>>> toolchain side.
>>>>>>
>>>>>> https://sourceware.org/bugzilla/show_bug.cgi?id=32666
>>>>>
>>>>> I have a working in progress patch that adds sframe support for kernel
>>>>> module.
>>>>> https://github.com/heuza/linux/tree/sframe_unwinder.rfc
>>>>>
>>>>> According to the sframe table values I got during runtime testing, looks
>>>>> like the offsets are not correct .
>>>>>
>>>>
>>>> I hope to sanitize the fix for 32666 and post upstream soon (I had to
>>>> address other related issues).  Unless fixed, relocating .sframe
>>>> sections using the .rela.sframe is expected to generate incorrect output.
>>>>
>>>>> When unwind symbols init_module(0xffff80007b155048) from the kernel
>>>>> module(livepatch-sample.ko), the start_address of the FDE entries in the
>>>>> sframe table of the kernel modules appear incorrect.
>>>>
>>>> init_module will apply the relocations on the .sframe section, isnt it ?
>>>>
>>>>> For instance, the first FDE's start_addr is reported as -20564. Adding
>>>>> this offset to the module's sframe section address (0xffff80007b15a040)
>>>>> yields 0xffff80007b154fec, which is not within the livepatch-sample.ko
>>>>> memory region(It should be larger than 0xffff80007b155000).
>>>>>
>>>>
>>>> Hmm..something seems off here.  Having tested a potential fix for 32666
>>>> locally, I do not expect the first FDE to show this symptom.
>>>>
>>>
> 
> Hi,
> 
> Sorry for not responding in the past few days.  I was on PTO and was
> trying to improve my snowboarding technique, I am back now!!
> 
> I think what we are seeing is expected behaviour:
> 
>   | For instance, the first FDE's start_addr is reported as -20564. Adding
>   | this offset to the module's sframe section address (0xffff80007b15a040)
>   | yields 0xffff80007b154fec, which is not within the livepatch-sample.ko
>   | memory region(It should be larger than 0xffff80007b155000).
> 
> 
> Let me explain using a __dummy__ example.
> 
> Assume Memory layout before relocation:
> 
>   | Address | Element                                 | Relocation
>   |  ....   | ....                                    |
>   |   60    | init_module (start address)             |
>   |   72    | init_module (end address)               |
>   |  ....   | .....                                   |
>   |   100   | Sframe section header start address     |
>   |   128   | First FDE's start address               | RELOC_OP_PREL -> Put init_module address (60) - current address (128)
> 
> So, after relocation First FDE's start address has value 60 - 128 = -68
> 

For SFrame FDE function start address is :

"Signed 32-bit integral field denoting the virtual memory address of the 
described function, for which the SFrame FDE applies.  The value encoded 
in the ‘sfde_func_start_address’ field is the offset in bytes of the 
function’s start address, from the SFrame section."

So, in your case, after applying the relocations, you will get:
S + A - P = 60 - 128 = -68

This is the distance of the function start address (60) from the current 
location in SFrame section (128)

But what we intend to store is the distance of the function start 
address from the start of the SFrame section.  So we need to do an 
additional step for SFrame FDE:  Value += r_offset

-68 + 28 = -40
Where 28 is the r_offset in the RELA.

So we really expect a -40 in the relocated SFrame section instead of -68 
above.  IOW, the RELAs of SFrame section will need an additional step 
after relocation.

> Now, while doing unwinding we Try to add this value to the sframe
> section header's start address which is in this example 100,
> 
> so 100 + (-68) = 32
> 
> So, 32 is not within [60, 72], i.e. within init_module.
> 
> You can see that it is possible for this value to be less than the start
> address of the module's memory region when this function's address is
> very close to the start of the memory region.
> 
> The crux is that the offset in the FDE's start address is calculated
> based on the address of the FDE's start_address and not based on the
> address of the sframe section.
> 
> 
> Thanks,
> Puranjay
Puranjay Mohan Feb. 27, 2025, 9:38 a.m. UTC | #62
Indu Bhagat <indu.bhagat@oracle.com> writes:

> On 2/26/25 2:23 AM, Puranjay Mohan wrote:
>> Indu Bhagat <indu.bhagat@oracle.com> writes:
>> 
>>> On 2/25/25 3:54 PM, Weinan Liu wrote:
>>>> On Tue, Feb 25, 2025 at 11:38 AM Indu Bhagat <indu.bhagat@oracle.com> wrote:
>>>>>
>>>>> On Mon, Feb 10, 2025 at 12:30 AM Weinan Liu <wnliu@google.com> wrote:
>>>>>>> I already have a WIP patch to add sframe support to the kernel module.
>>>>>>> However, it is not yet working. I had trouble unwinding frames for the
>>>>>>> kernel module using the current algorithm.
>>>>>>>
>>>>>>> Indu has likely identified the issue and will be addressing it from the
>>>>>>> toolchain side.
>>>>>>>
>>>>>>> https://sourceware.org/bugzilla/show_bug.cgi?id=32666
>>>>>>
>>>>>> I have a working in progress patch that adds sframe support for kernel
>>>>>> module.
>>>>>> https://github.com/heuza/linux/tree/sframe_unwinder.rfc
>>>>>>
>>>>>> According to the sframe table values I got during runtime testing, looks
>>>>>> like the offsets are not correct .
>>>>>>
>>>>>
>>>>> I hope to sanitize the fix for 32666 and post upstream soon (I had to
>>>>> address other related issues).  Unless fixed, relocating .sframe
>>>>> sections using the .rela.sframe is expected to generate incorrect output.
>>>>>
>>>>>> When unwind symbols init_module(0xffff80007b155048) from the kernel
>>>>>> module(livepatch-sample.ko), the start_address of the FDE entries in the
>>>>>> sframe table of the kernel modules appear incorrect.
>>>>>
>>>>> init_module will apply the relocations on the .sframe section, isnt it ?
>>>>>
>>>>>> For instance, the first FDE's start_addr is reported as -20564. Adding
>>>>>> this offset to the module's sframe section address (0xffff80007b15a040)
>>>>>> yields 0xffff80007b154fec, which is not within the livepatch-sample.ko
>>>>>> memory region(It should be larger than 0xffff80007b155000).
>>>>>>
>>>>>
>>>>> Hmm..something seems off here.  Having tested a potential fix for 32666
>>>>> locally, I do not expect the first FDE to show this symptom.
>>>>>
>>>>
>> 
>> Hi,
>> 
>> Sorry for not responding in the past few days.  I was on PTO and was
>> trying to improve my snowboarding technique, I am back now!!
>> 
>> I think what we are seeing is expected behaviour:
>> 
>>   | For instance, the first FDE's start_addr is reported as -20564. Adding
>>   | this offset to the module's sframe section address (0xffff80007b15a040)
>>   | yields 0xffff80007b154fec, which is not within the livepatch-sample.ko
>>   | memory region(It should be larger than 0xffff80007b155000).
>> 
>> 
>> Let me explain using a __dummy__ example.
>> 
>> Assume Memory layout before relocation:
>> 
>>   | Address | Element                                 | Relocation
>>   |  ....   | ....                                    |
>>   |   60    | init_module (start address)             |
>>   |   72    | init_module (end address)               |
>>   |  ....   | .....                                   |
>>   |   100   | Sframe section header start address     |
>>   |   128   | First FDE's start address               | RELOC_OP_PREL -> Put init_module address (60) - current address (128)
>> 
>> So, after relocation First FDE's start address has value 60 - 128 = -68
>> 
>
> For SFrame FDE function start address is :
>
> "Signed 32-bit integral field denoting the virtual memory address of the 
> described function, for which the SFrame FDE applies.  The value encoded 
> in the ‘sfde_func_start_address’ field is the offset in bytes of the 
> function’s start address, from the SFrame section."
>
> So, in your case, after applying the relocations, you will get:
> S + A - P = 60 - 128 = -68
>
> This is the distance of the function start address (60) from the current 
> location in SFrame section (128)
>
> But what we intend to store is the distance of the function start 
> address from the start of the SFrame section.  So we need to do an 
> additional step for SFrame FDE:  Value += r_offset

Thanks for the explaination, now it makes sense.

But I couldn't find a relocation type in AARCH64 that does this extra +=
r_offset along with PREL32.

The kernel's module loader is only doing the R_AARCH64_PREL32 which is
why we see this issue.

How is this working even for the kernel itself? or for that matter, any
other binary compiled with sframe?

From my limited undestanding, the way to fix this would be to hack the
relocator to do this additional step while relocating .sframe sections.
Or the 'addend' values in .rela.sframe should already have the +r_offset
added to it, then no change to the relocator would be needed.

> -68 + 28 = -40
> Where 28 is the r_offset in the RELA.
>
> So we really expect a -40 in the relocated SFrame section instead of -68 
> above.  IOW, the RELAs of SFrame section will need an additional step 
> after relocation.
>

Thanks,
Puranjay
Indu Bhagat Feb. 28, 2025, 6:47 a.m. UTC | #63
On 2/27/25 1:38 AM, Puranjay Mohan wrote:
> Indu Bhagat <indu.bhagat@oracle.com> writes:
> 
>> On 2/26/25 2:23 AM, Puranjay Mohan wrote:
>>> Indu Bhagat <indu.bhagat@oracle.com> writes:
>>>
>>>> On 2/25/25 3:54 PM, Weinan Liu wrote:
>>>>> On Tue, Feb 25, 2025 at 11:38 AM Indu Bhagat <indu.bhagat@oracle.com> wrote:
>>>>>>
>>>>>> On Mon, Feb 10, 2025 at 12:30 AM Weinan Liu <wnliu@google.com> wrote:
>>>>>>>> I already have a WIP patch to add sframe support to the kernel module.
>>>>>>>> However, it is not yet working. I had trouble unwinding frames for the
>>>>>>>> kernel module using the current algorithm.
>>>>>>>>
>>>>>>>> Indu has likely identified the issue and will be addressing it from the
>>>>>>>> toolchain side.
>>>>>>>>
>>>>>>>> https://sourceware.org/bugzilla/show_bug.cgi?id=32666
>>>>>>>
>>>>>>> I have a working in progress patch that adds sframe support for kernel
>>>>>>> module.
>>>>>>> https://github.com/heuza/linux/tree/sframe_unwinder.rfc
>>>>>>>
>>>>>>> According to the sframe table values I got during runtime testing, looks
>>>>>>> like the offsets are not correct .
>>>>>>>
>>>>>>
>>>>>> I hope to sanitize the fix for 32666 and post upstream soon (I had to
>>>>>> address other related issues).  Unless fixed, relocating .sframe
>>>>>> sections using the .rela.sframe is expected to generate incorrect output.
>>>>>>
>>>>>>> When unwind symbols init_module(0xffff80007b155048) from the kernel
>>>>>>> module(livepatch-sample.ko), the start_address of the FDE entries in the
>>>>>>> sframe table of the kernel modules appear incorrect.
>>>>>>
>>>>>> init_module will apply the relocations on the .sframe section, isnt it ?
>>>>>>
>>>>>>> For instance, the first FDE's start_addr is reported as -20564. Adding
>>>>>>> this offset to the module's sframe section address (0xffff80007b15a040)
>>>>>>> yields 0xffff80007b154fec, which is not within the livepatch-sample.ko
>>>>>>> memory region(It should be larger than 0xffff80007b155000).
>>>>>>>
>>>>>>
>>>>>> Hmm..something seems off here.  Having tested a potential fix for 32666
>>>>>> locally, I do not expect the first FDE to show this symptom.
>>>>>>
>>>>>
>>>
>>> Hi,
>>>
>>> Sorry for not responding in the past few days.  I was on PTO and was
>>> trying to improve my snowboarding technique, I am back now!!
>>>
>>> I think what we are seeing is expected behaviour:
>>>
>>>    | For instance, the first FDE's start_addr is reported as -20564. Adding
>>>    | this offset to the module's sframe section address (0xffff80007b15a040)
>>>    | yields 0xffff80007b154fec, which is not within the livepatch-sample.ko
>>>    | memory region(It should be larger than 0xffff80007b155000).
>>>
>>>
>>> Let me explain using a __dummy__ example.
>>>
>>> Assume Memory layout before relocation:
>>>
>>>    | Address | Element                                 | Relocation
>>>    |  ....   | ....                                    |
>>>    |   60    | init_module (start address)             |
>>>    |   72    | init_module (end address)               |
>>>    |  ....   | .....                                   |
>>>    |   100   | Sframe section header start address     |
>>>    |   128   | First FDE's start address               | RELOC_OP_PREL -> Put init_module address (60) - current address (128)
>>>
>>> So, after relocation First FDE's start address has value 60 - 128 = -68
>>>
>>
>> For SFrame FDE function start address is :
>>
>> "Signed 32-bit integral field denoting the virtual memory address of the
>> described function, for which the SFrame FDE applies.  The value encoded
>> in the ‘sfde_func_start_address’ field is the offset in bytes of the
>> function’s start address, from the SFrame section."
>>
>> So, in your case, after applying the relocations, you will get:
>> S + A - P = 60 - 128 = -68
>>
>> This is the distance of the function start address (60) from the current
>> location in SFrame section (128)
>>
>> But what we intend to store is the distance of the function start
>> address from the start of the SFrame section.  So we need to do an
>> additional step for SFrame FDE:  Value += r_offset
> 
> Thanks for the explaination, now it makes sense.
> 
> But I couldn't find a relocation type in AARCH64 that does this extra +=
> r_offset along with PREL32.
> 
> The kernel's module loader is only doing the R_AARCH64_PREL32 which is
> why we see this issue.
> 
> How is this working even for the kernel itself? or for that matter, any
> other binary compiled with sframe?
> 

For the usual executables or shared objects, the calculations are 
applied by ld.bfd at this time.  Hence, the issue manifests in 
relocatable files.

>  From my limited undestanding, the way to fix this would be to hack the
> relocator to do this additional step while relocating .sframe sections.
> Or the 'addend' values in .rela.sframe should already have the +r_offset
> added to it, then no change to the relocator would be needed.
> 

Of the two, adjusting the addend values in .rela.sframe may be a 
reasonable way to go about it.  Let me try it out in GAS and ld.bfd.

>> -68 + 28 = -40
>> Where 28 is the r_offset in the RELA.
>>
>> So we really expect a -40 in the relocated SFrame section instead of -68
>> above.  IOW, the RELAs of SFrame section will need an additional step
>> after relocation.
>>
> 
> Thanks,
> Puranjay
Indu Bhagat March 9, 2025, 2:43 p.m. UTC | #64
On 2/27/25 10:47 PM, Indu Bhagat wrote:
> On 2/27/25 1:38 AM, Puranjay Mohan wrote:
>> Indu Bhagat <indu.bhagat@oracle.com> writes:
>>
>>> On 2/26/25 2:23 AM, Puranjay Mohan wrote:
>>>> Indu Bhagat <indu.bhagat@oracle.com> writes:
>>>>
>>>>> On 2/25/25 3:54 PM, Weinan Liu wrote:
>>>>>> On Tue, Feb 25, 2025 at 11:38 AM Indu Bhagat 
>>>>>> <indu.bhagat@oracle.com> wrote:
>>>>>>>
>>>>>>> On Mon, Feb 10, 2025 at 12:30 AM Weinan Liu <wnliu@google.com> 
>>>>>>> wrote:
>>>>>>>>> I already have a WIP patch to add sframe support to the kernel 
>>>>>>>>> module.
>>>>>>>>> However, it is not yet working. I had trouble unwinding frames 
>>>>>>>>> for the
>>>>>>>>> kernel module using the current algorithm.
>>>>>>>>>
>>>>>>>>> Indu has likely identified the issue and will be addressing it 
>>>>>>>>> from the
>>>>>>>>> toolchain side.
>>>>>>>>>
>>>>>>>>> https://sourceware.org/bugzilla/show_bug.cgi?id=32666
>>>>>>>>
>>>>>>>> I have a working in progress patch that adds sframe support for 
>>>>>>>> kernel
>>>>>>>> module.
>>>>>>>> https://github.com/heuza/linux/tree/sframe_unwinder.rfc
>>>>>>>>
>>>>>>>> According to the sframe table values I got during runtime 
>>>>>>>> testing, looks
>>>>>>>> like the offsets are not correct .
>>>>>>>>
>>>>>>>
>>>>>>> I hope to sanitize the fix for 32666 and post upstream soon (I 
>>>>>>> had to
>>>>>>> address other related issues).  Unless fixed, relocating .sframe
>>>>>>> sections using the .rela.sframe is expected to generate incorrect 
>>>>>>> output.
>>>>>>>
>>>>>>>> When unwind symbols init_module(0xffff80007b155048) from the kernel
>>>>>>>> module(livepatch-sample.ko), the start_address of the FDE 
>>>>>>>> entries in the
>>>>>>>> sframe table of the kernel modules appear incorrect.
>>>>>>>
>>>>>>> init_module will apply the relocations on the .sframe section, 
>>>>>>> isnt it ?
>>>>>>>
>>>>>>>> For instance, the first FDE's start_addr is reported as -20564. 
>>>>>>>> Adding
>>>>>>>> this offset to the module's sframe section address 
>>>>>>>> (0xffff80007b15a040)
>>>>>>>> yields 0xffff80007b154fec, which is not within the livepatch- 
>>>>>>>> sample.ko
>>>>>>>> memory region(It should be larger than 0xffff80007b155000).
>>>>>>>>
>>>>>>>
>>>>>>> Hmm..something seems off here.  Having tested a potential fix for 
>>>>>>> 32666
>>>>>>> locally, I do not expect the first FDE to show this symptom.
>>>>>>>
>>>>>>
>>>>
>>>> Hi,
>>>>
>>>> Sorry for not responding in the past few days.  I was on PTO and was
>>>> trying to improve my snowboarding technique, I am back now!!
>>>>
>>>> I think what we are seeing is expected behaviour:
>>>>
>>>>    | For instance, the first FDE's start_addr is reported as -20564. 
>>>> Adding
>>>>    | this offset to the module's sframe section address 
>>>> (0xffff80007b15a040)
>>>>    | yields 0xffff80007b154fec, which is not within the livepatch- 
>>>> sample.ko
>>>>    | memory region(It should be larger than 0xffff80007b155000).
>>>>
>>>>
>>>> Let me explain using a __dummy__ example.
>>>>
>>>> Assume Memory layout before relocation:
>>>>
>>>>    | Address | Element                                 | Relocation
>>>>    |  ....   | ....                                    |
>>>>    |   60    | init_module (start address)             |
>>>>    |   72    | init_module (end address)               |
>>>>    |  ....   | .....                                   |
>>>>    |   100   | Sframe section header start address     |
>>>>    |   128   | First FDE's start address               | 
>>>> RELOC_OP_PREL -> Put init_module address (60) - current address (128)
>>>>
>>>> So, after relocation First FDE's start address has value 60 - 128 = -68
>>>>
>>>
>>> For SFrame FDE function start address is :
>>>
>>> "Signed 32-bit integral field denoting the virtual memory address of the
>>> described function, for which the SFrame FDE applies.  The value encoded
>>> in the ‘sfde_func_start_address’ field is the offset in bytes of the
>>> function’s start address, from the SFrame section."
>>>
>>> So, in your case, after applying the relocations, you will get:
>>> S + A - P = 60 - 128 = -68
>>>
>>> This is the distance of the function start address (60) from the current
>>> location in SFrame section (128)
>>>
>>> But what we intend to store is the distance of the function start
>>> address from the start of the SFrame section.  So we need to do an
>>> additional step for SFrame FDE:  Value += r_offset
>>
>> Thanks for the explaination, now it makes sense.
>>
>> But I couldn't find a relocation type in AARCH64 that does this extra +=
>> r_offset along with PREL32.
>>
>> The kernel's module loader is only doing the R_AARCH64_PREL32 which is
>> why we see this issue.
>>
>> How is this working even for the kernel itself? or for that matter, any
>> other binary compiled with sframe?
>>
> 
> For the usual executables or shared objects, the calculations are 
> applied by ld.bfd at this time.  Hence, the issue manifests in 
> relocatable files.
> 
>>  From my limited undestanding, the way to fix this would be to hack the
>> relocator to do this additional step while relocating .sframe sections.
>> Or the 'addend' values in .rela.sframe should already have the +r_offset
>> added to it, then no change to the relocator would be needed.
>>
> 
> Of the two, adjusting the addend values in .rela.sframe may be a 
> reasonable way to go about it.  Let me try it out in GAS and ld.bfd.
> 

A fix for this is in the works (being discussed on the 
binutils@sourceware list).  I will keep you posted.

Thanks
Indu