I was just wondering if there is anyone out there in redhat land who can shed more light on the use of dwarf register 16 for a virtual "return address" in .eh_frame info, probably hand generated .eh_frame info in the vicinity of the pthreads library mutex locking code.
It is briefly mentioned in one place in the x86_64 abi with no clue as to how it is used. Google finds zillions of patches where it was inserted in the library, but no actual explanation.
The .eh_frame dumps of the pthread library via readelf make no sense to me at all.
And it will clearly take me at least 15 years to trace through the code in gdb and figure out what it actually does, so if anyone out there knows, please tell me :-).
On Tue, May 19, 2009 at 11:40:54AM -0400, Tom Horsley wrote:
I was just wondering if there is anyone out there in redhat land who can shed more light on the use of dwarf register 16 for a virtual "return address" in .eh_frame info, probably hand generated .eh_frame info in the vicinity of the pthreads library mutex locking code.
Does http://sources.redhat.com/ml/libc-hacker/2006-09/msg00003.html http://gcc.gnu.org/ml/gcc-patches/2006-03/msg00208.html shed some light? The lock spinning pads are in inline asm in separate subsections (as they are unlikely) and at least before GCC started using .cfi_* directives for eh it was impossible to write inline assembly with code in separate sections/subsections that preserved usable unwind info. The GCC patch as examples in the testcase contains both older version which disassembled the instructions in the pad and computed virtual return address to the spot that branched to the pad (and pad branched to at the end) and the actually used version.
Jakub
On Tue, 19 May 2009 18:24:52 +0200 Jakub Jelinek wrote:
The GCC patch as examples in the testcase contains both older version which disassembled the instructions in the pad and computed virtual return address to the spot that branched to the pad (and pad branched to at the end) and the actually used version.
Maybe it sheds some light :-). I had sort of been developing the theory that the stuff I was looking at was trying to describe a frame that is not exactly a frame, but just some inline code (is that what a "pad" is?), but I still haven't been able to make any actual sense of the .eh_frame dumps from readelf (maybe readelf is broken?). For example, trying to walkback from inside a pthread_mutex_lock call, I find this CIE/FDE combo:
000000b8 00000014 00000000 CIE Version: 1 Augmentation: "zR" Code alignment factor: 1 Data alignment factor: -8 Return address column: 16 Augmentation data: 1b <= encoding used by addresses in fde (pc relative, signed 4 bytes)
DW_CFA_def_cfa_sf: r7 (rsp) ofs -128 DW_CFA_nop DW_CFA_nop DW_CFA_nop DW_CFA_nop
00001370 0000004c 000012bc FDE cie=000000b8 pc=31906091a1..31906091bc <<==frame1 DW_CFA_val_expression: r16 (rip) (DW_OP_breg16: 15) DW_CFA_advance_loc: 3 to 31906091a4 DW_CFA_val_expression: r16 (rip) (DW_OP_breg16: 12) DW_CFA_advance_loc: 7 to 31906091ab DW_CFA_def_cfa_offset: 0 DW_CFA_val_expression: r16 (rip) (DW_OP_breg16: 5) DW_CFA_advance_loc: 4 to 31906091af DW_CFA_def_cfa_offset: 128 DW_CFA_val_expression: r16 (rip) (DW_OP_breg16: 6; DW_OP_const4s: -42046; DW_OP_minus; DW_OP_const4s: -43862; DW_OP_plus) DW_CFA_advance_loc: 8 to 31906091b7 DW_CFA_def_cfa_offset_sf: -128 DW_CFA_val_expression: r16 (rip) (DW_OP_breg16: -7) DW_CFA_nop DW_CFA_nop DW_CFA_nop DW_CFA_nop DW_CFA_nop DW_CFA_nop
It appears to be defining register 16 by using register 16 as a base register, with no initial definition of register 16 provided in the CIE, then there is the really complex expression for the instruction I'm actually trying to walkback through at 31906091af - my brain just sort of shuts down when I try to understand this stuff :-).
Perhaps I should go look at the actual pthread source code that matches the version loaded on my system, it might make more sense when I see it with some context around it.
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
Tom Horsley wrote:
I was just wondering if there is anyone out there in redhat land who can shed more light on the use of dwarf register 16 for a virtual "return address" in .eh_frame info, probably hand generated .eh_frame info in the vicinity of the pthreads library mutex locking code.
This has nothing to do with hand-generated or not. The debug and exception handling information has to contain information on how to find the return address at any point in the program. In Dwarf this is best done by expressing the return address as a register, even if it is not a register on real hardware. r16 is that register for x86 and the DWARF info describes how to find it.
The .eh_frame dumps of the pthread library via readelf make no sense to me at all.
Then nothing I explain will make any sense. You'll have to understand how DWARF allows to describe a "program" to recover register content etc.
For r16 it starts usually with
offset r16 (rip) at cfa-8
Which means the value is at offset -8 from the call frame register. This is defined as well in the same block. In short, this points at the beginning of the function to the most recently pushed value on the stack. Later modifications of the stack pointer have to be accompanied by appropriate adjustments of the CFA and therefore the return address can always be found.
It is possibly to load the return address into a register. At that point the unwind program would contain an entry like
cfi_register rip rax
or so.
It's really all pretty simple, just read the DWARF specification.
- -- ➧ Ulrich Drepper ➧ Red Hat, Inc. ➧ 444 Castro St ➧ Mountain View, CA ❖
On Thu, 21 May 2009 09:25:20 -0700 Ulrich Drepper wrote:
It's really all pretty simple, just read the DWARF specification.
I've read the dwarf spec, I've even written dwarf reader code, what I can't figure out is the specific frame descriptions in the pthread library. The main problem being that reg16 is defined in terms of reg16, and no initial value is given in the CIE entry for what reg16 starts with :-). I've tried working backward from the expressions given to evaluate it, and the value I have to start with for the arithmetic in the frame to produce the correct result makes no sense at all. It isn't anything like any value that I can imagine comes from any place in the vicinity of the code I'm looking at. I even have a vague idea what the fanatical macro defs for these little "inline" routines are trying to accomplish, I just can't make the arithmetic work.
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
Tom Horsley wrote:
I've read the dwarf spec, I've even written dwarf reader code, what I can't figure out is the specific frame descriptions in the pthread library.
You don't give any kind of details so you cannot get help. If you find a problem with the frame info file a bug. But be sure it's a problem.
- -- ➧ Ulrich Drepper ➧ Red Hat, Inc. ➧ 444 Castro St ➧ Mountain View, CA ❖
On Thu, 21 May 2009 10:34:18 -0700 Ulrich Drepper wrote:
You don't give any kind of details so you cannot get help. If you find a problem with the frame info file a bug. But be sure it's a problem.
Its obviously not a problem, since gdb can walkback through the frame in question, I just can't figure out what implicit undocumented information gdb must be using to initialize the process of interpreting the frame info. Specifically the bizarre little macros such as lll_lock() from nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.h which have the hand coded frame descriptions from the LLL_STUB_UNWIND_INFO_5 macro (and similar friends).
Someday I'll find a good place to set a breakpoint in gdb itself so I can step through the algorithm (since gdb is actually the only standard "document" that matters), but just finding that place is a task akin to cleaning the Augean stables :-).
On Thu, 21 May 2009 13:49:16 -0400 Tom Horsley wrote:
Its obviously not a problem, since gdb can walkback through the frame in question, I just can't figure out what implicit undocumented information gdb must be using to initialize the process of interpreting the frame info.
DOH! I finally figured it out. One of my early guesses was actually correct, but I apparently made a cut & paste error when plugging the numbers into a calculator, so decided it didn't make any sense.
The unspecified initial value for reg16 is the value of the PC in the current frame (the most obvious guess, and the first thing I tried, if only I had done the arithmetic correctly, I wouldn't have gotten so confused :-).