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

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Weinan Liu <wnliu@xxxxxxxxxx> 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

Attachment: signature.asc
Description: PGP signature


[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux Kernel]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux SCSI]

  Powered by Linux