OSDev.org

The Place to Start for Operating System Developers
It is currently Thu Mar 28, 2024 2:08 pm

All times are UTC - 6 hours




Post new topic Reply to topic  [ 5 posts ] 
Author Message
 Post subject: _Unwind_RaiseException() calls abort()
PostPosted: Tue Feb 14, 2017 12:24 pm 
Offline
Member
Member

Joined: Fri May 16, 2014 2:40 pm
Posts: 36
Currently, I'm implementing the C++ ABI (as described on http://mentorembedded.github.io/cxx-abi/) to get RTTI and Exceptions working. RTTI is working fine already, however I'm experiencing some difficulties while getting Exceptions to work.

I made a simple testcase in which I throw an integer and catch it in the function below. Compiling works just fine, and when running, allocating my exception structure + exception body works fine too. The __cxa_throw method is called correctly as well. However, in this method, **** hits the fan. To start unwinding the stack, I call _Unwind_RaiseException() with my unwindHeader as an argument. This however calls my abort function (Which is required since libgcc needs it as soon as exceptions are not disabled).

After some debugging, I think the libgcc unwinder can't find the stack frames and relating info. I read in the wiki before that when using libsupc++ (Which I'm not using), you would have to call "__register_frame(address_of_eh_frames);" to set the correct eh_frame location so that it can find the info in those frames. I'm not setting the address of the eh_frames anywhere currently, and haven't seen anything in the ABI describing this.
I also went through the sourcecode of libsupc++ to see what the __register_frame function does, but I didn't see anything interacting with the libgcc unwinder.

I also checked my compiled elf to see whether the sections are set correctly, which they seem to be:
Code:
ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0xffffffff8000dfdc
  Start of program headers:          64 (bytes into file)
  Start of section headers:          2627112 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           56 (bytes)
  Number of program headers:         4
  Size of section headers:           64 (bytes)
  Number of section headers:         20
  Section header string table index: 17

Section Headers:
  [Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
  [ 0]                   NULL             0000000000000000  00000000
       0000000000000000  0000000000000000           0     0     0
  [ 1] .text             PROGBITS         ffffffff80000000  00001000
       000000000001ba04  0000000000000000  AX       0     0     4096
  [ 2] .data             PROGBITS         ffffffff8001c000  0001d000
       00000000002135b8  0000000000000000  WA       0     0     4096
  [ 3] .bss              NOBITS           ffffffff80230000  002305b8
       00000000000027f8  0000000000000000  WA       0     0     4096
  [ 4] .eh_frame         PROGBITS         ffffffff80233000  00231000
       00000000000031a8  0000000000000000   A       0     0     4096
  [ 5] .gcc_except_table PROGBITS         ffffffff80237000  00235000
       0000000000000040  0000000000000000   A       0     0     4096
  [ 6] .init             PROGBITS         ffffffff80238000  00236000
       0000000000000010  0000000000000000  AX       0     0     4096
  [ 7] .fini             PROGBITS         ffffffff80239000  00237000
       000000000000000b  0000000000000000  AX       0     0     4096
  [ 8] .jcr              PROGBITS         ffffffff8023a000  00238000
       0000000000000008  0000000000000000  WA       0     0     4096
  [ 9] .comment          PROGBITS         0000000000000000  00238008
       0000000000000011  0000000000000001  MS       0     0     1
  [10] .debug_info       PROGBITS         0000000000000000  00238019
       000000000001df48  0000000000000000           0     0     1
  [11] .debug_abbrev     PROGBITS         0000000000000000  00255f61
       0000000000004c2d  0000000000000000           0     0     1
  [12] .debug_aranges    PROGBITS         0000000000000000  0025ab8e
       0000000000000a50  0000000000000000           0     0     1
  [13] .debug_ranges     PROGBITS         0000000000000000  0025b5de
       0000000000001c10  0000000000000000           0     0     1
  [14] .debug_line       PROGBITS         0000000000000000  0025d1ee
       00000000000056c7  0000000000000000           0     0     1
  [15] .debug_str        PROGBITS         0000000000000000  002628b5
       0000000000009387  0000000000000001  MS       0     0     1
  [16] .debug_loc        PROGBITS         0000000000000000  0026bc3c
       000000000000bb1f  0000000000000000           0     0     1
  [17] .shstrtab         STRTAB           0000000000000000  0028156c
       00000000000000bb  0000000000000000           0     0     1
  [18] .symtab           SYMTAB           0000000000000000  00277760
       0000000000005b50  0000000000000018          19   398     8
  [19] .strtab           STRTAB           0000000000000000  0027d2b0
       00000000000042bc  0000000000000000           0     0     1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),
  l (large), p (processor specific)

There are no section groups in this file.

Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  LOAD           0x0000000000001000 0xffffffff80000000 0xffffffff80000000
                 0x000000000001ba04 0x000000000001ba04  R E    1000
  LOAD           0x000000000001d000 0xffffffff8001c000 0xffffffff8001c000
                 0x00000000002135b8 0x00000000002167f8  RW     1000
  LOAD           0x0000000000231000 0xffffffff80233000 0xffffffff80233000
                 0x000000000000600b 0x000000000000600b  R E    1000
  LOAD           0x0000000000238000 0xffffffff8023a000 0xffffffff8023a000
                 0x0000000000000008 0x0000000000000008  RW     1000

Section to Segment mapping:
  Segment Sections...
   00     .text
   01     .data .bss
   02     .eh_frame .gcc_except_table .init .fini
   03     .jcr

There is no dynamic section in this file.

There are no relocations in this file.


Am I overlooking something in the ABI? Or is something missing in there? Any clues on how to get _Unwind_RaiseException() to work and start unwinding the stack (After which my personality function can take over...)?


Top
 Profile  
 
 Post subject: Re: _Unwind_RaiseException() calls abort()
PostPosted: Tue Feb 14, 2017 6:41 pm 
Offline
Member
Member
User avatar

Joined: Sun Dec 25, 2016 1:54 am
Posts: 204
In libgcc the eh_frame registration hokus-pokus is contained in

https://github.com/gcc-mirror/gcc/blob/ ... crtstuff.c

as well as

https://github.com/gcc-mirror/gcc/blob/ ... bl-ctors.h

and is intimately related to the compiler emitting proper entries in .init/.fini sections.

So just as a test I would check that things like c constructors actually work first....

Code:
char *teststring = 0;

__attribute__((constructor)) void TestMe (void)
{
teststring = "Worked!";
}

int main(int argc, char **argv)
{
printf("Message [%s]\n", teststring);
}


I did not print in the TestMe() constructor as stdout will not have been setup yet by crt0.c

If you get "Worked!" then your .init/.fini is playing nice with the compiler and likewise - with libgcc at least - the eh_frame will have been registered.

I know you said you don't use libgcc, but the control flow in the libgcc files above should give you a heads up as to how to go about it.

Good luck and cheers

_________________
Plagiarize. Plagiarize. Let not one line escape thine eyes...


Top
 Profile  
 
 Post subject: Re: _Unwind_RaiseException() calls abort()
PostPosted: Wed Feb 15, 2017 2:57 am 
Offline
Member
Member

Joined: Fri May 16, 2014 2:40 pm
Posts: 36
Thank you for responding ;)

dchapiesky wrote:
In libgcc the eh_frame registration hokus-pokus is contained in

https://github.com/gcc-mirror/gcc/blob/ ... crtstuff.c

as well as

https://github.com/gcc-mirror/gcc/blob/ ... bl-ctors.h


I've been looking into the source and I first thought that __register_frame_info was something defined in libsupc++, but I now tried calling it as an external symbol anyway, and it seems to link just fine. So I will be experimenting with it, to see if this fixes my issues.

dchapiesky wrote:
and is intimately related to the compiler emitting proper entries in .init/.fini sections.

So just as a test I would check that things like c constructors actually work first....


Constructors are working fine (both C and static C++ objects, not that it makes a difference to the compiler).

dchapiesky wrote:
If you get "Worked!" then your .init/.fini is playing nice with the compiler and likewise - with libgcc at least - the eh_frame will have been registered.

I know you said you don't use libgcc, but the control flow in the libgcc files above should give you a heads up as to how to go about it.

I am using libgcc, I'm not using libsupc++. So you're saying that the registering of eh_frame should work just fine if the .init/.fini sections are linked and run correctly?


Top
 Profile  
 
 Post subject: Re: _Unwind_RaiseException() calls abort()
PostPosted: Wed Feb 15, 2017 6:22 am 
Offline
Member
Member
User avatar

Joined: Sun Dec 25, 2016 1:54 am
Posts: 204
Well....

after looking at those two files I posted and remembering the pain....

Please let me ramble about this for a few moments and then hopefully I will have something to contribute...

Basically it goes like this...

1) elf loader loads your program
2) elf loader finds ENTRY() point - usually _start
3) _start() being in crt0.c iterates .init and calls each function pointer in the list
4) one of those entries in .init is called frame_dummy() - line 459 in crtstuff.c from libgcc - injected into .init section simply by linking attributes
5) frame_dummy() - and this is the important part - calls register_frame_info in a fashion that was configured at build time of the host gcc compiler... note the USE_EH_FRAME_REGISTRY, etc... so libgcc, and how the frame information is *generated* by the compiler are closely intertwined - thus hokus-pokus
6) in unwind_dw2-fde.c of libgcc we see __register_frame() defined at line 110 - it checks to see if eh_frame exists and does an allocation using malloc() and then calls register_frame_info() on the eh_frame pointer.

__register_frame() seems to be bone thrown to non-glibc libraries since if you grep the source code of gcc you find that the ONLY place __register_frame() is used is in its definition.

Ramble over...

In gcc.c at around 1740 we see that register_frame_info() is referenced and more hokus pokus based on compiler configuration.

So...

in gcc.c at 1763 - we see
Code:
#ifdef USE_LIBUNWIND_EXCEPTIONS


and so I would ask is your compiler configured for this?

But I worry that I am simply sending you on a wild goose chase....

So the best I think I can recommend at this point is examining the llvm project and how they do it..

https://github.com/llvm-mirror?tab=repositories

llvm.org

specifically their libunwind, libcxx, and libcxxabi libraries....

I do note that their libunwind looks for an .eh_frame_hdr section which is not shown in your first post. See https://github.com/llvm-mirror/libunwin ... Parser.hpp

Sorry I couldn't be of much better help.

_________________
Plagiarize. Plagiarize. Let not one line escape thine eyes...


Top
 Profile  
 
 Post subject: Re: _Unwind_RaiseException() calls abort()
PostPosted: Wed Feb 15, 2017 8:27 am 
Offline
Member
Member

Joined: Fri May 16, 2014 2:40 pm
Posts: 36
dchapiesky wrote:
1) elf loader loads your program
2) elf loader finds ENTRY() point - usually _start
3) _start() being in crt0.c iterates .init and calls each function pointer in the list
4) one of those entries in .init is called frame_dummy() - line 459 in crtstuff.c from libgcc - injected into .init section simply by linking attributes
5) frame_dummy() - and this is the important part - calls register_frame_info in a fashion that was configured at build time of the host gcc compiler... note the USE_EH_FRAME_REGISTRY, etc... so libgcc, and how the frame information is *generated* by the compiler are closely intertwined - thus hokus-pokus
6) in unwind_dw2-fde.c of libgcc we see __register_frame() defined at line 110 - it checks to see if eh_frame exists and does an allocation using malloc() and then calls register_frame_info() on the eh_frame pointer.

__register_frame() seems to be bone thrown to non-glibc libraries since if you grep the source code of gcc you find that the ONLY place __register_frame() is used is in its definition.



After some more examining of libgcc and libsupc++ I arrived at the same conclusions. I still tried manually registering the frame, but this didn't change anything.

dchapiesky wrote:
In gcc.c at around 1740 we see that register_frame_info() is referenced and more hokus pokus based on compiler configuration.

So...

in gcc.c at 1763 - we see
Code:
#ifdef USE_LIBUNWIND_EXCEPTIONS


and so I would ask is your compiler configured for this?


As far as I can see this is used when actually using libunwind (Which differs from the basic libgcc unwinding). It might be that I'm incorrect on this point though, I'm just touching the source of gcc for the very first time with this project.

dchapiesky wrote:
I do note that their libunwind looks for an .eh_frame_hdr section which is not shown in your first post. See https://github.com/llvm-mirror/libunwin ... Parser.hpp

Sorry I couldn't be of much better help.

That's actually a good one. I have seen the section before, but can't remember when. I'll go check whether this might be an issue.

Also, I want to thank you because you have already given me quite some pointers on what might be wrong, so don't be sorry, it's actually very usefull ;)


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 5 posts ] 

All times are UTC - 6 hours


Who is online

Users browsing this forum: Amazonbot [bot], Bing [Bot], DotBot [Bot], Majestic-12 [Bot], mrjbom and 77 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group