Path: blob/main/contrib/llvm-project/llvm/lib/DebugInfo/LogicalView/Readers/LVDWARFReader.cpp
35295 views
//===-- LVDWARFReader.cpp -------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This implements the LVDWARFReader class.9// It supports ELF, Mach-O and Wasm binary formats.10//11//===----------------------------------------------------------------------===//1213#include "llvm/DebugInfo/LogicalView/Readers/LVDWARFReader.h"14#include "llvm/DebugInfo/DIContext.h"15#include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h"16#include "llvm/DebugInfo/DWARF/DWARFExpression.h"17#include "llvm/DebugInfo/LogicalView/Core/LVLine.h"18#include "llvm/DebugInfo/LogicalView/Core/LVScope.h"19#include "llvm/DebugInfo/LogicalView/Core/LVSymbol.h"20#include "llvm/DebugInfo/LogicalView/Core/LVType.h"21#include "llvm/Object/Error.h"22#include "llvm/Object/MachO.h"23#include "llvm/Support/FormatVariadic.h"2425using namespace llvm;26using namespace llvm::object;27using namespace llvm::logicalview;2829#define DEBUG_TYPE "DWARFReader"3031LVElement *LVDWARFReader::createElement(dwarf::Tag Tag) {32CurrentScope = nullptr;33CurrentSymbol = nullptr;34CurrentType = nullptr;35CurrentRanges.clear();3637if (!options().getPrintSymbols()) {38switch (Tag) {39// As the command line options did not specify a request to print40// logical symbols (--print=symbols or --print=all or --print=elements),41// skip its creation.42case dwarf::DW_TAG_formal_parameter:43case dwarf::DW_TAG_unspecified_parameters:44case dwarf::DW_TAG_member:45case dwarf::DW_TAG_variable:46case dwarf::DW_TAG_inheritance:47case dwarf::DW_TAG_constant:48case dwarf::DW_TAG_call_site_parameter:49case dwarf::DW_TAG_GNU_call_site_parameter:50return nullptr;51default:52break;53}54}5556switch (Tag) {57// Types.58case dwarf::DW_TAG_base_type:59CurrentType = createType();60CurrentType->setIsBase();61if (options().getAttributeBase())62CurrentType->setIncludeInPrint();63return CurrentType;64case dwarf::DW_TAG_const_type:65CurrentType = createType();66CurrentType->setIsConst();67CurrentType->setName("const");68return CurrentType;69case dwarf::DW_TAG_enumerator:70CurrentType = createTypeEnumerator();71return CurrentType;72case dwarf::DW_TAG_imported_declaration:73CurrentType = createTypeImport();74CurrentType->setIsImportDeclaration();75return CurrentType;76case dwarf::DW_TAG_imported_module:77CurrentType = createTypeImport();78CurrentType->setIsImportModule();79return CurrentType;80case dwarf::DW_TAG_pointer_type:81CurrentType = createType();82CurrentType->setIsPointer();83CurrentType->setName("*");84return CurrentType;85case dwarf::DW_TAG_ptr_to_member_type:86CurrentType = createType();87CurrentType->setIsPointerMember();88CurrentType->setName("*");89return CurrentType;90case dwarf::DW_TAG_reference_type:91CurrentType = createType();92CurrentType->setIsReference();93CurrentType->setName("&");94return CurrentType;95case dwarf::DW_TAG_restrict_type:96CurrentType = createType();97CurrentType->setIsRestrict();98CurrentType->setName("restrict");99return CurrentType;100case dwarf::DW_TAG_rvalue_reference_type:101CurrentType = createType();102CurrentType->setIsRvalueReference();103CurrentType->setName("&&");104return CurrentType;105case dwarf::DW_TAG_subrange_type:106CurrentType = createTypeSubrange();107return CurrentType;108case dwarf::DW_TAG_template_value_parameter:109CurrentType = createTypeParam();110CurrentType->setIsTemplateValueParam();111return CurrentType;112case dwarf::DW_TAG_template_type_parameter:113CurrentType = createTypeParam();114CurrentType->setIsTemplateTypeParam();115return CurrentType;116case dwarf::DW_TAG_GNU_template_template_param:117CurrentType = createTypeParam();118CurrentType->setIsTemplateTemplateParam();119return CurrentType;120case dwarf::DW_TAG_typedef:121CurrentType = createTypeDefinition();122return CurrentType;123case dwarf::DW_TAG_unspecified_type:124CurrentType = createType();125CurrentType->setIsUnspecified();126return CurrentType;127case dwarf::DW_TAG_volatile_type:128CurrentType = createType();129CurrentType->setIsVolatile();130CurrentType->setName("volatile");131return CurrentType;132133// Symbols.134case dwarf::DW_TAG_formal_parameter:135CurrentSymbol = createSymbol();136CurrentSymbol->setIsParameter();137return CurrentSymbol;138case dwarf::DW_TAG_unspecified_parameters:139CurrentSymbol = createSymbol();140CurrentSymbol->setIsUnspecified();141CurrentSymbol->setName("...");142return CurrentSymbol;143case dwarf::DW_TAG_member:144CurrentSymbol = createSymbol();145CurrentSymbol->setIsMember();146return CurrentSymbol;147case dwarf::DW_TAG_variable:148CurrentSymbol = createSymbol();149CurrentSymbol->setIsVariable();150return CurrentSymbol;151case dwarf::DW_TAG_inheritance:152CurrentSymbol = createSymbol();153CurrentSymbol->setIsInheritance();154return CurrentSymbol;155case dwarf::DW_TAG_call_site_parameter:156case dwarf::DW_TAG_GNU_call_site_parameter:157CurrentSymbol = createSymbol();158CurrentSymbol->setIsCallSiteParameter();159return CurrentSymbol;160case dwarf::DW_TAG_constant:161CurrentSymbol = createSymbol();162CurrentSymbol->setIsConstant();163return CurrentSymbol;164165// Scopes.166case dwarf::DW_TAG_catch_block:167CurrentScope = createScope();168CurrentScope->setIsCatchBlock();169return CurrentScope;170case dwarf::DW_TAG_lexical_block:171CurrentScope = createScope();172CurrentScope->setIsLexicalBlock();173return CurrentScope;174case dwarf::DW_TAG_try_block:175CurrentScope = createScope();176CurrentScope->setIsTryBlock();177return CurrentScope;178case dwarf::DW_TAG_compile_unit:179case dwarf::DW_TAG_skeleton_unit:180CurrentScope = createScopeCompileUnit();181CompileUnit = static_cast<LVScopeCompileUnit *>(CurrentScope);182return CurrentScope;183case dwarf::DW_TAG_inlined_subroutine:184CurrentScope = createScopeFunctionInlined();185return CurrentScope;186case dwarf::DW_TAG_namespace:187CurrentScope = createScopeNamespace();188return CurrentScope;189case dwarf::DW_TAG_template_alias:190CurrentScope = createScopeAlias();191return CurrentScope;192case dwarf::DW_TAG_array_type:193CurrentScope = createScopeArray();194return CurrentScope;195case dwarf::DW_TAG_call_site:196case dwarf::DW_TAG_GNU_call_site:197CurrentScope = createScopeFunction();198CurrentScope->setIsCallSite();199return CurrentScope;200case dwarf::DW_TAG_entry_point:201CurrentScope = createScopeFunction();202CurrentScope->setIsEntryPoint();203return CurrentScope;204case dwarf::DW_TAG_subprogram:205CurrentScope = createScopeFunction();206CurrentScope->setIsSubprogram();207return CurrentScope;208case dwarf::DW_TAG_subroutine_type:209CurrentScope = createScopeFunctionType();210return CurrentScope;211case dwarf::DW_TAG_label:212CurrentScope = createScopeFunction();213CurrentScope->setIsLabel();214return CurrentScope;215case dwarf::DW_TAG_class_type:216CurrentScope = createScopeAggregate();217CurrentScope->setIsClass();218return CurrentScope;219case dwarf::DW_TAG_structure_type:220CurrentScope = createScopeAggregate();221CurrentScope->setIsStructure();222return CurrentScope;223case dwarf::DW_TAG_union_type:224CurrentScope = createScopeAggregate();225CurrentScope->setIsUnion();226return CurrentScope;227case dwarf::DW_TAG_enumeration_type:228CurrentScope = createScopeEnumeration();229return CurrentScope;230case dwarf::DW_TAG_GNU_formal_parameter_pack:231CurrentScope = createScopeFormalPack();232return CurrentScope;233case dwarf::DW_TAG_GNU_template_parameter_pack:234CurrentScope = createScopeTemplatePack();235return CurrentScope;236default:237// Collect TAGs not implemented.238if (options().getInternalTag() && Tag)239CompileUnit->addDebugTag(Tag, CurrentOffset);240break;241}242return nullptr;243}244245void LVDWARFReader::processOneAttribute(const DWARFDie &Die,246LVOffset *OffsetPtr,247const AttributeSpec &AttrSpec) {248uint64_t OffsetOnEntry = *OffsetPtr;249DWARFUnit *U = Die.getDwarfUnit();250const DWARFFormValue &FormValue =251DWARFFormValue::createFromUnit(AttrSpec.Form, U, OffsetPtr);252253// We are processing .debug_info section, implicit_const attribute254// values are not really stored here, but in .debug_abbrev section.255auto GetAsUnsignedConstant = [&]() -> int64_t {256return AttrSpec.isImplicitConst() ? AttrSpec.getImplicitConstValue()257: *FormValue.getAsUnsignedConstant();258};259260auto GetFlag = [](const DWARFFormValue &FormValue) -> bool {261return FormValue.isFormClass(DWARFFormValue::FC_Flag);262};263264auto GetBoundValue = [](const DWARFFormValue &FormValue) -> int64_t {265switch (FormValue.getForm()) {266case dwarf::DW_FORM_ref_addr:267case dwarf::DW_FORM_ref1:268case dwarf::DW_FORM_ref2:269case dwarf::DW_FORM_ref4:270case dwarf::DW_FORM_ref8:271case dwarf::DW_FORM_ref_udata:272case dwarf::DW_FORM_ref_sig8:273return *FormValue.getAsReferenceUVal();274case dwarf::DW_FORM_data1:275case dwarf::DW_FORM_flag:276case dwarf::DW_FORM_data2:277case dwarf::DW_FORM_data4:278case dwarf::DW_FORM_data8:279case dwarf::DW_FORM_udata:280case dwarf::DW_FORM_ref_sup4:281case dwarf::DW_FORM_ref_sup8:282return *FormValue.getAsUnsignedConstant();283case dwarf::DW_FORM_sdata:284return *FormValue.getAsSignedConstant();285default:286return 0;287}288};289290LLVM_DEBUG({291dbgs() << " " << hexValue(OffsetOnEntry)292<< formatv(" {0}", AttrSpec.Attr) << "\n";293});294295switch (AttrSpec.Attr) {296case dwarf::DW_AT_accessibility:297CurrentElement->setAccessibilityCode(*FormValue.getAsUnsignedConstant());298break;299case dwarf::DW_AT_artificial:300CurrentElement->setIsArtificial();301break;302case dwarf::DW_AT_bit_size:303CurrentElement->setBitSize(*FormValue.getAsUnsignedConstant());304break;305case dwarf::DW_AT_call_file:306CurrentElement->setCallFilenameIndex(GetAsUnsignedConstant());307break;308case dwarf::DW_AT_call_line:309CurrentElement->setCallLineNumber(IncrementFileIndex310? GetAsUnsignedConstant() + 1311: GetAsUnsignedConstant());312break;313case dwarf::DW_AT_comp_dir:314CompileUnit->setCompilationDirectory(dwarf::toStringRef(FormValue));315break;316case dwarf::DW_AT_const_value:317if (FormValue.isFormClass(DWARFFormValue::FC_Block)) {318ArrayRef<uint8_t> Expr = *FormValue.getAsBlock();319// Store the expression as a hexadecimal string.320CurrentElement->setValue(321llvm::toHex(llvm::toStringRef(Expr), /*LowerCase=*/true));322} else if (FormValue.isFormClass(DWARFFormValue::FC_Constant)) {323// In the case of negative values, generate the string representation324// for a positive value prefixed with the negative sign.325if (FormValue.getForm() == dwarf::DW_FORM_sdata) {326std::stringstream Stream;327int64_t Value = *FormValue.getAsSignedConstant();328if (Value < 0) {329Stream << "-";330Value = std::abs(Value);331}332Stream << hexString(Value, 2);333CurrentElement->setValue(Stream.str());334} else335CurrentElement->setValue(336hexString(*FormValue.getAsUnsignedConstant(), 2));337} else338CurrentElement->setValue(dwarf::toStringRef(FormValue));339break;340case dwarf::DW_AT_count:341CurrentElement->setCount(*FormValue.getAsUnsignedConstant());342break;343case dwarf::DW_AT_decl_line:344CurrentElement->setLineNumber(GetAsUnsignedConstant());345break;346case dwarf::DW_AT_decl_file:347CurrentElement->setFilenameIndex(IncrementFileIndex348? GetAsUnsignedConstant() + 1349: GetAsUnsignedConstant());350break;351case dwarf::DW_AT_enum_class:352if (GetFlag(FormValue))353CurrentElement->setIsEnumClass();354break;355case dwarf::DW_AT_external:356if (GetFlag(FormValue))357CurrentElement->setIsExternal();358break;359case dwarf::DW_AT_GNU_discriminator:360CurrentElement->setDiscriminator(*FormValue.getAsUnsignedConstant());361break;362case dwarf::DW_AT_inline:363CurrentElement->setInlineCode(*FormValue.getAsUnsignedConstant());364break;365case dwarf::DW_AT_lower_bound:366CurrentElement->setLowerBound(GetBoundValue(FormValue));367break;368case dwarf::DW_AT_name:369CurrentElement->setName(dwarf::toStringRef(FormValue));370break;371case dwarf::DW_AT_linkage_name:372case dwarf::DW_AT_MIPS_linkage_name:373CurrentElement->setLinkageName(dwarf::toStringRef(FormValue));374break;375case dwarf::DW_AT_producer:376if (options().getAttributeProducer())377CurrentElement->setProducer(dwarf::toStringRef(FormValue));378break;379case dwarf::DW_AT_upper_bound:380CurrentElement->setUpperBound(GetBoundValue(FormValue));381break;382case dwarf::DW_AT_virtuality:383CurrentElement->setVirtualityCode(*FormValue.getAsUnsignedConstant());384break;385386case dwarf::DW_AT_abstract_origin:387case dwarf::DW_AT_call_origin:388case dwarf::DW_AT_extension:389case dwarf::DW_AT_import:390case dwarf::DW_AT_specification:391case dwarf::DW_AT_type:392updateReference(AttrSpec.Attr, FormValue);393break;394395case dwarf::DW_AT_low_pc:396if (options().getGeneralCollectRanges()) {397FoundLowPC = true;398// For toolchains that support the removal of unused code, the linker399// marks functions that have been removed, by setting the value for the400// low_pc to the max address.401if (std::optional<uint64_t> Value = FormValue.getAsAddress()) {402CurrentLowPC = *Value;403} else {404uint64_t UValue = FormValue.getRawUValue();405if (U->getAddrOffsetSectionItem(UValue)) {406CurrentLowPC = *FormValue.getAsAddress();407} else {408FoundLowPC = false;409// We are dealing with an index into the .debug_addr section.410LLVM_DEBUG({411dbgs() << format("indexed (%8.8x) address = ", (uint32_t)UValue);412});413}414}415if (FoundLowPC) {416if (CurrentLowPC == MaxAddress)417CurrentElement->setIsDiscarded();418// Consider the case of WebAssembly.419CurrentLowPC += WasmCodeSectionOffset;420if (CurrentElement->isCompileUnit())421setCUBaseAddress(CurrentLowPC);422}423}424break;425426case dwarf::DW_AT_high_pc:427if (options().getGeneralCollectRanges()) {428FoundHighPC = true;429if (std::optional<uint64_t> Address = FormValue.getAsAddress())430// High PC is an address.431CurrentHighPC = *Address;432if (std::optional<uint64_t> Offset = FormValue.getAsUnsignedConstant())433// High PC is an offset from LowPC.434// Don't add the WebAssembly offset if we have seen a DW_AT_low_pc, as435// the CurrentLowPC has already that offset added. Basically, use the436// original DW_AT_loc_pc value.437CurrentHighPC =438(FoundLowPC ? CurrentLowPC - WasmCodeSectionOffset : CurrentLowPC) +439*Offset;440// Store the real upper limit for the address range.441if (UpdateHighAddress && CurrentHighPC > 0)442--CurrentHighPC;443// Consider the case of WebAssembly.444CurrentHighPC += WasmCodeSectionOffset;445if (CurrentElement->isCompileUnit())446setCUHighAddress(CurrentHighPC);447}448break;449450case dwarf::DW_AT_ranges:451if (RangesDataAvailable && options().getGeneralCollectRanges()) {452auto GetRanges = [](const DWARFFormValue &FormValue,453DWARFUnit *U) -> Expected<DWARFAddressRangesVector> {454if (FormValue.getForm() == dwarf::DW_FORM_rnglistx)455return U->findRnglistFromIndex(*FormValue.getAsSectionOffset());456return U->findRnglistFromOffset(*FormValue.getAsSectionOffset());457};458Expected<DWARFAddressRangesVector> RangesOrError =459GetRanges(FormValue, U);460if (!RangesOrError) {461LLVM_DEBUG({462std::string TheError(toString(RangesOrError.takeError()));463dbgs() << format("error decoding address ranges = ",464TheError.c_str());465});466consumeError(RangesOrError.takeError());467break;468}469// The address ranges are absolute. There is no need to add any addend.470DWARFAddressRangesVector Ranges = RangesOrError.get();471for (DWARFAddressRange &Range : Ranges) {472// This seems to be a tombstone for empty ranges.473if (Range.LowPC == Range.HighPC)474continue;475// Store the real upper limit for the address range.476if (UpdateHighAddress && Range.HighPC > 0)477--Range.HighPC;478// Consider the case of WebAssembly.479Range.LowPC += WasmCodeSectionOffset;480Range.HighPC += WasmCodeSectionOffset;481// Add the pair of addresses.482CurrentScope->addObject(Range.LowPC, Range.HighPC);483// If the scope is the CU, do not update the ranges set.484if (!CurrentElement->isCompileUnit())485CurrentRanges.emplace_back(Range.LowPC, Range.HighPC);486}487}488break;489490// Get the location list for the symbol.491case dwarf::DW_AT_data_member_location:492if (options().getAttributeAnyLocation())493processLocationMember(AttrSpec.Attr, FormValue, Die, OffsetOnEntry);494break;495496// Get the location list for the symbol.497case dwarf::DW_AT_location:498case dwarf::DW_AT_string_length:499case dwarf::DW_AT_use_location:500if (options().getAttributeAnyLocation() && CurrentSymbol)501processLocationList(AttrSpec.Attr, FormValue, Die, OffsetOnEntry);502break;503504case dwarf::DW_AT_call_data_value:505case dwarf::DW_AT_call_value:506case dwarf::DW_AT_GNU_call_site_data_value:507case dwarf::DW_AT_GNU_call_site_value:508if (options().getAttributeAnyLocation() && CurrentSymbol)509processLocationList(AttrSpec.Attr, FormValue, Die, OffsetOnEntry,510/*CallSiteLocation=*/true);511break;512513default:514break;515}516}517518LVScope *LVDWARFReader::processOneDie(const DWARFDie &InputDIE, LVScope *Parent,519DWARFDie &SkeletonDie) {520// If the input DIE corresponds to the compile unit, it can be:521// a) Simple DWARF: a standard DIE. Ignore the skeleton DIE (is empty).522// b) Split DWARF: the DIE for the split DWARF. The skeleton is the DIE523// for the skeleton DWARF. Process both DIEs.524const DWARFDie &DIE = SkeletonDie.isValid() ? SkeletonDie : InputDIE;525DWARFDataExtractor DebugInfoData =526DIE.getDwarfUnit()->getDebugInfoExtractor();527LVOffset Offset = DIE.getOffset();528529// Reset values for the current DIE.530CurrentLowPC = 0;531CurrentHighPC = 0;532CurrentOffset = Offset;533CurrentEndOffset = 0;534FoundLowPC = false;535FoundHighPC = false;536537// Process supported attributes.538if (DebugInfoData.isValidOffset(Offset)) {539540LLVM_DEBUG({541dbgs() << "DIE: " << hexValue(Offset) << formatv(" {0}", DIE.getTag())542<< "\n";543});544545// Create the logical view element for the current DIE.546dwarf::Tag Tag = DIE.getTag();547CurrentElement = createElement(Tag);548if (!CurrentElement)549return CurrentScope;550551CurrentElement->setTag(Tag);552CurrentElement->setOffset(Offset);553554if (options().getAttributeAnySource() && CurrentElement->isCompileUnit())555addCompileUnitOffset(Offset,556static_cast<LVScopeCompileUnit *>(CurrentElement));557558// Insert the newly created element into the element symbol table. If the559// element is in the list, it means there are previously created elements560// referencing this element.561if (ElementTable.find(Offset) == ElementTable.end()) {562// No previous references to this offset.563ElementTable.emplace(std::piecewise_construct,564std::forward_as_tuple(Offset),565std::forward_as_tuple(CurrentElement));566} else {567// There are previous references to this element. We need to update the568// element and all the references pointing to this element.569LVElementEntry &Reference = ElementTable[Offset];570Reference.Element = CurrentElement;571// Traverse the element set and update the elements (backtracking).572for (LVElement *Target : Reference.References)573Target->setReference(CurrentElement);574for (LVElement *Target : Reference.Types)575Target->setType(CurrentElement);576// Clear the pending elements.577Reference.References.clear();578Reference.Types.clear();579}580581// Add the current element to its parent as there are attributes582// (locations) that require the scope level.583if (CurrentScope)584Parent->addElement(CurrentScope);585else if (CurrentSymbol)586Parent->addElement(CurrentSymbol);587else if (CurrentType)588Parent->addElement(CurrentType);589590// Process the attributes for the given DIE.591auto ProcessAttributes = [&](const DWARFDie &TheDIE,592DWARFDataExtractor &DebugData) {593CurrentEndOffset = Offset;594uint32_t abbrCode = DebugData.getULEB128(&CurrentEndOffset);595if (abbrCode) {596if (const DWARFAbbreviationDeclaration *AbbrevDecl =597TheDIE.getAbbreviationDeclarationPtr())598if (AbbrevDecl)599for (const DWARFAbbreviationDeclaration::AttributeSpec &AttrSpec :600AbbrevDecl->attributes())601processOneAttribute(TheDIE, &CurrentEndOffset, AttrSpec);602}603};604605ProcessAttributes(DIE, DebugInfoData);606607// If the input DIE is for a compile unit, process its attributes in608// the case of split DWARF, to override any common attribute values.609if (SkeletonDie.isValid()) {610DWARFDataExtractor DebugInfoData =611InputDIE.getDwarfUnit()->getDebugInfoExtractor();612LVOffset Offset = InputDIE.getOffset();613if (DebugInfoData.isValidOffset(Offset))614ProcessAttributes(InputDIE, DebugInfoData);615}616}617618if (CurrentScope) {619if (CurrentScope->getCanHaveRanges()) {620// If the scope has ranges, they are already added to the scope.621// Add any collected LowPC/HighPC values.622bool IsCompileUnit = CurrentScope->getIsCompileUnit();623if (FoundLowPC && FoundHighPC) {624CurrentScope->addObject(CurrentLowPC, CurrentHighPC);625if (!IsCompileUnit) {626// If the scope is a function, add it to the public names.627if ((options().getAttributePublics() ||628options().getPrintAnyLine()) &&629CurrentScope->getIsFunction() &&630!CurrentScope->getIsInlinedFunction())631CompileUnit->addPublicName(CurrentScope, CurrentLowPC,632CurrentHighPC);633}634}635636// Look for scopes with ranges and no linkage name information that637// are referencing another scopes via DW_AT_specification. They are638// possible candidates for a comdat scope.639if (CurrentScope->getHasRanges() &&640!CurrentScope->getLinkageNameIndex() &&641CurrentScope->getHasReferenceSpecification()) {642// Get the linkage name in order to search for a possible comdat.643std::optional<DWARFFormValue> LinkageDIE =644DIE.findRecursively(dwarf::DW_AT_linkage_name);645if (LinkageDIE.has_value()) {646StringRef Name(dwarf::toStringRef(LinkageDIE));647if (!Name.empty())648CurrentScope->setLinkageName(Name);649}650}651652// If the current scope is in the 'LinkageNames' table, update its653// logical scope. For other scopes, always we will assume the default654// ".text" section index.655LVSectionIndex SectionIndex = updateSymbolTable(CurrentScope);656if (CurrentScope->getIsComdat())657CompileUnit->setHasComdatScopes();658659// Update section index contained ranges.660if (SectionIndex) {661if (!CurrentRanges.empty()) {662for (LVAddressRange &Range : CurrentRanges)663addSectionRange(SectionIndex, CurrentScope, Range.first,664Range.second);665CurrentRanges.clear();666}667// If the scope is the CU, do not update the ranges set.668if (FoundLowPC && FoundHighPC && !IsCompileUnit) {669addSectionRange(SectionIndex, CurrentScope, CurrentLowPC,670CurrentHighPC);671}672}673}674// Mark member functions.675if (Parent->getIsAggregate())676CurrentScope->setIsMember();677}678679// Keep track of symbols with locations.680if (options().getAttributeAnyLocation() && CurrentSymbol &&681CurrentSymbol->getHasLocation())682SymbolsWithLocations.push_back(CurrentSymbol);683684// If we have template parameters, mark the parent as template.685if (CurrentType && CurrentType->getIsTemplateParam())686Parent->setIsTemplate();687688return CurrentScope;689}690691void LVDWARFReader::traverseDieAndChildren(DWARFDie &DIE, LVScope *Parent,692DWARFDie &SkeletonDie) {693// Process the current DIE.694LVScope *Scope = processOneDie(DIE, Parent, SkeletonDie);695if (Scope) {696LVOffset Lower = DIE.getOffset();697LVOffset Upper = CurrentEndOffset;698DWARFDie DummyDie;699// Traverse the children chain.700DWARFDie Child = DIE.getFirstChild();701while (Child) {702traverseDieAndChildren(Child, Scope, DummyDie);703Upper = Child.getOffset();704Child = Child.getSibling();705}706// Calculate contributions to the debug info section.707if (options().getPrintSizes() && Upper)708CompileUnit->addSize(Scope, Lower, Upper);709}710}711712void LVDWARFReader::processLocationGaps() {713if (options().getAttributeAnyLocation())714for (LVSymbol *Symbol : SymbolsWithLocations)715Symbol->fillLocationGaps();716}717718void LVDWARFReader::createLineAndFileRecords(719const DWARFDebugLine::LineTable *Lines) {720if (!Lines)721return;722723// Get the source filenames.724if (!Lines->Prologue.FileNames.empty())725for (const DWARFDebugLine::FileNameEntry &Entry :726Lines->Prologue.FileNames) {727std::string Directory;728if (Lines->getDirectoryForEntry(Entry, Directory))729Directory = transformPath(Directory);730if (Directory.empty())731Directory = std::string(CompileUnit->getCompilationDirectory());732std::string File = transformPath(dwarf::toStringRef(Entry.Name));733std::string String;734raw_string_ostream(String) << Directory << "/" << File;735CompileUnit->addFilename(String);736}737738// In DWARF5 the file indexes start at 0;739bool IncrementIndex = Lines->Prologue.getVersion() >= 5;740741// Get the source lines if requested by command line option.742if (options().getPrintLines() && Lines->Rows.size())743for (const DWARFDebugLine::Row &Row : Lines->Rows) {744// Here we collect logical debug lines in CULines. Later on,745// the 'processLines()' function will move each created logical line746// to its enclosing logical scope, using the debug ranges information747// and they will be released when its scope parent is deleted.748LVLineDebug *Line = createLineDebug();749CULines.push_back(Line);750// Consider the case of WebAssembly.751Line->setAddress(Row.Address.Address + WasmCodeSectionOffset);752Line->setFilename(753CompileUnit->getFilename(IncrementIndex ? Row.File + 1 : Row.File));754Line->setLineNumber(Row.Line);755if (Row.Discriminator)756Line->setDiscriminator(Row.Discriminator);757if (Row.IsStmt)758Line->setIsNewStatement();759if (Row.BasicBlock)760Line->setIsBasicBlock();761if (Row.EndSequence)762Line->setIsEndSequence();763if (Row.EpilogueBegin)764Line->setIsEpilogueBegin();765if (Row.PrologueEnd)766Line->setIsPrologueEnd();767LLVM_DEBUG({768dbgs() << "Address: " << hexValue(Line->getAddress())769<< " Line: " << Line->lineNumberAsString(/*ShowZero=*/true)770<< "\n";771});772}773}774775std::string LVDWARFReader::getRegisterName(LVSmall Opcode,776ArrayRef<uint64_t> Operands) {777// The 'prettyPrintRegisterOp' function uses the DWARFUnit to support778// DW_OP_regval_type. At this point we are operating on a logical view779// item, with no access to the underlying DWARF data used by LLVM.780// We do not support DW_OP_regval_type here.781if (Opcode == dwarf::DW_OP_regval_type)782return {};783784std::string string;785raw_string_ostream Stream(string);786DIDumpOptions DumpOpts;787auto *MCRegInfo = MRI.get();788auto GetRegName = [&MCRegInfo](uint64_t DwarfRegNum, bool IsEH) -> StringRef {789if (!MCRegInfo)790return {};791if (std::optional<unsigned> LLVMRegNum =792MCRegInfo->getLLVMRegNum(DwarfRegNum, IsEH))793if (const char *RegName = MCRegInfo->getName(*LLVMRegNum))794return StringRef(RegName);795return {};796};797DumpOpts.GetNameForDWARFReg = GetRegName;798DWARFExpression::prettyPrintRegisterOp(/*U=*/nullptr, Stream, DumpOpts,799Opcode, Operands);800return Stream.str();801}802803Error LVDWARFReader::createScopes() {804LLVM_DEBUG({805W.startLine() << "\n";806W.printString("File", Obj.getFileName().str());807W.printString("Format", FileFormatName);808});809810if (Error Err = LVReader::createScopes())811return Err;812813// As the DwarfContext object is valid only during the scopes creation,814// we need to create our own Target information, to be used during the815// logical view printing, in the case of instructions being requested.816std::unique_ptr<DWARFContext> DwarfContext = DWARFContext::create(Obj);817if (!DwarfContext)818return createStringError(errc::invalid_argument,819"Could not create DWARF information: %s",820getFilename().str().c_str());821822if (Error Err = loadTargetInfo(Obj))823return Err;824825// Create a mapping for virtual addresses.826mapVirtualAddress(Obj);827828// Select the correct compile unit range, depending if we are dealing with829// a standard or split DWARF object.830DWARFContext::compile_unit_range CompileUnits =831DwarfContext->getNumCompileUnits() ? DwarfContext->compile_units()832: DwarfContext->dwo_compile_units();833for (const std::unique_ptr<DWARFUnit> &CU : CompileUnits) {834835// Deduction of index used for the line records.836//837// For the following test case: test.cpp838// void foo(void ParamPtr) { }839840// Both GCC and Clang generate DWARF-5 .debug_line layout.841842// * GCC (GNU C++17 11.3.0) - All DW_AT_decl_file use index 1.843//844// .debug_info:845// format = DWARF32, version = 0x0005846// DW_TAG_compile_unit847// DW_AT_name ("test.cpp")848// DW_TAG_subprogram ("foo")849// DW_AT_decl_file (1)850// DW_TAG_formal_parameter ("ParamPtr")851// DW_AT_decl_file (1)852// .debug_line:853// Line table prologue: format (DWARF32), version (5)854// include_directories[0] = "..."855// file_names[0]: name ("test.cpp"), dir_index (0)856// file_names[1]: name ("test.cpp"), dir_index (0)857858// * Clang (14.0.6) - All DW_AT_decl_file use index 0.859//860// .debug_info:861// format = DWARF32, version = 0x0005862// DW_AT_producer ("clang version 14.0.6")863// DW_AT_name ("test.cpp")864//865// DW_TAG_subprogram ("foo")866// DW_AT_decl_file (0)867// DW_TAG_formal_parameter ("ParamPtr")868// DW_AT_decl_file (0)869// .debug_line:870// Line table prologue: format (DWARF32), version (5)871// include_directories[0] = "..."872// file_names[0]: name ("test.cpp"), dir_index (0)873874// From DWARFDebugLine::getFileNameByIndex documentation:875// In Dwarf 4, the files are 1-indexed.876// In Dwarf 5, the files are 0-indexed.877// Additional discussions here:878// https://www.mail-archive.com/[email protected]/msg00883.html879880// The DWARF reader is expecting the files are 1-indexed, so using881// the .debug_line header information decide if the indexed require882// an internal adjustment.883884// For the case of GCC (DWARF5), if the entries[0] and [1] are the885// same, do not perform any adjustment.886auto DeduceIncrementFileIndex = [&]() -> bool {887if (CU->getVersion() < 5)888// DWARF-4 or earlier -> Don't increment index.889return false;890891if (const DWARFDebugLine::LineTable *LT =892CU->getContext().getLineTableForUnit(CU.get())) {893// Check if there are at least 2 entries and if they are the same.894if (LT->hasFileAtIndex(0) && LT->hasFileAtIndex(1)) {895const DWARFDebugLine::FileNameEntry &EntryZero =896LT->Prologue.getFileNameEntry(0);897const DWARFDebugLine::FileNameEntry &EntryOne =898LT->Prologue.getFileNameEntry(1);899// Check directory indexes.900if (EntryZero.DirIdx != EntryOne.DirIdx)901// DWARF-5 -> Increment index.902return true;903// Check filename.904std::string FileZero;905std::string FileOne;906StringRef None;907LT->getFileNameByIndex(9080, None, DILineInfoSpecifier::FileLineInfoKind::RawValue,909FileZero);910LT->getFileNameByIndex(9111, None, DILineInfoSpecifier::FileLineInfoKind::RawValue,912FileOne);913return FileZero.compare(FileOne);914}915}916917// DWARF-5 -> Increment index.918return true;919};920// The DWARF reader expects the indexes as 1-indexed.921IncrementFileIndex = DeduceIncrementFileIndex();922923DWARFDie UnitDie = CU->getUnitDIE();924SmallString<16> DWOAlternativeLocation;925if (UnitDie) {926std::optional<const char *> DWOFileName =927CU->getVersion() >= 5928? dwarf::toString(UnitDie.find(dwarf::DW_AT_dwo_name))929: dwarf::toString(UnitDie.find(dwarf::DW_AT_GNU_dwo_name));930StringRef From(DWOFileName.value_or(""));931DWOAlternativeLocation = createAlternativePath(From);932}933934// The current CU can be a normal compile unit (standard) or a skeleton935// compile unit (split). For both cases, the returned die, will be used936// to create the logical scopes.937DWARFDie CUDie = CU->getNonSkeletonUnitDIE(938/*ExtractUnitDIEOnly=*/false,939/*DWOAlternativeLocation=*/DWOAlternativeLocation);940if (!CUDie.isValid())941continue;942943// The current unit corresponds to the .dwo file. We need to get the944// skeleton unit and query for any ranges that will enclose any ranges945// in the non-skeleton unit.946DWARFDie DummyDie;947DWARFDie SkeletonDie =948CUDie.getDwarfUnit()->isDWOUnit() ? CU->getUnitDIE(false) : DummyDie;949// Disable the ranges processing if we have just a single .dwo object,950// as any DW_AT_ranges will access not available range information.951RangesDataAvailable =952(!CUDie.getDwarfUnit()->isDWOUnit() ||953(SkeletonDie.isValid() ? !SkeletonDie.getDwarfUnit()->isDWOUnit()954: true));955956traverseDieAndChildren(CUDie, Root, SkeletonDie);957958createLineAndFileRecords(DwarfContext->getLineTableForUnit(CU.get()));959if (Error Err = createInstructions())960return Err;961962// Process the compilation unit, as there are cases where enclosed963// functions have the same ranges values. Insert the compilation unit964// ranges at the end, to allow enclosing ranges to be first in the list.965LVSectionIndex SectionIndex = getSectionIndex(CompileUnit);966addSectionRange(SectionIndex, CompileUnit);967LVRange *ScopesWithRanges = getSectionRanges(SectionIndex);968ScopesWithRanges->sort();969970processLines(&CULines, SectionIndex);971processLocationGaps();972973// These are per compile unit.974ScopesWithRanges->clear();975SymbolsWithLocations.clear();976CULines.clear();977}978979return Error::success();980}981982// Get the location information for the associated attribute.983void LVDWARFReader::processLocationList(dwarf::Attribute Attr,984const DWARFFormValue &FormValue,985const DWARFDie &Die,986uint64_t OffsetOnEntry,987bool CallSiteLocation) {988989auto ProcessLocationExpression = [&](const DWARFExpression &Expression) {990for (const DWARFExpression::Operation &Op : Expression)991CurrentSymbol->addLocationOperands(Op.getCode(), Op.getRawOperands());992};993994DWARFUnit *U = Die.getDwarfUnit();995DWARFContext &DwarfContext = U->getContext();996bool IsLittleEndian = DwarfContext.isLittleEndian();997if (FormValue.isFormClass(DWARFFormValue::FC_Block) ||998(DWARFAttribute::mayHaveLocationExpr(Attr) &&999FormValue.isFormClass(DWARFFormValue::FC_Exprloc))) {1000ArrayRef<uint8_t> Expr = *FormValue.getAsBlock();1001DataExtractor Data(StringRef((const char *)Expr.data(), Expr.size()),1002IsLittleEndian, 0);1003DWARFExpression Expression(Data, U->getAddressByteSize(),1004U->getFormParams().Format);10051006// Add location and operation entries.1007CurrentSymbol->addLocation(Attr, /*LowPC=*/0, /*HighPC=*/-1,1008/*SectionOffset=*/0, OffsetOnEntry,1009CallSiteLocation);1010ProcessLocationExpression(Expression);1011return;1012}10131014if (DWARFAttribute::mayHaveLocationList(Attr) &&1015FormValue.isFormClass(DWARFFormValue::FC_SectionOffset)) {1016uint64_t Offset = *FormValue.getAsSectionOffset();1017if (FormValue.getForm() == dwarf::DW_FORM_loclistx) {1018std::optional<uint64_t> LoclistOffset = U->getLoclistOffset(Offset);1019if (!LoclistOffset)1020return;1021Offset = *LoclistOffset;1022}1023uint64_t BaseAddr = 0;1024if (std::optional<SectionedAddress> BA = U->getBaseAddress())1025BaseAddr = BA->Address;1026LVAddress LowPC = 0;1027LVAddress HighPC = 0;10281029auto ProcessLocationEntry = [&](const DWARFLocationEntry &Entry) {1030if (Entry.Kind == dwarf::DW_LLE_base_address) {1031BaseAddr = Entry.Value0;1032return;1033}1034if (Entry.Kind == dwarf::DW_LLE_offset_pair) {1035LowPC = BaseAddr + Entry.Value0;1036HighPC = BaseAddr + Entry.Value1;1037DWARFAddressRange Range{LowPC, HighPC, Entry.SectionIndex};1038if (Range.SectionIndex == SectionedAddress::UndefSection)1039Range.SectionIndex = Entry.SectionIndex;1040DWARFLocationExpression Loc{Range, Entry.Loc};1041DWARFDataExtractor Data(Loc.Expr, IsLittleEndian,1042U->getAddressByteSize());1043DWARFExpression Expression(Data, U->getAddressByteSize());10441045// Store the real upper limit for the address range.1046if (UpdateHighAddress && HighPC > 0)1047--HighPC;1048// Add location and operation entries.1049CurrentSymbol->addLocation(Attr, LowPC, HighPC, Offset, OffsetOnEntry,1050CallSiteLocation);1051ProcessLocationExpression(Expression);1052}1053};1054Error E = U->getLocationTable().visitLocationList(1055&Offset, [&](const DWARFLocationEntry &E) {1056ProcessLocationEntry(E);1057return true;1058});1059if (E)1060consumeError(std::move(E));1061}1062}10631064void LVDWARFReader::processLocationMember(dwarf::Attribute Attr,1065const DWARFFormValue &FormValue,1066const DWARFDie &Die,1067uint64_t OffsetOnEntry) {1068// Check if the value is an integer constant.1069if (FormValue.isFormClass(DWARFFormValue::FC_Constant))1070// Add a record to hold a constant as location.1071CurrentSymbol->addLocationConstant(Attr, *FormValue.getAsUnsignedConstant(),1072OffsetOnEntry);1073else1074// This is a location description, or a reference to one.1075processLocationList(Attr, FormValue, Die, OffsetOnEntry);1076}10771078// Update the current element with the reference.1079void LVDWARFReader::updateReference(dwarf::Attribute Attr,1080const DWARFFormValue &FormValue) {1081// FIXME: We are assuming that at most one Reference (DW_AT_specification,1082// DW_AT_abstract_origin, ...) and at most one Type (DW_AT_import, DW_AT_type)1083// appear in any single DIE, but this may not be true.1084uint64_t Offset;1085if (std::optional<uint64_t> Off = FormValue.getAsRelativeReference())1086Offset = FormValue.getUnit()->getOffset() + *Off;1087else if (Off = FormValue.getAsDebugInfoReference(); Off)1088Offset = *Off;1089else1090llvm_unreachable("Unsupported reference type");10911092// Get target for the given reference, if already created.1093LVElement *Target = getElementForOffset(1094Offset, CurrentElement,1095/*IsType=*/Attr == dwarf::DW_AT_import || Attr == dwarf::DW_AT_type);1096// Check if we are dealing with cross CU references.1097if (FormValue.getForm() == dwarf::DW_FORM_ref_addr) {1098if (Target) {1099// The global reference is ready. Mark it as global.1100Target->setIsGlobalReference();1101// Remove global reference from the unseen list.1102removeGlobalOffset(Offset);1103} else1104// Record the unseen cross CU reference.1105addGlobalOffset(Offset);1106}11071108// At this point, 'Target' can be null, in the case of the target element1109// not being seen. But the correct bit is set, to indicate that the target1110// is being referenced by (abstract_origin, extension, specification) or1111// (import, type).1112// We must differentiate between the kind of reference. This is needed to1113// complete inlined function instances with dropped abstract references,1114// in order to facilitate a logical comparison.1115switch (Attr) {1116case dwarf::DW_AT_abstract_origin:1117case dwarf::DW_AT_call_origin:1118CurrentElement->setReference(Target);1119CurrentElement->setHasReferenceAbstract();1120break;1121case dwarf::DW_AT_extension:1122CurrentElement->setReference(Target);1123CurrentElement->setHasReferenceExtension();1124break;1125case dwarf::DW_AT_specification:1126CurrentElement->setReference(Target);1127CurrentElement->setHasReferenceSpecification();1128break;1129case dwarf::DW_AT_import:1130case dwarf::DW_AT_type:1131CurrentElement->setType(Target);1132break;1133default:1134break;1135}1136}11371138// Get an element given the DIE offset.1139LVElement *LVDWARFReader::getElementForOffset(LVOffset Offset,1140LVElement *Element, bool IsType) {1141auto Iter = ElementTable.try_emplace(Offset).first;1142// Update the element and all the references pointing to this element.1143LVElementEntry &Entry = Iter->second;1144if (!Entry.Element) {1145if (IsType)1146Entry.Types.insert(Element);1147else1148Entry.References.insert(Element);1149}1150return Entry.Element;1151}11521153Error LVDWARFReader::loadTargetInfo(const ObjectFile &Obj) {1154// Detect the architecture from the object file. We usually don't need OS1155// info to lookup a target and create register info.1156Triple TT;1157TT.setArch(Triple::ArchType(Obj.getArch()));1158TT.setVendor(Triple::UnknownVendor);1159TT.setOS(Triple::UnknownOS);11601161// Features to be passed to target/subtarget1162Expected<SubtargetFeatures> Features = Obj.getFeatures();1163SubtargetFeatures FeaturesValue;1164if (!Features) {1165consumeError(Features.takeError());1166FeaturesValue = SubtargetFeatures();1167}1168FeaturesValue = *Features;1169return loadGenericTargetInfo(TT.str(), FeaturesValue.getString());1170}11711172void LVDWARFReader::mapRangeAddress(const ObjectFile &Obj) {1173for (auto Iter = Obj.symbol_begin(); Iter != Obj.symbol_end(); ++Iter) {1174const SymbolRef &Symbol = *Iter;11751176Expected<SymbolRef::Type> TypeOrErr = Symbol.getType();1177if (!TypeOrErr) {1178consumeError(TypeOrErr.takeError());1179continue;1180}11811182// Process only symbols that represent a function.1183SymbolRef::Type Type = *TypeOrErr;1184if (Type != SymbolRef::ST_Function)1185continue;11861187// In the case of a Mach-O STAB symbol, get its section only if1188// the STAB symbol's section field refers to a valid section index.1189// Otherwise the symbol may error trying to load a section that1190// does not exist.1191const MachOObjectFile *MachO = dyn_cast<const MachOObjectFile>(&Obj);1192bool IsSTAB = false;1193if (MachO) {1194DataRefImpl SymDRI = Symbol.getRawDataRefImpl();1195uint8_t NType =1196(MachO->is64Bit() ? MachO->getSymbol64TableEntry(SymDRI).n_type1197: MachO->getSymbolTableEntry(SymDRI).n_type);1198if (NType & MachO::N_STAB)1199IsSTAB = true;1200}12011202Expected<section_iterator> IterOrErr = Symbol.getSection();1203if (!IterOrErr) {1204consumeError(IterOrErr.takeError());1205continue;1206}1207section_iterator Section = IsSTAB ? Obj.section_end() : *IterOrErr;1208if (Section == Obj.section_end())1209continue;12101211// Get the symbol value.1212Expected<uint64_t> AddressOrErr = Symbol.getAddress();1213if (!AddressOrErr) {1214consumeError(AddressOrErr.takeError());1215continue;1216}1217uint64_t Address = *AddressOrErr;12181219// Get symbol name.1220StringRef Name;1221Expected<StringRef> NameOrErr = Symbol.getName();1222if (!NameOrErr) {1223consumeError(NameOrErr.takeError());1224continue;1225}1226Name = *NameOrErr;12271228// Check if the symbol is Comdat.1229Expected<uint32_t> FlagsOrErr = Symbol.getFlags();1230if (!FlagsOrErr) {1231consumeError(FlagsOrErr.takeError());1232continue;1233}1234uint32_t Flags = *FlagsOrErr;12351236// Mark the symbol as 'comdat' in any of the following cases:1237// - Symbol has the SF_Weak flag or1238// - Symbol section index different from the DotTextSectionIndex.1239LVSectionIndex SectionIndex = Section->getIndex();1240bool IsComdat =1241(Flags & SymbolRef::SF_Weak) || (SectionIndex != DotTextSectionIndex);12421243// Record the symbol name (linkage) and its loading address.1244addToSymbolTable(Name, Address, SectionIndex, IsComdat);1245}1246}12471248void LVDWARFReader::sortScopes() { Root->sort(); }12491250void LVDWARFReader::print(raw_ostream &OS) const {1251OS << "LVType\n";1252LLVM_DEBUG(dbgs() << "CreateReaders\n");1253}125412551256