From: Julian Seward Date: Tue, 3 May 2005 16:05:00 +0000 (+0000) Subject: * Clean up the DWARF2 CFI reader a bit X-Git-Tag: svn/VALGRIND_3_0_0~714 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=2dec4f2a3d8f6de9b8f6dc4aa733b115d7276a2a;p=thirdparty%2Fvalgrind.git * Clean up the DWARF2 CFI reader a bit * Check that cie.ra_reg that shows up matches the RA_COL we assume * Improve debug printing a bit git-svn-id: svn://svn.valgrind.org/valgrind/trunk@3604 --- diff --git a/coregrind/vg_dwarf.c b/coregrind/vg_dwarf.c index bd344d0143..8e546ba57b 100644 --- a/coregrind/vg_dwarf.c +++ b/coregrind/vg_dwarf.c @@ -829,6 +829,42 @@ void VG_(read_debuginfo_dwarf1) ( /*--- Read call-frame info from an .eh_frame section ---*/ /*------------------------------------------------------------*/ +/* Useful info .. + + In general: + gdb-6.3/gdb/dwarf2-frame.c + + gdb-6.3/gdb/i386-tdep.c: + + DWARF2/GCC uses the stack address *before* the function call as a + frame's CFA. [jrs: I presume this means %esp before the call as + the CFA]. + + JRS: on amd64, the dwarf register numbering is, as per + gdb-6.3/gdb/tdep-amd64.c and also amd64-abi-0.95.pdf: + + 0 1 2 3 4 5 6 7 + RAX RDX RCX RBX RSI RDI RBP RSP + + 8 ... 15 + R8 ... R15 + + 16 is the return address (RIP) + + This is pretty strange given this not the encoding scheme for + registers used in amd64 code. + + On x86 I cannot find any documentation. It _appears_ to be the + actual instruction encoding, viz: + + 0 1 2 3 4 5 6 7 + EAX ECX EDX EBX ESP EBP ESI EDI + + 8 is the return address (EIP) */ + + +/* ------------ Deal with summary-info records ------------ */ + void VG_(ppCfiSI) ( CfiSI* si ) { # define SHOW_HOW(_how, _off) \ @@ -879,35 +915,7 @@ static void initCfiSI ( CfiSI* si ) } -/* Useful info .. - - gdb-6.3/gdb/i386-tdep.c: - - DWARF2/GCC uses the stack address *before* the function call as a - frame's CFA. [jrs: I presume this means %esp before the call as - the CFA]. - - JRS: on amd64, the dwarf register numbering is, as per - gdb-6.3/gdb/tdep-amd64.c and also amd64-abi-0.95.pdf: - - 0 1 2 3 4 5 6 7 - RAX RDX RCX RBX RSI RDI RBP RSP - - 8 ... 15 - R8 ... R15 - - 16 is the return address (RIP) - - This is pretty strange given this not the encoding scheme for - registers used in amd64 code. - - On x86 I cannot find any documentation. It _appears_ to be the - actual instruction encoding, viz: - - 0 1 2 3 4 5 6 7 - EAX ECX EDX EBX ESP EBP ESI EDI - - 8 is the return address (EIP) */ +/* --------------- Decls --------------- */ #if defined(VGP_x86_linux) #define FP_COL 5 @@ -976,10 +984,16 @@ enum dwarf_cfa_secondary_ops #define DW_EH_PE_indirect 0x80 +/* RegRule and UnwindContext are used temporarily to do the unwinding. + The result is then summarised into a CfiSI, if possible. */ + typedef struct { enum { RR_Undef, RR_Same, RR_CFAoff, RR_Reg, RR_Arch } tag; + /* Note, .coff and .reg are never both in use. Therefore could + merge them into one. */ + /* CFA offset if tag==RR_CFAoff */ Int coff; @@ -988,6 +1002,19 @@ typedef } RegRule; +static void ppRegRule ( RegRule* reg ) +{ + switch (reg->tag) { + case RR_Undef: VG_(printf)("u "); break; + case RR_Same: VG_(printf)("s "); break; + case RR_CFAoff: VG_(printf)("c%d ", reg->coff); break; + case RR_Reg: VG_(printf)("r%d ", reg->reg); break; + case RR_Arch: VG_(printf)("a "); break; + default: VG_(core_panic)("ppRegRule"); + } +} + + typedef struct { /* Read-only fields. */ @@ -1006,6 +1033,16 @@ typedef } UnwindContext; +static void ppUnwindContext ( UnwindContext* ctx ) +{ + Int i; + VG_(printf)("0x%llx: ", (ULong)ctx->loc); + VG_(printf)("%d(r%d) ", ctx->cfa_offset, ctx->cfa_reg); + for (i = 0; i < N_CFI_REGS; i++) + ppRegRule(&ctx->reg[i]); + VG_(printf)("\n"); +} + static void initUnwindContext ( /*OUT*/UnwindContext* ctx ) { Int i; @@ -1021,29 +1058,8 @@ static void initUnwindContext ( /*OUT*/UnwindContext* ctx ) } } -static void ppRegRule ( RegRule* reg ) -{ - switch (reg->tag) { - case RR_Undef: VG_(printf)("u "); break; - case RR_Same: VG_(printf)("s "); break; - case RR_CFAoff: VG_(printf)("c%d ", reg->coff); break; - case RR_Reg: VG_(printf)("r%d ", reg->reg); break; - case RR_Arch: VG_(printf)("a "); break; - default: VG_(core_panic)("ppRegRule"); - } -} - - -static void ppUnwindContext ( UnwindContext* ctx ) -{ - Int i; - VG_(printf)("0x%llx: ", (ULong)ctx->loc); - VG_(printf)("%d(r%d) ", ctx->cfa_offset, ctx->cfa_reg); - for (i = 0; i < N_CFI_REGS; i++) - ppRegRule(&ctx->reg[i]); - VG_(printf)("\n"); -} +/* --------------- Summarisation --------------- */ /* Summarise ctx into si, if possible. Returns True if successful. This is taken to be just after ctx's loc advances; hence the @@ -1110,9 +1126,12 @@ static Bool summarise_context( /*OUT*/CfiSI* si, return True; failed: - VG_(printf)("summarise_context(loc_start = %p)" - ": cannot summarise(why=%d):\n ", loc_start, why); - ppUnwindContext(ctx); + if (VG_(clo_verbosity) > 1) { + VG_(message)(Vg_DebugMsg, + "summarise_context(loc_start = %p)" + ": cannot summarise(why=%d): ", loc_start, why); + ppUnwindContext(ctx); + } return False; } @@ -1137,6 +1156,9 @@ static void ppUnwindContext_summary ( UnwindContext* ctx ) VG_(printf)("\n"); } + +/* ------------ Pick apart DWARF2 byte streams ------------ */ + static inline Bool host_is_little_endian ( void ) { UInt x = 0x76543210; @@ -1144,7 +1166,6 @@ static inline Bool host_is_little_endian ( void ) return toBool(*p == 0x10); } - static Short read_Short ( UChar* data ) { vg_assert(host_is_little_endian()); @@ -1217,11 +1238,11 @@ static ULong read_ULong ( UChar* data ) static Addr read_Addr ( UChar* data ) { - if (sizeof(Addr) == 4) - return read_UInt(data); - else if (sizeof(Addr) == 8) - return read_ULong(data); - vg_assert(0); +# if VG_WORDSIZE == 4 + return read_UInt(data); +# else + return read_ULong(data); +# endif } static UChar read_UChar ( UChar* data ) @@ -1320,6 +1341,8 @@ static Addr read_encoded_Addr ( UChar* data, UChar encoding, Int *nbytes, } +/* ------------ Run/show CFI instructions ------------ */ + /* Run a CFI instruction, and also return its length. Returns 0 if the instruction could not be executed. */ @@ -1440,7 +1463,8 @@ static Int run_CF_instruction ( /*MOD*/UnwindContext* ctx, break; default: - VG_(printf)("Unhandled CFI instruction 0:%d\n", (Int)lo6); + VG_(message)(Vg_DebugMsg, "DWARF2 CFI reader: unhandled CFI " + "instruction 0:%d", (Int)lo6); i = 0; break; } @@ -1450,6 +1474,7 @@ static Int run_CF_instruction ( /*MOD*/UnwindContext* ctx, /* Show a CFI instruction, and also return its length. */ + static Int show_CF_instruction ( UChar* instr ) { UInt delta; @@ -1611,8 +1636,11 @@ Bool run_CF_instructions ( SegInfo* si, } +/* ------------ Main entry point for CFI reading ------------ */ + void VG_(read_callframe_info_dwarf2) - ( /*OUT*/SegInfo* si, UChar* ehframe, Int ehframe_sz, Addr ehframe_addr ) + ( /*OUT*/SegInfo* si, + UChar* ehframe, Int ehframe_sz, Addr ehframe_addr ) { UnwindContext ctx, restore_ctx; Int nbytes; @@ -1718,6 +1746,10 @@ void VG_(read_callframe_info_dwarf2) UChar cie_rareg = read_UChar(data); data += sizeof(UChar); if (VG_(clo_trace_cfi)) VG_(printf)("cie.ra_reg = %d\n", (Int)cie_rareg); + if (cie_rareg != RA_COL) { + how = "cie.ra_reg does not match RA_COL"; + goto bad; + } saw_z_augmentation = *cie_augmentation == 'z'; if (saw_z_augmentation) { diff --git a/coregrind/vg_symtab2.c b/coregrind/vg_symtab2.c index dfd82a90bc..20c07783e7 100644 --- a/coregrind/vg_symtab2.c +++ b/coregrind/vg_symtab2.c @@ -391,9 +391,19 @@ void VG_(addCfiSI) ( SegInfo* si, CfiSI* cfisi ) them. */ if ( cfisi->base + cfisi->len - 1 < si->start || si->start + si->size - 1 < cfisi->base ) { - if (VG_(clo_trace_cfi)) { - VG_(printf)("CfiSI outside segment: "); - VG_(ppCfiSI)(cfisi); + static Int complaints = 3; + if (VG_(clo_trace_cfi) || complaints > 0) { + complaints--; + VG_(message)( + Vg_DebugMsg, + "warning: CfiSI %p .. %p outside segment %p .. %p", + cfisi->base, + cfisi->base + cfisi->len - 1, + si->start, + si->start + si->size - 1 + ); + if (VG_(clo_trace_cfi)) + VG_(ppCfiSI)(cfisi); } return; } @@ -1709,7 +1719,7 @@ Bool read_lib_symbols ( SegInfo* si ) } /* Read .eh_frame (call-frame-info) if any */ - if (ehframe && ehframe_sz > 4) { + if (ehframe) { VG_(read_callframe_info_dwarf2) ( si, ehframe, ehframe_sz, ehframe_addr ); }