How to generate meaningfull stacktraces with RTEMS on the Leon3
Jan Sommer
soja-lists at aries.uberspace.de
Tue Dec 13 07:26:13 UTC 2016
Ok,
in the end it was easier than expected.
Writing a new bsp_spurious_initialize function will override the default one, so that I can register my custom spurious handler.
Sometimes the trap handler will cause a new trap if it dereferences addresses after reaching the end of the callstack, but that is not a real problem.
In case it might help someone else at some point, here is my custom trap handler:
rtems_isr bsp_spurious_handler(
rtems_vector_number trap,
CPU_Interrupt_frame *isf
)
{
// Flush register windows (in RTEMS this is handled by user trap 0x83)
asm volatile ("ta 0x3");
// Save the current stackpointer
uint32_t* sp;
asm volatile ("\t mov %%sp, %0" : "=r"(sp));
uint32_t real_trap;
real_trap = SPARC_REAL_TRAP_NUMBER(trap);
printk("====== Unexpected trap (0x%02x) at address 0x%08x" , real_trap, isf->tpc);
switch (real_trap)
{
/*
* First the ones defined by the basic architecture
*/
case 0x00:
printk( "(reset) ======\n" );
break;
case 0x01:
printk( "(instruction access exception) ======\n" );
break;
case 0x02:
printk( "(illegal instruction) ======\n" );
break;
case 0x03:
printk( "(privileged instruction) ======\n" );
break;
case 0x04:
printk( "(fp disabled) ======\n" );
break;
case 0x07:
printk( "(memory address not aligned) ======\n" );
break;
case 0x08:
printk( "(fp exception) ======\n" );
break;
case 0x09:
printk( "(data access exception) ======\n");
break;
case 0x0A:
printk( "(tag overflow) ======\n" );
break;
default:
printk(" ======\n");
break;
}
printk("#0: Trap address: 0x%08x\n", isf->tpc);
for (int i=1; i<10; ++i)
{
printk("#%d: return: 0x%08x, arg1: 0x%08x, arg2: 0x%08x, arg3: 0x%08x\n",
i,
sp[15], // Return address
sp[ 8], // i0
sp[ 9], // i1
sp[10] // i2
);
sp = (uint32_t*) (*(sp+14));
}
printk("====== End of backtrace ======\n");
printk("Use \"cut -d: -f3 <<trace.txt>> | addr2line -C -f -e <<elf>>\" to get symbol names.\n");
asm volatile( "mov 1, %g1; ta 0x0" );
}
Best regards,
Jan
On Montag, 12. Dezember 2016 14:44:23 CET Jan Sommer wrote:
> Hello,
>
> thank you for all your help.
> It took some time to read into the sparc specifics, but I think I
> understand enough of the deatils know.
> So far I managed to flush the register windows by creating a trap 0x83
> and could properly walk the
> callstack upwards from within a function.
>
> I will have to check if I can initiate the trap from within a trap
> handler too and how to get the correct frame pointer at the beginning.
>
> I was wondering if there is a proper way to determine when I have
> reached the beginning of the stack and stop the unwinding. So far I just
> unwind 10 times and afterwards ignore the bogus addresses which may
> appear at some point.
>
> And is there an easy way to replace the bsp_spurious_handler with an own
> implementation without recompiling the BSP?
> It doesn't seem to be marked weakly linked.
>
> One last question: What does tpc stand for in the
> CPU_Minimum_stack_frame-struct which is used by the handler-function? I
> first thought it's the trap program counter, but this register seems to
> be new in sparcV9 whereas the leon is sparcV8 (The documentation only
> says "This is the offset of the tpc register on an ISF.").
>
> Best regards,
>
> Jan
>
>
>
> Am 2016-12-08 08:39, schrieb Jiri Gaisler:
> > Remember that on SPARC (leon3), parts of the stack will be cached in
> > the
> > register file windows. Printing the backtrace by following the
> > stack/frame pointers will then not work unless all windows are first
> > flushed to memory. This is done automatically on high-level O/S (Linux
> > &
> > Solaris), but not on embedded systems like RTEMS.
> >
> > Jiri.
> >
> > On 07/12/16 13:30, Matthew J Fletcher wrote:
> >> Hi,
> >>
> >> The gcc builtin functions (and libunwind) and only work if the stack
> >> frame information is not optimised away, this is controlled by gcc
> >> compiler flags,
> >> see; https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html
> >> -fomit-frame-pointer
> >>
> >> Without that you have to do your own unwinding, for example on x86 you
> >> could do the following, but its pretty crude. Linux/FreeBSD do much
> >> more fancy unwinders, it depends on what you want.
> >>
> >> #define get_ebp() \
> >> ({ unsigned long __value; \
> >> asm volatile (" mov %%ebp,%0": "=a"(__value)); \
> >> __value; })
> >>
> >> void error_dump_callstack(int fd)
> >> {
> >> unsigned longebp=0,arg0,arg4,arg8,arg12,arg16;
> >> int i;
> >>
> >> arg0 = get_ebp(); // base pointer, start of current stack frame
> >>
> >> assert_out(fd,"\r\nCall Stack Information:\r\n\r\n");
> >> for (i=0; i<15; i++)
> >> {
> >> // attempt get backtrace (with arguments) from stored EPB
> >> arg0 = *(unsigned long*)(arg0);
> >>
> >> if (arg0 == 0)
> >> break;
> >>
> >> // print stackframe back past inturrupt
> >> arg0 = *(unsigned long*)(arg0);
> >> arg4 = *(unsigned long*)(arg0+4);
> >> arg8 = *(unsigned long*)(arg0+8);
> >> arg12 = *(unsigned long*)(arg0+12);
> >> arg16 = *(unsigned long*)(arg0+16);
> >> sprintf(assertbuffer,"ebp: %p\r\nframe%d: %p\r\narg1:
> >> %p\r\narg2: %p\r\narg3: %p\r\n",arg0,i,arg4,arg8,arg12,arg16);
> >> assert_out(fd,assertbuffer);
> >> }
> >> assert_out(fd,"use 'addr2line -C -e abc.elf -f address' to get symbol
> >> names\r\n");
> >> }
> >>
> >>
> >>
> >>
> >>
> >> On 6 December 2016 at 22:36, Chris Johns <chrisj at rtems.org
> >> <mailto:chrisj at rtems.org>> wrote:
> >>
> >> On 06/12/2016 01:46, Jan Sommer wrote:
> >>
> >> Is there a common way how to create stacktraces in RTEMS?
> >>
> >>
> >> Not that I know of.
> >>
> >> I tried to use the _Unwind_Backtrace_-function from gcc, but
> >> so far it
> >> only returns _URC_END_OF_STACK if I call it from a leaf
> >> function
> >> (haven't tried a trap handler yet).
> >>
> >>
> >> The end of stack code means the unwinder could not find any data
> >> about the frames in the stack. The default DWARF unwinder, which
> >> SPARC uses, searches for a valid Frame Description Entry (FDE) and
> >> if not found reports the end of stack code. If an FDE is found the
> >> Common Information Entry (CIE) is extracted from that data and the
> >> frame info decoded.
> >>
> >> C++ uses the same process for exceptions. A .eh_frame plus some
> >> other sections are created and the frames effected by the
> >> exceptions added to these sections. These sections are registered
> >> at start up. For a DWARF unwinder, which includes the SPARC, the
> >> DWARF standard is used for the format of these sections.
> >>
> >> I am not sure if that is the way to go.
> >>
> >>
> >> I am not 100% sure myself. I think you would need to include some
> >> level of DWARF related information in the executable to do this.
> >> This information would need to be registered with the DWARF
> >> unwinder code via something like 'void __register_frame (void
> >> *begin)'.
> >>
> >> I would also take a look at FreeBSD and see how they implement the
> >> unwinder. I do not know if the FreeBSD kernel has one.
> >>
> >> Are there any recommendations or examples for this topic?
> >>
> >>
> >> The DWARF standard website is the best source of info:
> >>
> >> http://dwarfstd.org/
> >>
> >> Chris
> >>
> >> _______________________________________________
> >> users mailing list
> >> users at rtems.org <mailto:users at rtems.org>
> >> http://lists.rtems.org/mailman/listinfo/users
> >> <http://lists.rtems.org/mailman/listinfo/users>
> >>
> >>
> >>
> >>
> >> --
> >>
> >> regards
> >> ---
> >> Matthew J Fletcher
> >>
> >>
> >>
> >> _______________________________________________
> >> users mailing list
> >> users at rtems.org
> >> http://lists.rtems.org/mailman/listinfo/users
> >
> >
> > _______________________________________________
> > users mailing list
> > users at rtems.org
> > http://lists.rtems.org/mailman/listinfo/users
> _______________________________________________
> users mailing list
> users at rtems.org
> http://lists.rtems.org/mailman/listinfo/users
>
More information about the users
mailing list