@@ -328,45 +328,59 @@ struct LineState {
328328 }
329329};
330330
331- // Represents a mapping of addresses to expressions.
331+ // Represents a mapping of addresses to expressions. We track beginnings and
332+ // endings of expressions separately, since the end of one (which is one past
333+ // the end in DWARF notation) overlaps with the beginning of the next, and also
334+ // to let us use contextual information (we may know we are looking up the end
335+ // of an instruction).
332336struct AddrExprMap {
333- std::unordered_map<uint32_t , Expression*> map;
337+ std::unordered_map<uint32_t , Expression*> startMap;
338+ std::unordered_map<uint32_t , Expression*> endMap;
334339
335340 // Construct the map from the binaryLocations loaded from the wasm.
336341 AddrExprMap (const Module& wasm) {
337342 for (auto & func : wasm.functions ) {
338343 for (auto pair : func->expressionLocations ) {
339- assert (map.count (pair.second ) == 0 );
340- map[pair.second ] = pair.first ;
344+ add (pair.first , pair.second );
341345 }
342346 }
343347 }
344348
345349 // Construct the map from new binaryLocations just written
346350 AddrExprMap (const BinaryLocations& newLocations) {
347351 for (auto pair : newLocations.expressions ) {
348- assert (map.count (pair.second ) == 0 );
349- map[pair.second ] = pair.first ;
352+ add (pair.first , pair.second );
350353 }
351354 }
352355
353- Expression* get (uint32_t addr) const {
354- auto iter = map .find (addr);
355- if (iter != map .end ()) {
356+ Expression* getStart (uint32_t addr) const {
357+ auto iter = startMap .find (addr);
358+ if (iter != startMap .end ()) {
356359 return iter->second ;
357360 }
358361 return nullptr ;
359362 }
360363
361- void dump ( ) const {
362- std::cout << " (size: " << map. size () << " ) \n " ;
363- for ( auto pair : map ) {
364- std::cout << " " << pair. first << " => " << pair. second << ' \n ' ;
364+ Expression* getEnd ( uint32_t addr ) const {
365+ auto iter = endMap. find (addr) ;
366+ if (iter != endMap. end () ) {
367+ return iter-> second ;
365368 }
369+ return nullptr ;
370+ }
371+
372+ private:
373+ void add (Expression* expr, BinaryLocations::Span span) {
374+ assert (startMap.count (span.start ) == 0 );
375+ startMap[span.start ] = expr;
376+ assert (endMap.count (span.end ) == 0 );
377+ endMap[span.end ] = expr;
366378 }
367379};
368380
369- // Represents a mapping of addresses to expressions.
381+ // Represents a mapping of addresses to expressions. Note that we use a single
382+ // map for the start and end addresses, since there is no chance of a function's
383+ // start overlapping with another's end (there is the size LEB in the middle).
370384struct FuncAddrMap {
371385 std::unordered_map<uint32_t , Function*> map;
372386
@@ -415,10 +429,6 @@ struct LocationUpdater {
415429 // TODO: for memory efficiency, we may want to do this in a streaming manner,
416430 // binary to binary, without YAML IR.
417431
418- // TODO: apparently DWARF offsets may be into the middle of instructions...
419- // we may need to track their spans too
420- // https://github.com/WebAssembly/debugging/issues/9#issuecomment-567720872
421-
422432 LocationUpdater (Module& wasm, const BinaryLocations& newLocations)
423433 : wasm(wasm), newLocations(newLocations), oldExprAddrMap(wasm),
424434 newExprAddrMap (newLocations), oldFuncAddrMap(wasm) {}
@@ -427,10 +437,21 @@ struct LocationUpdater {
427437 // address, or if there was but if that instruction no longer exists, return
428438 // 0. Otherwise, return the new updated location.
429439 uint32_t getNewExprAddr (uint32_t oldAddr) const {
430- if (auto * expr = oldExprAddrMap.get (oldAddr)) {
440+ if (auto * expr = oldExprAddrMap.getStart (oldAddr)) {
431441 auto iter = newLocations.expressions .find (expr);
432442 if (iter != newLocations.expressions .end ()) {
433- uint32_t newAddr = iter->second ;
443+ uint32_t newAddr = iter->second .start ;
444+ return newAddr;
445+ }
446+ }
447+ return 0 ;
448+ }
449+
450+ uint32_t getNewExprEndAddr (uint32_t oldAddr) const {
451+ if (auto * expr = oldExprAddrMap.getEnd (oldAddr)) {
452+ auto iter = newLocations.expressions .find (expr);
453+ if (iter != newLocations.expressions .end ()) {
454+ uint32_t newAddr = iter->second .end ;
434455 return newAddr;
435456 }
436457 }
@@ -529,6 +550,76 @@ static void iterContextAndYAML(const T& contextList, U& yamlList, W func) {
529550 assert (yamlValue == yamlList.end ());
530551}
531552
553+ static void updateDIE (const llvm::DWARFDebugInfoEntry& DIE,
554+ llvm::DWARFYAML::Entry& yamlEntry,
555+ const llvm::DWARFAbbreviationDeclaration* abbrevDecl,
556+ const LocationUpdater& locationUpdater) {
557+ auto tag = DIE.getTag ();
558+ // Pairs of low/high_pc require some special handling, as the high
559+ // may be an offset relative to the low. First, process the low_pcs.
560+ uint32_t oldLowPC = 0 , newLowPC = 0 ;
561+ iterContextAndYAML (
562+ abbrevDecl->attributes (),
563+ yamlEntry.Values ,
564+ [&](const llvm::DWARFAbbreviationDeclaration::AttributeSpec& attrSpec,
565+ llvm::DWARFYAML::FormValue& yamlValue) {
566+ auto attr = attrSpec.Attr ;
567+ if (attr != llvm::dwarf::DW_AT_low_pc) {
568+ return ;
569+ }
570+ uint32_t oldValue = yamlValue.Value , newValue = 0 ;
571+ if (tag == llvm::dwarf::DW_TAG_GNU_call_site ||
572+ tag == llvm::dwarf::DW_TAG_inlined_subroutine ||
573+ tag == llvm::dwarf::DW_TAG_lexical_block ||
574+ tag == llvm::dwarf::DW_TAG_label) {
575+ newValue = locationUpdater.getNewExprAddr (oldValue);
576+ } else if (tag == llvm::dwarf::DW_TAG_compile_unit ||
577+ tag == llvm::dwarf::DW_TAG_subprogram) {
578+ newValue = locationUpdater.getNewFuncAddr (oldValue);
579+ } else {
580+ Fatal () << " unknown tag with low_pc "
581+ << llvm::dwarf::TagString (tag).str ();
582+ }
583+ oldLowPC = oldValue;
584+ newLowPC = newValue;
585+ yamlValue.Value = newValue;
586+ });
587+ // Next, process the high_pcs.
588+ // TODO: do this more efficiently, without a second traversal (but that's a
589+ // little tricky given the special double-traversal we have).
590+ iterContextAndYAML (
591+ abbrevDecl->attributes (),
592+ yamlEntry.Values ,
593+ [&](const llvm::DWARFAbbreviationDeclaration::AttributeSpec& attrSpec,
594+ llvm::DWARFYAML::FormValue& yamlValue) {
595+ auto attr = attrSpec.Attr ;
596+ if (attr != llvm::dwarf::DW_AT_high_pc) {
597+ return ;
598+ }
599+ uint32_t oldValue = yamlValue.Value , newValue = 0 ;
600+ bool isRelative = attrSpec.Form == llvm::dwarf::DW_FORM_data4;
601+ if (isRelative) {
602+ oldValue += oldLowPC;
603+ }
604+ if (tag == llvm::dwarf::DW_TAG_GNU_call_site ||
605+ tag == llvm::dwarf::DW_TAG_inlined_subroutine ||
606+ tag == llvm::dwarf::DW_TAG_lexical_block ||
607+ tag == llvm::dwarf::DW_TAG_label) {
608+ newValue = locationUpdater.getNewExprEndAddr (oldValue);
609+ } else if (tag == llvm::dwarf::DW_TAG_compile_unit ||
610+ tag == llvm::dwarf::DW_TAG_subprogram) {
611+ newValue = locationUpdater.getNewFuncAddr (oldValue);
612+ } else {
613+ Fatal () << " unknown tag with low_pc "
614+ << llvm::dwarf::TagString (tag).str ();
615+ }
616+ if (isRelative) {
617+ newValue -= newLowPC;
618+ }
619+ yamlValue.Value = newValue;
620+ });
621+ }
622+
532623static void updateCompileUnits (const BinaryenDWARFInfo& info,
533624 llvm::DWARFYAML::Data& yaml,
534625 const LocationUpdater& locationUpdater) {
@@ -545,36 +636,12 @@ static void updateCompileUnits(const BinaryenDWARFInfo& info,
545636 yamlUnit.Entries ,
546637 [&](const llvm::DWARFDebugInfoEntry& DIE,
547638 llvm::DWARFYAML::Entry& yamlEntry) {
548- auto tag = DIE.getTag ();
549639 // Process the entries in each relevant DIE, looking for attributes to
550640 // change.
551641 auto abbrevDecl = DIE.getAbbreviationDeclarationPtr ();
552642 if (abbrevDecl) {
553- iterContextAndYAML (
554- abbrevDecl->attributes (),
555- yamlEntry.Values ,
556- [&](const llvm::DWARFAbbreviationDeclaration::AttributeSpec&
557- attrSpec,
558- llvm::DWARFYAML::FormValue& yamlValue) {
559- if (attrSpec.Attr == llvm::dwarf::DW_AT_low_pc) {
560- if (tag == llvm::dwarf::DW_TAG_GNU_call_site ||
561- tag == llvm::dwarf::DW_TAG_inlined_subroutine ||
562- tag == llvm::dwarf::DW_TAG_lexical_block ||
563- tag == llvm::dwarf::DW_TAG_label) {
564- // low_pc in certain tags represent expressions.
565- yamlValue.Value =
566- locationUpdater.getNewExprAddr (yamlValue.Value );
567- } else if (tag == llvm::dwarf::DW_TAG_compile_unit ||
568- tag == llvm::dwarf::DW_TAG_subprogram) {
569- // low_pc in certain tags represent function.
570- yamlValue.Value =
571- locationUpdater.getNewFuncAddr (yamlValue.Value );
572- } else {
573- Fatal () << " unknown tag with low_pc "
574- << llvm::dwarf::TagString (tag).str ();
575- }
576- }
577- });
643+ // This is relevant; look for things to update.
644+ updateDIE (DIE, yamlEntry, abbrevDecl, locationUpdater);
578645 }
579646 });
580647 });
0 commit comments