[Crash-utility] Re: [PATCH v4 07/16] Stop stack unwinding at non-kernel address

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

 



Hi Lijiang,

On Thu, Jul 25, 2024 at 9:08 PM lijiang <lijiang@xxxxxxxxxx> wrote:
>
> On Thu, Jul 25, 2024 at 3:31 PM Tao Liu <ltao@xxxxxxxxxx> wrote:
>>
>> Hi Lijiang,
>>
>> On Thu, Jul 25, 2024 at 6:27 PM lijiang <lijiang@xxxxxxxxxx> wrote:
>> >
>> > On Thu, Jul 25, 2024 at 7:59 AM Tao Liu <ltao@xxxxxxxxxx> wrote:
>> >>
>> >> Hi Lijiang,
>> >>
>> >> On Wed, Jul 24, 2024 at 6:37 PM lijiang <lijiang@xxxxxxxxxx> wrote:
>> >> >
>> >> > Hi, Tao
>> >> >
>> >> > On Tue, Jul 23, 2024 at 2:24 PM lijiang <lijiang@xxxxxxxxxx> wrote:
>> >> >>
>> >> >> On Tue, Jul 23, 2024 at 1:55 PM Tao Liu <ltao@xxxxxxxxxx> wrote:
>> >> >>>
>> >> >>> Hi Aditya & Lianbo,
>> >> >>>
>> >> >>> On Mon, Jun 24, 2024 at 11:46 PM Aditya Gupta <adityag@xxxxxxxxxxxxx> wrote:
>> >> >>> >
>> >> >>> > Hello Lianbo,
>> >> >>> >
>> >> >>> > On 24/06/24 05:32PM, lijiang wrote:
>> >> >>> > > > <...snip...>
>> >> >>> > > >
>> >> >>> > > > Before:
>> >> >>> > > > crash> gdb bt
>> >> >>> > > >  #0  0xffffffff816a8f65 in context_switch ...
>> >> >>> > > >  #1  __schedule () ...
>> >> >>> > > >  #2  0xffffffff816a94e9 in schedule ...
>> >> >>> > > >  #3  0xffffffff816a86fd in schedule_hrtimeout_range_clock ...
>> >> >>> > > >  #4  0xffffffff816a8733 in schedule_hrtimeout_range ...
>> >> >>> > > >  #5  0xffffffff8124bb7e in ep_poll ...
>> >> >>> > > >  #6  0xffffffff8124d00d in SYSC_epoll_wait ...
>> >> >>> > > >  #7  SyS_epoll_wait ...
>> >> >>> > > >  #8  <signal handler called>
>> >> >>> > > >  #9  0x00007f0449407923 in ?? ()
>> >> >>> > > >  #10 0xffff880100000001 in ?? ()
>> >> >>> > > >  #11 0xffff880169b3c010 in ?? ()
>> >> >>> > > >  #12 0x0000000000000040 in irq_stack_union ()
>> >> >>> > > >  #13 0xffff880169b3c058 in ?? ()
>> >> >>> > > >  #14 0xffff880169b3c048 in ?? ()
>> >> >>> > > >  #15 0xffff880169b3c050 in ?? ()
>> >> >>> > > >  #16 0x0000000000000000 in ?? ()
>> >> >>> > > >
>> >> >>> > > > After:
>> >> >>> > > > crash> gdb bt
>> >> >>> > > >  #0  0xffffffff816a8f65 in context_switch ...
>> >> >>> > > >  #1  __schedule () ...
>> >> >>> > > >  #2  0xffffffff816a94e9 in schedule () ...
>> >> >>> > > >  #3  0xffffffff816a86fd in schedule_hrtimeout_range_clock ...
>> >> >>> > > >  #4  0xffffffff816a8733 in schedule_hrtimeout_range ...
>> >> >>> > > >  #5  0xffffffff8124bb7e in ep_poll ...
>> >> >>> > > >  #6  0xffffffff8124d00d in SYSC_epoll_wait ...
>> >> >>> > > >  #7  SyS_epoll_wait ...
>> >> >>> > > >  #8  <signal handler called>
>> >> >>> > > >  #9  0x00007f0449407923 in ?? ()
>> >> >>> > > >
>> >> >>> > > >
>> >> >>> > > It seems that there are still some non-kernel addresses that do not get
>> >> >>> > > filtered. Can you help double check?
>> >> >>>
>> >> >>> Yes, it is a non-kernel address which does not get filtered.
>> >> >>>
>> >> >>> > >
>> >> >>> > >
>> >> >>> > > For example:
>> >> >>> > >
>> >> >>> > > crash> gdb bt
>> >> >>> > > #0  crash_setup_regs (newregs=0xffffb5bb4f197938, oldregs=0x0) at
>> >> >>> > > ./arch/x86/include/asm/kexec.h:114
>> >> >>> > > #1  0xffffffff8e61e32e in __crash_kexec (regs=regs@entry=0x0) at
>> >> >>> > > kernel/crash_core.c:122
>> >> >>> > > #2  0xffffffff8e51a64d in panic (fmt=fmt@entry=0xffffffff8fa51609 "sysrq
>> >> >>> > > triggered crash\n") at kernel/panic.c:366
>> >> >>> > > #3  0xffffffff8ec21f86 in sysrq_handle_crash (key=<optimized out>) at
>> >> >>> > > drivers/tty/sysrq.c:154
>> >> >>> > > #4  0xffffffff8ec22550 in __handle_sysrq (key=<optimized out>,
>> >> >>> > > check_mask=check_mask@entry=false) at drivers/tty/sysrq.c:612
>> >> >>> > > #5  0xffffffff8ec22bf5 in write_sysrq_trigger (file=<optimized out>,
>> >> >>> > > buf=<optimized out>, count=2, ppos=<optimized out>) at
>> >> >>> > > drivers/tty/sysrq.c:1183
>> >> >>> > > #6  0xffffffff8e935ae5 in pde_write (ppos=<optimized out>, count=<optimized
>> >> >>> > > out>, buf=<optimized out>, file=0xffffb5bb4f197938, pde=0xffff98338b78e0c0)
>> >> >>> > > at fs/proc/inode.c:334
>> >> >>> > > #7  proc_reg_write (file=0xffffb5bb4f197938, buf=0x0, count=1, ppos=0x0) at
>> >> >>> > > fs/proc/inode.c:346
>> >> >>> > > #8  0xffffffff8e88d382 in vfs_write (file=file@entry=0xffff98338b789200,
>> >> >>> > > buf=buf@entry=0x5614d58a22c0 <error: Cannot access memory at address
>> >> >>> > > 0x5614d58a22c0>, count=count@entry=2, pos=pos@entry=0xffffb5bb4f197b78) at
>> >> >>> > > fs/read_write.c:588
>> >> >>> > > #9  0xffffffff8e88d9ff in ksys_write (fd=<optimized out>,
>> >> >>> > > buf=0x5614d58a22c0 <error: Cannot access memory at address 0x5614d58a22c0>,
>> >> >>> > > count=2) at fs/read_write.c:643
>> >> >>> > > #10 0xffffffff8f124429 in do_syscall_x64 (nr=1, regs=0xffffb5bb4f197f58) at
>> >> >>> > > arch/x86/entry/common.c:52
>> >> >>> > > #11 do_syscall_64 (regs=0xffffb5bb4f197f58, nr=1) at
>> >> >>> > > arch/x86/entry/common.c:83
>> >> >>> > > #12 0xffffffff8f20012b in entry_SYSCALL_64 () at
>> >> >>> > > arch/x86/entry/entry_64.S:121
>> >> >>> > > #13 0x00007f9a147f69e0 in ?? ()
>> >> >>> > >
>> >> >>> > > The frame #13 looks like a non-kernel address.
>> >> >>>
>> >> >>> The address usually to be the user space address before entering
>> >> >>> kernel, you can see it by:
>> >> >>>
>> >> >>> crash> gdb bt
>> >> >>> ...snip...
>> >> >>> #7  SyS_epoll_wait ...
>> >> >>> #8  <signal handler called>
>> >> >>> #9  0x00007f0449407923 in ?? ()
>> >> >>>
>> >> >>> crash> bt
>> >> >>> ...snip...
>> >> >>> #6 [ffff880169b3bf80] system_call_fastpath at ffffffff816b5009
>> >> >>>     RIP: 00007f0449407923 ...
>> >> >>>
>> >> >>> So I think leaving the last frame here is useful and shouldn't be
>> >> >>> filtered. Though it looks like some garbage data, it can help for some
>> >> >>> experienced users...
>> >> >>
>> >> >>
>> >> >>
>> >> >> Hmm, normally it should be filtered, otherwise this looks weird.
>> >> >>
>> >> >> Let me dig into the details and see if that can be filtered out.
>> >> >
>> >> >
>> >> Thanks for your patch!
>> >>
>> >> > Can you help try this? I saw the non-kernel addresses are filtered out.
>> >> >
>> >> > + #ifdef CRASH_MERGE
>> >> > + extern "C" int is_kvaddr(ulong);
>> >> > + #endif
>> >> >
>> >> > static void
>> >> > print_frame (const frame_print_options &fp_opts,
>> >> >              frame_info *frame, int print_level,
>> >> >              enum print_what print_what, int print_args,
>> >> >              struct symtab_and_line sal)
>> >> > {
>> >> >   struct gdbarch *gdbarch = get_frame_arch (frame);
>> >> >   struct ui_out *uiout = current_uiout;
>> >> >   enum language funlang = language_unknown;
>> >> >   struct value_print_options opts;
>> >> >   struct symbol *func;
>> >> >   CORE_ADDR pc = 0;
>> >> >   int pc_p;
>> >> >
>> >> >   pc_p = get_frame_pc_if_available (frame, &pc);
>> >> > + #ifdef CRASH_MERGE
>> >> > +  if (!is_kvaddr(pc))
>> >> > +        return;
>> >> > + #endif
>> >> > ...
>> >> > }
>> >>
>> >> Your code change is "stop printing for non-kernel address", however I
>> >> would prefer to "stop stack unwinding for non-kernel address", so I
>> >
>> >
>> > Yes, they are different.
>> >
>> > If "stop stack unwinding for non-kernel address" won't truncate the backtrace, I would also prefer it.
>> > Otherwise I would prefer another one.
>>
>> OK, it won't truncate the backtrace.
>>
>> >
>> >>
>> >> think it is better to modify it within the for loop, this is where
>> >> stack unwinding happens.
>> >>
>> >> for (fi = trailing; fi && count--; fi = get_prev_frame (fi))
>> >>       ...
>> >>       print_frame_info (fp_opts, fi, 1, LOCATION, 1, 0);
>> >>
>> >> I made the following code change:
>> >>
>> >>       for (fi = trailing; fi && count--; fi = get_prev_frame (fi))
>> >>         {
>> >>           QUIT;
>> >>           ...
>> >> +         CORE_ADDR pc = 0;
>> >> +          get_frame_pc_if_available (fi, &pc);
>> >> +         if (!is_kvaddr(pc)) {
>> >> +               fi = NULL;
>> >> +                break;
>> >>  +        }
>> >>           print_frame_info (fp_opts, fi, 1, LOCATION, 1, 0);
>> >>
>> >> With the change:
>> >>
>> >> crash> gdb bt
>> >> #0  blk_mq_rq_timed_out (req=0xffff880fdb246000,
>> >> reserved=reserved@entry=false) at block/blk-mq.c:640
>> >> #1  0xffffffff8130504c in blk_mq_check_expired
>> >> (hctx=hctx@entry=0xffff880fda56bc00, rq=<optimized out>,
>> >> priv=priv@entry=0xffff880fcf68fde8, reserved=reserved@entry=false) at
>> >> block/blk-mq.c:697
>> >> #2  0xffffffff81305eb4 in bt_for_each
>> >> (hctx=hctx@entry=0xffff880fda56bc00, bt=bt@entry=0xffff88014c14c310,
>> >> off=32, fn=fn@entry=0xffffffff81304ff0 <blk_mq_check_expired>,
>> >> data=data@entry=0xffff880fcf68fde8, reserved=reserved@entry=false) at
>> >> block/blk-mq-tag.c:431
>> >> #3  0xffffffff8130686e in blk_mq_queue_tag_busy_iter
>> >> (q=q@entry=0xffff88004912a340, fn=fn@entry=0xffffffff81304ff0
>> >> <blk_mq_check_expired>, priv=priv@entry=0xffff880fcf68fde8) at
>> >> block/blk-mq-tag.c:530
>> >> #4  0xffffffff81301d2b in blk_mq_timeout_work
>> >> (work=0xffff88004912ab68) at block/blk-mq.c:730
>> >> #5  0xffffffff810a881a in process_one_work
>> >> (worker=worker@entry=0xffff880fd86efa00, work=0xffff88004912ab68) at
>> >> kernel/workqueue.c:2252
>> >> #6  0xffffffff810a94e6 in worker_thread (__worker=0xffff880fd86efa00)
>> >> at kernel/workqueue.c:2380
>> >> #7  0xffffffff810b098f in kthread (_create=0xffff8801695f7d38) at
>> >> kernel/kthread.c:202
>> >> #8  <signal handler called>
>> >
>> I don't know, I didn't dive into gdb for this inspection. Frankly I
>> didn't have much knowledge on how gdb unwinded each stack frame. All I
>> know is, gdb has different handlers for processing each frame
>> unwinding, such as the one to process function inline. So I guess for
>> this case, gdb thinks it is some signal processing routine.
>>
>
> Thanks for the explanation, Tao.
>
> One more question:
> Will the backtrace('#8  <signal handler called>') be printed if my changes are applied?
>
Yes, still the same output:

#6  0xffffffff8124d00d in SYSC_epoll_wait (timeout=<optimized out>,
maxevents=29, events=<optimized out>, epfd=<optimized out>) at
fs/eventpoll.c:2043
#7  SyS_epoll_wait (epfd=<optimized out>, events=140721208415648,
maxevents=29, timeout=4294967295) at fs/eventpoll.c:2008
#8  <signal handler called>

Thanks,
Tao Liu

> Thanks
> Lianbo
>
>>
>> Personally I'm OK with this, if you see the original stack trace:
>>
>> #7  SyS_epoll_wait (epfd=<optimized out>, events=140721208415648,
>> maxevents=29, timeout=4294967295) at fs/eventpoll.c:2008
>> #8  <signal handler called>
>> #9  0x00007f0449407923 in ?? ()
>>
>> It usually happens right before the syscall, which is switching from
>> user space to kernel space. Maybe it looks like a signal or interrupt
>> handling routine. Just my guess...
>>
>>
>> >     ^^^^^^^^^^^^^^^^^^^^^^^^
>> >
>> > What's this for?
>> >
>> > Thanks
>> > Lianbo
>> >
>> >>
>> >> crash>
>> >>
>> >> What do you think?
>> >>
>> >> Thanks,
>> >> Tao Liu
>> >>
>> >> >
>> >> > Thanks
>> >> > Lianbo
>> >> >
>> >> >>
>> >> >> Thanks
>> >> >> Lianbo
>> >> >>
>> >> >>>
>> >> >>> >
>> >> >>> > True. Though it seems to be okay for it to print the last frame with a
>> >> >>> > non-kernel address, as in this snippet from gdb:
>> >> >>> >
>> >> >>> >     for (fi = trailing; fi && count--; fi = get_prev_frame (fi))
>> >> >>> >         ...
>> >> >>> >           print_frame_info (fp_opts, fi, 1, LOCATION, 1, 0);
>> >> >>> >
>> >> >>> > Seems that frame #13, fi was not NULL.
>> >> >>> >
>> >> >>> > Seeing Tao's change, it compares the current frame's NIP/PC to see if
>> >> >>> > it should return NULL (which I think is nice and works). Here the
>> >> >>> > 'this_frame' would have been frame 12, (which would have called
>> >> >>> > `'get_prev_frame' to get the frame 13)
>> >> >>> >
>> >> >>> > ```
>> >> >>> >   frame_pc_p = get_frame_pc_if_available (this_frame, &frame_pc);
>> >> >>> > #ifdef CRASH_MERGE
>> >> >>> >   if (!is_kvaddr(frame_pc)) {
>> >> >>> >         return NULL;
>> >> >>> >   }
>> >> >>> > #endif
>> >> >>> > ```
>> >> >>> >
>> >> >>> > Tao's condition will hit when 'get_prev_frame(this_frame=frame#13)' will
>> >> >>> > be called to get the frame #14, which will return NULL and hence break
>> >> >>> > out of the loop.
>> >> >>> >
>> >> >>> > This is based on what I recall and a quick look at the implementation,
>> >> >>> > please feel free to correct Lianbo/Tao.
>> >> >>>
>> >> >>> Thanks Aditya for the detailed inspection, which I didn't dive into.
>> >> >>> When I notice the last frame to be the userspace address, I just keep
>> >> >>> it as it is.
>> >> >>>
>> >> >>> Thanks,
>> >> >>> Tao Liu
>> >> >>>
>> >> >>>
>> >> >>> >
>> >> >>> > Thanks,
>> >> >>> > Aditya Gupta
>> >> >>> >
>> >> >>> >
>> >> >>> > >
>> >> >>> > >
>> >> >>> > > Thanks
>> >> >>> > > Lianbo
>> >> >>> > >
>> >> >>> > >
>> >> >>> > > > Cc: Sourabh Jain <sourabhjain@xxxxxxxxxxxxx>
>> >> >>> > > > Cc: Hari Bathini <hbathini@xxxxxxxxxxxxx>
>> >> >>> > > > Cc: Mahesh J Salgaonkar <mahesh@xxxxxxxxxxxxx>
>> >> >>> > > > Cc: Naveen N. Rao <naveen.n.rao@xxxxxxxxxxxxxxxxxx>
>> >> >>> > > > Cc: Lianbo Jiang <lijiang@xxxxxxxxxx>
>> >> >>> > > > Cc: HAGIO KAZUHITO(萩尾 一仁) <k-hagio-ab@xxxxxxx>
>> >> >>> > > > Cc: Tao Liu <ltao@xxxxxxxxxx>
>> >> >>> > > > Cc: Alexey Makhalov <alexey.makhalov@xxxxxxxxxxxx>
>> >> >>> > > > Signed-off-by: Tao Liu <ltao@xxxxxxxxxx>
>> >> >>> > > > ---
>> >> >>> > > >  defs.h          |  1 +
>> >> >>> > > >  gdb-10.2.patch  | 26 ++++++++++++++++++++++++++
>> >> >>> > > >  gdb_interface.c |  6 ++++++
>> >> >>> > > >  3 files changed, 33 insertions(+)
>> >> >>> > > >
>> >> >>> > > > diff --git a/defs.h b/defs.h
>> >> >>> > > > index 012ffdc..c0e6a29 100644
>> >> >>> > > > --- a/defs.h
>> >> >>> > > > +++ b/defs.h
>> >> >>> > > > @@ -7902,6 +7902,7 @@ extern unsigned char *gdb_prettyprint_arrays;
>> >> >>> > > >  extern unsigned int *gdb_repeat_count_threshold;
>> >> >>> > > >  extern unsigned char *gdb_stop_print_at_null;
>> >> >>> > > >  extern unsigned int *gdb_output_radix;
>> >> >>> > > > +int is_kvaddr(ulong);
>> >> >>> > > >
>> >> >>> > > >  /*
>> >> >>> > > >   *  gdb/top.c
>> >> >>> > > > diff --git a/gdb-10.2.patch b/gdb-10.2.patch
>> >> >>> > > > index 0bed96a..3ed40c0 100644
>> >> >>> > > > --- a/gdb-10.2.patch
>> >> >>> > > > +++ b/gdb-10.2.patch
>> >> >>> > > > @@ -16171,3 +16171,29 @@ exit 0
>> >> >>> > > >   }
>> >> >>> > > >
>> >> >>> > > >   /*
>> >> >>> > > > +--- gdb-10.2/gdb/frame.c.orig
>> >> >>> > > > ++++ gdb-10.2/gdb/frame.c
>> >> >>> > > > +@@ -2331,6 +2331,10 @@ inside_entry_func (frame_info *this_frame)
>> >> >>> > > > +    This function should not contain target-dependent tests, such as
>> >> >>> > > > +    checking whether the program-counter is zero.  */
>> >> >>> > > > +
>> >> >>> > > > ++#ifdef CRASH_MERGE
>> >> >>> > > > ++extern "C" int is_kvaddr(ulong);
>> >> >>> > > > ++#endif
>> >> >>> > > > ++
>> >> >>> > > > + struct frame_info *
>> >> >>> > > > + get_prev_frame (struct frame_info *this_frame)
>> >> >>> > > > + {
>> >> >>> > > > +@@ -2353,7 +2357,11 @@ get_prev_frame (struct frame_info *this_frame)
>> >> >>> > > > +     get_frame_id (this_frame);
>> >> >>> > > > +
>> >> >>> > > > +   frame_pc_p = get_frame_pc_if_available (this_frame, &frame_pc);
>> >> >>> > > > +-
>> >> >>> > > > ++#ifdef CRASH_MERGE
>> >> >>> > > > ++  if (!is_kvaddr(frame_pc)) {
>> >> >>> > > > ++        return NULL;
>> >> >>> > > > ++  }
>> >> >>> > > > ++#endif
>> >> >>> > > > +   /* tausq/2004-12-07: Dummy frames are skipped because it doesn't make
>> >> >>> > > > much
>> >> >>> > > > +      sense to stop unwinding at a dummy frame.  One place where a dummy
>> >> >>> > > > +      frame may have an address "inside_main_func" is on HPUX.  On HPUX,
>> >> >>> > > > the
>> >> >>> > > > diff --git a/gdb_interface.c b/gdb_interface.c
>> >> >>> > > > index b13d5fd..e76ecc6 100644
>> >> >>> > > > --- a/gdb_interface.c
>> >> >>> > > > +++ b/gdb_interface.c
>> >> >>> > > > @@ -947,6 +947,12 @@ gdb_lookup_module_symbol(ulong addr, ulong *offset)
>> >> >>> > > >         }
>> >> >>> > > >  }
>> >> >>> > > >
>> >> >>> > > > +int
>> >> >>> > > > +is_kvaddr(ulong addr)
>> >> >>> > > > +{
>> >> >>> > > > +       return IS_KVADDR(addr);
>> >> >>> > > > +}
>> >> >>> > > > +
>> >> >>> > > >  /*
>> >> >>> > > >   *  Used by gdb_interface() to catch gdb-related errors, if desired.
>> >> >>> > > >   */
>> >> >>> > > > --
>> >> >>> > > > 2.40.1
>> >> >>> > > >
>> >> >>> >
>> >> >>>
>> >>
>>
--
Crash-utility mailing list -- devel@xxxxxxxxxxxxxxxxxxxxxxxxxxx
To unsubscribe send an email to devel-leave@xxxxxxxxxxxxxxxxxxxxxxxxxxx
https://${domain_name}/admin/lists/devel.lists.crash-utility.osci.io/
Contribution Guidelines: https://github.com/crash-utility/crash/wiki




[Index of Archives]     [Fedora Development]     [Fedora Desktop]     [Fedora SELinux]     [Yosemite News]     [KDE Users]     [Fedora Tools]

 

Powered by Linux