Author: sewardj Date: 2008-02-23 11:57:51 +0000 (Sat, 23 Feb 2008) New Revision: 7435
Log: When reading variable & formal parameter DIEs, distinguish between abstract and concrete instances, so that we can successfully recover variable information for functions that have been inlined. Modified: branches/DATASYMS/coregrind/m_debuginfo/readdwarf3.c Modified: branches/DATASYMS/coregrind/m_debuginfo/readdwarf3.c =================================================================== --- branches/DATASYMS/coregrind/m_debuginfo/readdwarf3.c 2008-02-22 01:19:49 UTC (rev 7434) +++ branches/DATASYMS/coregrind/m_debuginfo/readdwarf3.c 2008-02-23 11:57:51 UTC (rev 7435) @@ -109,7 +109,9 @@ /*------------------------------------------------------------*/ -/*--- The "new" DWARF3 reader ---*/ +/*--- ---*/ +/*--- Basic machinery for parsing DIEs. ---*/ +/*--- ---*/ /*------------------------------------------------------------*/ #define TRACE_D3(format, args...) \ @@ -304,6 +306,35 @@ } +/* Read a DWARF3 'Initial Length' field */ +static ULong get_Initial_Length ( /*OUT*/Bool* is64, + Cursor* c, + HChar* barfMsg ) +{ + ULong w64; + UInt w32; + *is64 = False; + w32 = get_UInt( c ); + if (w32 >= 0xFFFFFFF0 && w32 < 0xFFFFFFFF) { + c->barf( barfMsg ); + } + else if (w32 == 0xFFFFFFFF) { + *is64 = True; + w64 = get_ULong( c ); + } else { + *is64 = False; + w64 = (ULong)w32; + } + return w64; +} + + +/*------------------------------------------------------------*/ +/*--- ---*/ +/*--- "CUConst" structure ---*/ +/*--- ---*/ +/*------------------------------------------------------------*/ + #define N_ABBV_CACHE 32 /* Holds information that is constant through the parsing of a @@ -354,53 +385,12 @@ CUConst; -/* Read a DWARF3 'Initial Length' field */ -static ULong get_Initial_Length ( /*OUT*/Bool* is64, - Cursor* c, - HChar* barfMsg ) -{ - ULong w64; - UInt w32; - *is64 = False; - w32 = get_UInt( c ); - if (w32 >= 0xFFFFFFF0 && w32 < 0xFFFFFFFF) { - c->barf( barfMsg ); - } - else if (w32 == 0xFFFFFFFF) { - *is64 = True; - w64 = get_ULong( c ); - } else { - *is64 = False; - w64 = (ULong)w32; - } - return w64; -} +/*------------------------------------------------------------*/ +/*--- ---*/ +/*--- Helper functions for Guarded Expressions ---*/ +/*--- ---*/ +/*------------------------------------------------------------*/ - -/* Denotes an address range. Both aMin and aMax are included in the - range; hence a complete range is (0, ~0) and an empty range is any - (X, X-1) for X > 0.*/ -typedef - struct { Addr aMin; Addr aMax; } - AddrRange; - -static XArray* unitary_range_list ( Addr aMin, Addr aMax ) { - XArray* xa; - AddrRange pair; - vg_assert(aMin <= aMax); - /* Who frees this xa? varstack_preen() does. */ - xa = VG_(newXA)( ML_(dinfo_zalloc), ML_(dinfo_free), - sizeof(AddrRange) ); - pair.aMin = aMin; - pair.aMax = aMax; - VG_(addToXA)( xa, &pair ); - return xa; -} - -////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////// -/// begin GUARDED EXPRESSIONS - /* Parse the location list starting at img-offset 'debug_loc_offset' in .debug_loc. Results are biased with 'svma_of_referencing_CU' and so I believe are correct SVMAs for the object as a whole. This @@ -628,10 +618,21 @@ return gx; } -/// end GUARDED EXPRESSIONS -////////////////////////////////////////////////////////////////// -////////////////////////////////////////////////////////////////// +/*------------------------------------------------------------*/ +/*--- ---*/ +/*--- Helper functions for range lists and CU headers ---*/ +/*--- ---*/ +/*------------------------------------------------------------*/ + +/* Denotes an address range. Both aMin and aMax are included in the + range; hence a complete range is (0, ~0) and an empty range is any + (X, X-1) for X > 0.*/ +typedef + struct { Addr aMin; Addr aMax; } + AddrRange; + + __attribute__((noinline)) static XArray* /* of AddrRange */ empty_range_list ( void ) { @@ -643,6 +644,21 @@ } +static XArray* unitary_range_list ( Addr aMin, Addr aMax ) +{ + XArray* xa; + AddrRange pair; + vg_assert(aMin <= aMax); + /* Who frees this xa? varstack_preen() does. */ + xa = VG_(newXA)( ML_(dinfo_zalloc), ML_(dinfo_free), + sizeof(AddrRange) ); + pair.aMin = aMin; + pair.aMax = aMax; + VG_(addToXA)( xa, &pair ); + return xa; +} + + /* Enumerate the address ranges starting at img-offset 'debug_ranges_offset' in .debug_ranges. Results are biased with 'svma_of_referencing_CU' and so I believe are correct SVMAs for the @@ -979,28 +995,29 @@ } -///////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////// -// Variable location parser +/*------------------------------------------------------------*/ +/*--- ---*/ +/*--- Parsing of variable-related DIEs ---*/ +/*--- ---*/ +/*------------------------------------------------------------*/ typedef struct _TempVar { struct _TempVar* next; - UChar* name; /* in AR_DINFO */ - Addr pcMin; - Addr pcMax; - Int level; - Type* typeR; - GExpr* gexpr; /* for this variable */ - GExpr* fbGX; /* to find the frame base of the enclosing fn, if - any */ - UChar* fName; /* declaring file name, or NULL */ - Int fLine; /* declaring file line number, or zero */ - /* offset in .debug_info (for debug printing only). NB: - approximate value ONLY! NOT TO BE RELIED ON. Is only stored - so as to help readers make sense of the debug printed - output. */ - UWord dioff; + UChar* name; /* in DebugInfo's .strchunks */ + XArray* ranges; /* of AddrRange. UNIQUE PTR in AR_DINFO. */ + Int level; + Type* typeR; + GExpr* gexpr; /* for this variable */ + GExpr* fbGX; /* to find the frame base of the enclosing fn, if + any */ + UChar* fName; /* declaring file name, or NULL */ + Int fLine; /* declaring file line number, or zero */ + /* offset in .debug_info, so that abstract instances can be + found to satisfy references from concrete instances. */ + UWord dioff; + UWord absOri; /* so the absOri fields refer to dioff fields + in some other, related TempVar. */ } TempVar; @@ -1410,7 +1427,7 @@ Bool external = False; GExpr* gexpr = NULL; Int n_attrs = 0; - Bool has_abs_ori = False; + UWord abs_ori = (UWord)D3_INVALID_CUOFF; Bool declaration = False; Int lineNo = 0; UChar* fileName = NULL; @@ -1440,7 +1457,7 @@ external = True; } if (attr == DW_AT_abstract_origin && ctsSzB > 0) { - has_abs_ori = True; + abs_ori = (UWord)cts; } if (attr == DW_AT_declaration && ctsSzB > 0 && cts > 0) { declaration = True; @@ -1459,25 +1476,31 @@ if (0) VG_(printf)("XXX filename = %s\n", fileName); } } - /* We'll collect it if it has a type and a location. Doesn't - even have to have a name. */ - if (gexpr && typeR != D3_INVALID_CUOFF) { - /* Add this variable to the set of variables associated with - each address range at the top of the stack. */ - GExpr* fbGX = NULL; - Word i; - XArray* /* of AddrRange */ xa; + /* We'll collect it under if one of the following three + conditions holds: + (1) has location and type -> completed + (2) has type only -> is an abstract instance + (3) has location and abs_ori -> is a concrete instance + Name, filename and line number are all option frills. + */ + if ( /* 1 */ (gexpr && typeR != D3_INVALID_CUOFF) + /* 2 */ || (typeR != D3_INVALID_CUOFF) + /* 3 */ || (gexpr && abs_ori != (UWord)D3_INVALID_CUOFF) ) { + + /* Add this variable to the list of interesting looking + variables. Crucially, note along with it the address + range(s) associated with the variable, which for locals + will be the address ranges at the top of the varparser's + stack. */ + GExpr* fbGX = NULL; + Word i; + XArray* /* of AddrRange */ xa; + TempVar* tv; /* Stack can't be empty; we put a dummy entry on it for the entire address range before starting with the DIEs for this CU. */ vg_assert(parser->sp >= 0); - if (!name) - name = ML_(addStr)( - cc->di, dtag == DW_TAG_variable - ? "<anon_variable>" - : "<anon_formal>", -1 ); - /* If this is a local variable (non-external), try to find the GExpr for the DW_AT_frame_base of the containing function. It should have been pushed on the stack at the @@ -1505,7 +1528,13 @@ "warning: parse_var_DIE: non-external variable " "outside DW_TAG_subprogram"); } - // FIXME goto bad_DIE; + /* goto bad_DIE; */ + /* This seems to happen a lot. Just ignore it -- if, + when we come to evaluation of the location (guarded) + expression, it requires a frame base value, and + there's no expression for that, then evaluation as a + whole will fail. Harmless - a bit of a waste of + cycles but nothing more. */ } } @@ -1515,30 +1544,29 @@ address space. It is asserted elsewhere that level 0 always covers the entire address space. */ xa = parser->ranges[external ? 0 : parser->sp]; - for (i = 0; i < VG_(sizeXA)( xa ); i++) { - AddrRange* r = (AddrRange*) VG_(indexXA)( xa, i ); - TempVar* tv = ML_(dinfo_zalloc)( sizeof(TempVar) ); - tv->name = name; - tv->pcMin = r->aMin; - tv->pcMax = r->aMax; - tv->level = external ? 0 : parser->sp; - tv->typeR = typeR; - tv->gexpr = gexpr; - tv->fbGX = fbGX; - tv->fName = fileName; - tv->fLine = lineNo; - tv->next = *tempvars; - tv->dioff = saved_die_c_offset - 2; /* NB! NOT EXACT! */ - *tempvars = tv; - } + tv = ML_(dinfo_zalloc)( sizeof(TempVar) ); + tv->name = name; + tv->ranges = xa; + tv->level = external ? 0 : parser->sp; + tv->typeR = typeR; + tv->gexpr = gexpr; + tv->fbGX = fbGX; + tv->fName = fileName; + tv->fLine = lineNo; + tv->dioff = posn; + tv->absOri = abs_ori; + tv->ranges = VG_(cloneXA)( xa ); /* free when 'tv' freed */ + + tv->next = *tempvars; + *tempvars = tv; + TRACE_D3(" Recording this variable, with %ld PC range(s)\n", VG_(sizeXA)(xa) ); } -#if 0 - else - if ((dtag == DW_TAG_variable || dtag == DW_TAG_formal_parameter) - && name && typeR != D3_INVALID_CUOFF && !gexpr) { - /* We have a variable with a name and a type, but no + + /* Here are some other weird cases seen in the wild: + + We have a variable with a name and a type, but no location. I guess that's a sign that it has been optimised away. Ignore it. Here's an example: @@ -1556,13 +1584,10 @@ DW_AT_type : <5d3> whereas n1 and n2 do have locations specified. - */ - /* ignore */ - } - else - if (dtag == DW_TAG_formal_parameter - && typeR != D3_INVALID_CUOFF && !name && !gexpr) { - /* We see a DW_TAG_formal_parameter with a type, but + + --------------------------------------------- + + We see a DW_TAG_formal_parameter with a type, but no name and no location. It's probably part of a function type construction, thusly, hence ignore it: <1><2b4>: Abbrev Number: 12 (DW_TAG_subroutine_type) @@ -1573,67 +1598,47 @@ DW_AT_type : <13e> <2><2c3>: Abbrev Number: 13 (DW_TAG_formal_parameter) DW_AT_type : <133> - */ - /* ignore */ - } - else - if ((dtag == DW_TAG_variable || dtag == DW_TAG_formal_parameter) - && has_abs_ori && n_attrs == 1) { - /* Is very minimal, like this: + + --------------------------------------------- + + Is very minimal, like this: <4><81d>: Abbrev Number: 44 (DW_TAG_variable) DW_AT_abstract_origin: <7ba> - What that signifies I have no idea. Ignore. */ - /* ignore */ - } - else - if ((dtag == DW_TAG_variable || dtag == DW_TAG_formal_parameter) - && has_abs_ori && gexpr && n_attrs == 2) { - /* Is very minimal, like this: + What that signifies I have no idea. Ignore. + + ---------------------------------------------- + + Is very minimal, like this: <200f>: DW_TAG_formal_parameter DW_AT_abstract_ori: <1f4c> DW_AT_location : 13440 What that signifies I have no idea. Ignore. It might be significant, though: the variable at least has a location and so might exist somewhere. - Maybe we should handle this.*/ - /* ignore */ - } - else - if (dtag == DW_TAG_variable && declaration && !gexpr) { - /* <22407>: DW_TAG_variable + Maybe we should handle this. + + --------------------------------------------- + + <22407>: DW_TAG_variable DW_AT_name : (indirect string, offset: 0x6579): vgPlain_trampoline_stuff_start DW_AT_decl_file : 29 DW_AT_decl_line : 56 DW_AT_external : 1 DW_AT_declaration : 1 - */ - /* ignore */ - } - else - if (dtag == DW_TAG_variable && gexpr && n_attrs == 1) { - /* Nameless and typeless variable that has a location? Who + + Nameless and typeless variable that has a location? Who knows. Not me. <2><3d178>: Abbrev Number: 22 (DW_TAG_variable) DW_AT_location : 9 byte block: 3 c0 c7 13 38 0 0 0 0 (DW_OP_addr: 3813c7c0) - */ - /* ignore */ - } - else - if (dtag == DW_TAG_variable && n_attrs == 0) { - /* No, really. Check it out. gcc is quite simply borked. + + No, really. Check it out. gcc is quite simply borked. <3><168cc>: Abbrev Number: 141 (DW_TAG_variable) // followed by no attributes, and the next DIE is a sibling, // not a child - */ - /* ignore */ - } - else - goto bad_DIE; -#endif + */ } - return; bad_DIE: @@ -1657,10 +1662,11 @@ } -///////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////// -// Type parser. Sometimes maintains a pointer to a type -// currently under construction. +/*------------------------------------------------------------*/ +/*--- ---*/ +/*--- Parsing of type-related DIEs ---*/ +/*--- ---*/ +/*------------------------------------------------------------*/ #define N_D3_TYPE_STACK 16 @@ -1746,7 +1752,6 @@ } - /* Parse a type-related DIE. 'parser' holds the current parser state. 'admin' is where the completed types are dumped. 'dtag' is the tag for this DIE. 'c_die' points to the start of the data fields (FORM @@ -2321,10 +2326,13 @@ /*NOTREACHED*/ } -///////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////// -// Type Resolver +/*------------------------------------------------------------*/ +/*--- ---*/ +/*--- Resolution of references to type DIEs ---*/ +/*--- ---*/ +/*------------------------------------------------------------*/ + static Int cmp_D3TyAdmin_by_cuOff ( void* v1, void* v2 ) { TyAdmin* a1 = *(TyAdmin**)v1; TyAdmin* a2 = *(TyAdmin**)v2; @@ -2529,9 +2537,20 @@ } -///////////////////////////////////////////////////////////// -///////////////////////////////////////////////////////////// +/*------------------------------------------------------------*/ +/*--- ---*/ +/*--- Parsing of Compilation Units ---*/ +/*--- ---*/ +/*------------------------------------------------------------*/ +static Int cmp_TempVar_by_dioff ( void* v1, void* v2 ) { + TempVar* t1 = *(TempVar**)v1; + TempVar* t2 = *(TempVar**)v2; + if (t1->dioff < t2->dioff) return -1; + if (t1->dioff > t2->dioff) return 1; + return 0; +} + static void read_DIE ( /*OUT*/TyAdmin** admin, /*OUT*/TempVar** tempvars, /*OUT*/GExpr** gexprs, @@ -2661,7 +2680,10 @@ D3VarParser varparser; Addr dr_base; UWord dr_offset; + Word i; Bool td3 = di->trace_symtab; + XArray* /* of AddrRange */ xa; + XArray* /* of TempVar* */ dioff_lookup_tab; #if 0 /* This doesn't work properly because it assumes all entries are @@ -2858,17 +2880,15 @@ } /* Check the varparser's stack is in a sane state. */ - { Int i; - vg_assert(varparser.sp == -1); - for (i = 0; i < N_D3_VAR_STACK; i++) { - vg_assert(varparser.ranges[i] == NULL); - vg_assert(varparser.level[i] == 0); - } - for (i = 0; i < N_D3_TYPE_STACK; i++) { - vg_assert(typarser.qparent[i] == NULL); - vg_assert(typarser.qlevel[i] == 0); - } + vg_assert(varparser.sp == -1); + for (i = 0; i < N_D3_VAR_STACK; i++) { + vg_assert(varparser.ranges[i] == NULL); + vg_assert(varparser.level[i] == 0); } + for (i = 0; i < N_D3_TYPE_STACK; i++) { + vg_assert(typarser.qparent[i] == NULL); + vg_assert(typarser.qlevel[i] == 0); + } cu_start_offset = get_position_of_Cursor( &info ); TRACE_D3("\n"); @@ -2986,21 +3006,48 @@ } TRACE_D3("\n"); - TRACE_D3("------ Acquired the following variables: ------\n"); - for (varp = tempvars; varp; varp = varp2) { - varp2 = varp->next; + TRACE_D3("------ Acquired the following variables: ------\n\n"); + /* Park (pointers to) all the vars in an XArray, so we can look up + abstract origins quickly. The array is sorted (hence, looked-up + by) the .dioff fields. Since the .dioffs should be instrictly + ascending order, there is no need to sort the array after + construction. The ascendingness is however asserted for. */ + dioff_lookup_tab + = VG_(newXA)( ML_(dinfo_zalloc), ML_(dinfo_free), + sizeof(TempVar*) ); + vg_assert(dioff_lookup_tab); + varp2 = NULL; + for (varp = tempvars; varp; varp = varp->next) { + if (varp2) + vg_assert(varp2->dioff < varp->dioff); + VG_(addToXA)( dioff_lookup_tab, &varp ); + varp2 = varp; + } + VG_(setCmpFnXA)( dioff_lookup_tab, cmp_TempVar_by_dioff ); + VG_(sortXA)( dioff_lookup_tab ); /* POINTLESS; FIXME: rm */ + + /* Now visit each var. Collect up as much info as possible for + each var and hand it to ML_(addVar). */ + for (varp = tempvars; varp; varp = varp->next) { + /* Possibly show .. */ if (td3) { - VG_(printf)(" addVar: level %d %p-%p %s :: ", - varp->level, varp->pcMin, varp->pcMax, varp->name ); + VG_(printf)("<%lx> addVar: level %d: %s :: ", + varp->dioff, + varp->level, + varp->name ? varp->name : (UChar*)"<anonymous>" ); if (varp->typeR) { ML_(pp_Type_C_ishly)( varp->typeR ); } else { - VG_(printf)("!!type=NULL!!"); + VG_(printf)("NULL"); } - VG_(printf)("\n Var="); - ML_(pp_GX)(varp->gexpr); + VG_(printf)("\n Loc="); + if (varp->gexpr) { + ML_(pp_GX)(varp->gexpr); + } else { + VG_(printf)("NULL"); + } VG_(printf)("\n"); if (varp->fbGX) { VG_(printf)(" FrB="); @@ -3009,46 +3056,128 @@ } else { VG_(printf)(" FrB=none\n"); } - VG_(printf)(" .debug_info offset = <%lx> " - "(or thereabouts; not exact)\n", varp->dioff); VG_(printf)(" declared at: %s:%d\n", - varp->fName ? varp->fName : (UChar*)"(null)", + varp->fName ? varp->fName : (UChar*)"NULL", varp->fLine ); - VG_(printf)("\n"); + if (varp->absOri != (UWord)D3_INVALID_CUOFF) + VG_(printf)(" abstract origin: <%lx>\n", varp->absOri); } + /* Skip variables which have no location. These must be + abstract instances; they are useless as-is since with no + location they have no specified memory location. They will + presumably be referred to via the absOri fields of other + variables. */ + if (!varp->gexpr) { + TRACE_D3(" SKIP (no location)\n\n"); + continue; + } + + /* So it has a location, at least. If it refers to some other + entry through its absOri field, pull in further info through + that. */ + if (varp->absOri != (UWord)D3_INVALID_CUOFF) { + Bool found; + Word ixFirst, ixLast; + TempVar key; + TempVar* keyp = &key; + TempVar *varAI; + VG_(memset)(&key, 0, sizeof(key)); /* not necessary */ + key.dioff = varp->absOri; /* this is what we want to find */ + found = VG_(lookupXA)( dioff_lookup_tab, &keyp, + &ixFirst, &ixLast ); + if (!found) + barf("DW_AT_abstract_origin can't be resolved"); + /* If the following fails, there is more than one entry with + the same dioff. Which can't happen. */ + vg_assert(ixFirst == ixLast); + varAI = *(TempVar**)VG_(indexXA)( dioff_lookup_tab, ixFirst ); + /* stay sane */ + vg_assert(varAI); + vg_assert(varAI->dioff == varp->absOri); + + /* Copy what useful info we can. */ + if (varAI->typeR && !varp->typeR) + varp->typeR = varAI->typeR; + if (varAI->name && !varp->name) + varp->name = varAI->name; + if (varAI->fName && !varp->fName) + varp->fName = varAI->fName; + if (varAI->fLine > 0 && varp->fLine == 0) + varp->fLine = varAI->fLine; + } + + /* Give it a name if it doesn't have one. */ + if (!varp->name) + varp->name = ML_(addStr)( di, "<anonymous>", -1 ); + + /* So now does it have enough info to be useful? */ + /* NOTE: re typeR: this is a hack. If typeR is NULL then the + type didn't get resolved. Really, in that case something's + broken earlier on, and should be fixed, rather than just + skipping the variable. */ + if (!varp->typeR) continue; + vg_assert(varp->gexpr); + vg_assert(varp->name); + vg_assert(varp->typeR); + vg_assert(varp->level >= 0); + vg_assert(varp->ranges); + + /* Ok. So we're going to keep it. Call ML_(addVar) once for + each address range in which the variable exists. */ + xa = varp->ranges; + if (varp->level == 0) + vg_assert( VG_(sizeXA)(xa) == 1 ); + /* Level 0 is the global address range. So at level 0 we don't want to bias pcMin/pcMax; but at all other levels we do since those are derived from svmas in the Dwarf we're reading. Be paranoid ... */ - vg_assert(varp->level >= 0); - vg_assert(varp->pcMin <= varp->pcMax); - if (varp->level == 0) { - vg_assert(varp->pcMin == (Addr)0); - vg_assert(varp->pcMax == ~(Addr)0); - } else { - /* vg_assert(varp->pcMin > (Addr)0); - No .. we can legitmately expect to see ranges like - 0x0-0x11D (pre-biasing, of course). */ - vg_assert(varp->pcMax < ~(Addr)0); - } - /* NOTE: re "if": this is a hack. If typeR is NULL then the - type didn't get resolved. Really, in that case something's - broken earlier on, and should be fixed, rather than just - skipping the variable. */ - if (varp->typeR) + TRACE_D3(" ACQUIRE for range(s) "); + for (i = 0; i < VG_(sizeXA)( xa ); i++) { + AddrRange* range = VG_(indexXA)(xa, i); + Addr pcMin = range->aMin; + Addr pcMax = range->aMax; + vg_assert(pcMin <= pcMax); + if (varp->level == 0) { + vg_assert(pcMin == (Addr)0); + vg_assert(pcMax == ~(Addr)0); + } else { + /* vg_assert(pcMin > (Addr)0); + No .. we can legitimately expect to see ranges like + 0x0-0x11D (pre-biasing, of course). */ + vg_assert(pcMax < ~(Addr)0); + } + + if (i > 0 && (i%2) == 0) TRACE_D3("\n "); + TRACE_D3("[%p,%p] ", pcMin, pcMax ); + ML_(addVar)( di, varp->level, - varp->pcMin + (varp->level==0 ? 0 : di->text_bias), - varp->pcMax + (varp->level==0 ? 0 : di->text_bias), + pcMin + (varp->level==0 ? 0 : di->text_bias), + pcMax + (varp->level==0 ? 0 : di->text_bias), varp->name, (void*)varp->typeR, varp->gexpr, varp->fbGX, varp->fName, varp->fLine, td3 ); + } + + TRACE_D3("\n\n"); + /* and move on to the next var */ + } + + /* Now free all the TempVars */ + for (varp = tempvars; varp; varp = varp2) { + varp2 = varp->next; + vg_assert(varp->ranges); + VG_(deleteXA)(varp->ranges); ML_(dinfo_free)(varp); } tempvars = NULL; + /* And get rid of the temporary mapping table. */ + VG_(deleteXA)( dioff_lookup_tab ); + /* record the TyAdmins and the GExprs in di so they can be freed later */ vg_assert(!di->admin_tyadmins); @@ -3059,7 +3188,9 @@ /*------------------------------------------------------------*/ +/*--- ---*/ /*--- The "new" DWARF3 reader -- top level control logic ---*/ +/*--- ---*/ /*------------------------------------------------------------*/ /* --- !!! --- EXTERNAL HEADERS start --- !!! --- */ ------------------------------------------------------------------------- This SF.net email is sponsored by: Microsoft Defy all challenges. Microsoft(R) Visual Studio 2008. http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/ _______________________________________________ Valgrind-developers mailing list Valgrind-developers@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/valgrind-developers