52 return Addr == UINT32_MAX;
72 if (GsymFileIdx != UINT32_MAX)
101 if (Die.
getTag() == dwarf::DW_TAG_inlined_subroutine)
108 switch (ParentDie.
getTag()) {
109 case dwarf::DW_TAG_namespace:
110 case dwarf::DW_TAG_structure_type:
111 case dwarf::DW_TAG_union_type:
112 case dwarf::DW_TAG_class_type:
113 case dwarf::DW_TAG_subprogram:
115 case dwarf::DW_TAG_lexical_block:
131static std::optional<gsym_strp_t>
145 if (!(Language == dwarf::DW_LANG_C_plus_plus ||
146 Language == dwarf::DW_LANG_C_plus_plus_03 ||
147 Language == dwarf::DW_LANG_C_plus_plus_11 ||
148 Language == dwarf::DW_LANG_C_plus_plus_14 ||
149 Language == dwarf::DW_LANG_ObjC_plus_plus ||
152 Language == dwarf::DW_LANG_C))
163 if (ParentDeclCtxDie) {
165 while (ParentDeclCtxDie) {
167 if (!ParentName.
empty()) {
171 if (ParentName.
front() ==
'<' && ParentName.
back() ==
'>')
172 Name =
"{" + ParentName.
substr(1, ParentName.
size() - 2).
str() +
"}" +
175 Name = ParentName.
str() +
"::" + Name;
187 bool CheckChildren =
true;
189 case dwarf::DW_TAG_subprogram:
191 CheckChildren =
Depth == 0;
193 case dwarf::DW_TAG_inlined_subroutine:
211 if (DwarfRange.LowPC < DwarfRange.HighPC)
212 Ranges.insert({DwarfRange.LowPC, DwarfRange.HighPC});
226 if (Tag == dwarf::DW_TAG_inlined_subroutine) {
234 for (
const AddressRange &InlineRange : AllInlineRanges) {
237 if (InlineRange.empty()) {
241 II.Ranges.insert(InlineRange);
250 if (AllParentRanges.
contains(InlineRange)) {
253 Out.
Report(
"Function DIE has uncontained address range",
255 OS <<
"error: inlined function DIE at "
257 <<
HEX64(InlineRange.start()) <<
" - "
258 <<
HEX64(InlineRange.end())
259 <<
") that isn't contained in "
260 <<
"any parent address ranges, this inline range "
270 if (EmptyCount == AllInlineRanges.size())
273 if (
II.Ranges.empty())
277 II.Name = *NameIndex;
280 std::optional<uint32_t> OptGSymFileIdx =
282 if (OptGSymFileIdx) {
283 II.CallFile = OptGSymFileIdx.value();
288 AllInlineRanges, WarnIfEmpty);
292 "Inlined function die has invlaid file index in DW_AT_call_file",
295 <<
" has an invalid file index " << DwarfFileIdx
296 <<
" in its DW_AT_call_file attribute, this inline entry and "
298 <<
"children will be removed.\n";
302 if (Tag == dwarf::DW_TAG_subprogram || Tag == dwarf::DW_TAG_lexical_block) {
306 AllParentRanges, WarnIfEmpty);
313 std::vector<uint32_t> RowVector;
316 const uint64_t RangeSize = EndAddress - StartAddress;
321 std::optional<uint64_t> StmtSeqOffset;
322 if (
auto StmtSeqAttr = Die.
find(llvm::dwarf::DW_AT_LLVM_stmt_sequence)) {
332 if (StmtSeqVal != InvalidOffset)
333 StmtSeqOffset = StmtSeqVal;
343 Out.
Report(
"Invalid DW_AT_LLVM_stmt_sequence value",
346 <<
" has a DW_AT_LLVM_stmt_sequence value "
347 <<
HEX32(*StmtSeqOffset)
348 <<
" which doesn't match any line table "
349 <<
"sequence offset but there are " << RowVector.size()
350 <<
" matching line entries in other sequences.\n";
357 if (FilePath.empty()) {
364 if (DwarfFileIdx == UINT32_MAX)
369 <<
" has an invalid file index " << DwarfFileIdx
370 <<
" in its DW_AT_decl_file attribute, unable to create a single "
371 <<
"line entry from the DW_AT_decl_file/DW_AT_decl_line "
388 for (
uint32_t RowIndex : RowVector) {
391 std::optional<uint32_t> OptFileIdx =
395 "Invalid file index in DWARF line table", [&](
raw_ostream &OS) {
396 OS <<
"error: function DIE at " <<
HEX32(Die.
getOffset()) <<
" has "
397 <<
"a line entry with invalid DWARF file index, this entry will "
399 Row.dumpTableHeader(OS, 0);
405 const uint32_t FileIdx = OptFileIdx.value();
406 uint64_t RowAddress = Row.Address.Address;
415 Out.
Report(
"Start address lies between valid Row table entries",
417 OS <<
"error: DIE has a start address whose LowPC is "
420 << RowIndex <<
"] with address " <<
HEX64(RowAddress)
421 <<
" and the next one.\n";
430 LineEntry LE(RowAddress, FileIdx, Row.Line);
431 if (RowIndex != RowVector[0] && Row.Address < PrevRow.
Address) {
439 if (FirstLE && *FirstLE == LE)
442 OS <<
"warning: duplicate line table detected for DIE:\n";
446 Out.
Report(
"Non-monotonically increasing addresses",
448 OS <<
"error: line table has addresses that do not "
449 <<
"monotonically increase:\n";
450 for (
uint32_t RowIndex2 : RowVector)
459 if (LastLE && LastLE->File == FileIdx && LastLE->Line == Row.Line)
464 if (Row.EndSequence) {
484 case dwarf::DW_TAG_subprogram: {
486 if (!RangesOrError) {
495 Out.
Report(
"Function has no name", [&](raw_ostream &OS) {
497 <<
" has no name\n ";
511 for (
const DWARFAddressRange &
Range : Ranges) {
527 if (!Gsym.IsValidTextAddress(
Range.LowPC)) {
532 if (
Range.LowPC != 0) {
533 if (!Gsym.isQuiet()) {
535 Out.
Report(
"Address range starts outside executable section",
536 [&](raw_ostream &OS) {
537 OS <<
"warning: DIE has an address range whose "
539 "is not in any executable sections ("
540 << *Gsym.GetValidTextRanges()
541 <<
") and will not be processed:\n";
551 FI.
Name = *NameIndex;
557 FI.
Inline->Name = *NameIndex;
559 bool WarnIfEmpty =
true;
561 AllSubprogramRanges, WarnIfEmpty);
571 if (FI.
Inline->Children.empty()) {
572 if (WarnIfEmpty && !Gsym.isQuiet())
573 Out.
Report(
"DIE contains inline functions with no valid ranges",
574 [&](raw_ostream &OS) {
575 OS <<
"warning: DIE contains inline function "
576 "information that has no valid ranges, removing "
577 "inline information:\n";
585 if (LoadDwarfCallSites)
586 parseCallSiteInfoFromDwarf(CUI, Die, FI);
588 Gsym.addFunctionInfo(std::move(FI));
594 for (DWARFDie ChildDie : Die.
children())
595 handleDie(Out, CUI, ChildDie);
598void DwarfTransformer::parseCallSiteInfoFromDwarf(
CUInfo &CUI, DWARFDie Die,
607 CallSiteInfoCollection CSIC;
609 for (DWARFDie Child : Die.
children()) {
610 if (Child.getTag() != dwarf::DW_TAG_call_site)
625 if (DWARFDie OriginDie =
626 Child.getAttributeValueAsReferencedDie(dwarf::DW_AT_call_origin)) {
629 if (
const char *LinkName = OriginDie.getLinkageName()) {
630 gsym_strp_t LinkNameOff = Gsym.insertString(LinkName,
false);
632 }
else if (
const char *
ShortName = OriginDie.getShortName()) {
654 size_t NumBefore = Gsym.getNumFunctionInfos();
665 "warning: Unable to retrieve DWO .debug_info section for some "
666 "object files. (Remove the --quiet flag for full output)",
670 {dwarf::DW_AT_dwo_name, dwarf::DW_AT_GNU_dwo_name}),
672 OS <<
"warning: Unable to retrieve DWO .debug_info section for "
681 if (NumThreads == 1) {
684 for (
const auto &
CU : DICtx.compile_units()) {
687 handleDie(Out, CUI, Die);
697 for (
const auto &
CU : DICtx.compile_units())
698 CU->getAbbreviations();
703 for (
const auto &
CU : DICtx.compile_units())
704 pool.
async([&
CU]() {
CU->getUnitDIE(
false ); });
709 for (
const auto &
CU : DICtx.compile_units()) {
713 pool.
async([
this, CUI, &LogMutex, &Out, Die]()
mutable {
717 handleDie(ThreadOut, CUI, Die);
719 std::lock_guard<std::mutex> guard(LogMutex);
723 Out.
Merge(ThreadOut);
729 size_t FunctionsAddedCount = Gsym.getNumFunctionInfos() - NumBefore;
730 Out <<
"Loaded " << FunctionsAddedCount <<
" functions from DWARF.\n";
736 Out <<
"Verifying GSYM file \"" << GsymPath <<
"\":\n";
742 std::unique_ptr<GsymReader> &Gsym = *GsymOrErr;
744 auto NumAddrs = Gsym->getNumAddresses();
747 DILineInfoSpecifier::FunctionNameKind::LinkageName);
748 std::string gsymFilename;
750 auto FuncAddr = Gsym->getAddress(
I);
753 "failed to extract address[%i]",
I);
755 auto FI = Gsym->getFunctionInfo(*FuncAddr);
758 std::errc::invalid_argument,
759 "failed to extract function info for address 0x%" PRIu64, *FuncAddr);
761 for (
auto Addr = *FuncAddr; Addr < *FuncAddr + FI->
size(); ++Addr) {
764 auto LR = Gsym->lookup(Addr);
766 return LR.takeError();
768 auto DwarfInlineInfos =
769 DICtx.getInliningInfoForAddress(SectAddr, DLIS);
770 uint32_t NumDwarfInlineInfos = DwarfInlineInfos.getNumberOfFrames();
771 if (NumDwarfInlineInfos == 0) {
772 DwarfInlineInfos.addFrame(
773 DICtx.getLineInfoForAddress(SectAddr, DLIS).value_or(
DILineInfo()));
777 if (NumDwarfInlineInfos == 1 &&
778 DwarfInlineInfos.getFrame(0).FileName ==
"<invalid>") {
780 NumDwarfInlineInfos = 0;
782 if (NumDwarfInlineInfos > 0 &&
783 NumDwarfInlineInfos != LR->Locations.size()) {
786 Log <<
"error: address " <<
HEX64(Addr) <<
" has "
787 << NumDwarfInlineInfos <<
" DWARF inline frames and GSYM has "
788 << LR->Locations.size() <<
"\n";
789 Log <<
" " << NumDwarfInlineInfos <<
" DWARF frames:\n";
790 for (
size_t Idx = 0; Idx < NumDwarfInlineInfos; ++Idx) {
791 const auto &dii = DwarfInlineInfos.getFrame(Idx);
792 Log <<
" [" << Idx <<
"]: " << dii.FunctionName <<
" @ "
793 << dii.FileName <<
':' << dii.Line <<
'\n';
795 Log <<
" " << LR->Locations.size() <<
" GSYM frames:\n";
796 for (
size_t Idx = 0,
count = LR->Locations.size(); Idx <
count;
798 const auto &gii = LR->Locations[Idx];
799 Log <<
" [" << Idx <<
"]: " << gii.Name <<
" @ " << gii.Dir
800 <<
'/' << gii.Base <<
':' << gii.Line <<
'\n';
802 Gsym->dump(Log, *FI);
807 for (
size_t Idx = 0,
count = LR->Locations.size(); Idx <
count;
809 const auto &gii = LR->Locations[Idx];
810 if (Idx < NumDwarfInlineInfos) {
811 const auto &dii = DwarfInlineInfos.getFrame(Idx);
812 gsymFilename = LR->getSourceFile(Idx);
815 Out <<
"error: address " <<
HEX64(Addr) <<
" DWARF function \""
816 << dii.FunctionName.c_str()
817 <<
"\" doesn't match GSYM function \"" << gii.Name <<
"\"\n";
820 if (dii.FileName != gsymFilename)
821 Out <<
"error: address " <<
HEX64(Addr) <<
" DWARF path \""
822 << dii.FileName.c_str() <<
"\" doesn't match GSYM path \""
823 << gsymFilename.c_str() <<
"\"\n";
825 if (dii.Line != gii.Line)
826 Out <<
"error: address " <<
HEX64(Addr) <<
" DWARF line "
827 << dii.Line <<
" != GSYM line " << gii.Line <<
"\n";
ConstantRange Range(APInt(BitWidth, Low), APInt(BitWidth, High))
uint64_t IntrinsicInst * II
A class that represents an address range.
bool contains(uint64_t Addr) const
bool contains(uint64_t Addr) const
The AddressRanges class helps normalize address range collections.
A format-neutral container for inlined code description.
DWARFContext This data structure is the top level entity that deals with dwarf debug information pars...
const DWARFDebugLine::LineTable * getLineTableForUnit(DWARFUnit *U)
Get a pointer to a parsed line table corresponding to a compile unit.
Utility class that carries the DWARF compile/type unit and the debug info entry in an object.
uint64_t getOffset() const
Get the absolute offset into the debug info or types section.
LLVM_ABI Expected< DWARFAddressRangesVector > getAddressRanges() const
Get the address ranges for this DIE.
iterator_range< iterator > children() const
LLVM_ABI DWARFDie getAttributeValueAsReferencedDie(dwarf::Attribute Attr) const
Extract the specified attribute from this DIE as the referenced DIE.
LLVM_ABI DWARFDie getParent() const
Get the parent of this DIE object.
LLVM_ABI std::optional< DWARFFormValue > find(dwarf::Attribute Attr) const
Extract the specified attribute from this DIE.
DWARFUnit * getDwarfUnit() const
LLVM_ABI std::optional< DWARFFormValue > findRecursively(ArrayRef< dwarf::Attribute > Attrs) const
Extract the first value of any attribute in Attrs from this DIE and recurse into any DW_AT_specificat...
LLVM_ABI const char * getName(DINameKind Kind) const
Return the DIE name resolving DW_AT_specification or DW_AT_abstract_origin references if necessary.
LLVM_ABI std::string getDeclFile(DILineInfoSpecifier::FileLineInfoKind Kind) const
dwarf::Tag getTag() const
LLVM_ABI const char * getLinkageName() const
Return the DIE linkage name resolving DW_AT_specification or DW_AT_abstract_origin references if nece...
LLVM_ABI void dump(raw_ostream &OS, unsigned indent=0, DIDumpOptions DumpOpts=DIDumpOptions()) const
Dump the DIE and all of its attributes to the supplied stream.
const dwarf::FormParams & getFormParams() const
DWARFDie getUnitDIE(bool ExtractUnitDIEOnly=true)
This dwarf writer support class manages information associated with a source file.
Lightweight error class with error context and mandatory checking.
static ErrorSuccess success()
Create a success value.
Tagged union holding either a T or a Error.
Error takeError()
Take ownership of the stored error.
reference get()
Returns a reference to the stored T value.
void wait() override
Blocking wait for all the tasks to execute first.
Represent a constant reference to a string, i.e.
std::string str() const
Get the contents as an std::string.
constexpr StringRef substr(size_t Start, size_t N=npos) const
Return a reference to the substring from [Start, Start + N).
bool starts_with(StringRef Prefix) const
Check if this string starts with the given Prefix.
constexpr bool empty() const
Check if the string is empty.
char back() const
Get the last character in the string.
constexpr size_t size() const
Get the string size.
char front() const
Get the first character in the string.
auto async(Function &&F, Args &&...ArgList)
Asynchronous submission of a task to the pool.
GsymCreator is used to emit GSYM data to a stand alone file or section within a file.
LLVM_ABI gsym_strp_t insertString(StringRef S, bool Copy=true)
Insert a string into the GSYM string table.
LLVM_ABI uint32_t insertFile(StringRef Path, sys::path::Style Style=sys::path::Style::native)
Insert a file into this GSYM creator.
static LLVM_ABI llvm::Expected< std::unique_ptr< GsymReader > > openFile(StringRef Path)
Construct a GsymReader from a file on disk.
LineTable class contains deserialized versions of line tables for each function's address ranges.
void Report(StringRef s, std::function< void(raw_ostream &o)> detailCallback)
raw_ostream * GetOS() const
void Merge(const OutputAggregator &other)
This class implements an extremely fast bulk output stream that can only output to a stream.
A raw_ostream that writes to an std::string.
std::optional< uint64_t > toAddress(const std::optional< DWARFFormValue > &V)
Take an optional DWARFFormValue and try to extract an address.
std::optional< const char * > toString(const std::optional< DWARFFormValue > &V)
Take an optional DWARFFormValue and try to extract a string value from it.
std::optional< uint64_t > toSectionOffset(const std::optional< DWARFFormValue > &V)
Take an optional DWARFFormValue and try to extract an section offset.
std::optional< uint64_t > toUnsigned(const std::optional< DWARFFormValue > &V)
Take an optional DWARFFormValue and try to extract an unsigned constant.
uint64_t gsym_strp_t
The type of string offset used in the code.
This is an optimization pass for GlobalISel generic memory operations.
ThreadPoolStrategy hardware_concurrency(unsigned ThreadCount=0)
Returns a default thread strategy where all available hardware resources are to be used,...
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
void append_range(Container &C, Range &&R)
Wrapper function to append range R to container C.
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
auto count(R &&Range, const E &Element)
Wrapper function around std::count to count the number of times an element Element occurs in the give...
SingleThreadExecutor DefaultThreadPool
void consumeError(Error Err)
Consume a Error without doing anything.
std::vector< DWARFAddressRange > DWARFAddressRangesVector
DWARFAddressRangesVector - represents a set of absolute address ranges.
static DIDumpOptions getForSingleDIE()
Return default option set for printing a single DIE without children.
Controls which fields of DILineInfo container should be filled with data.
A format-neutral container for source line information.
LLVM_ABI bool lookupAddressRange(object::SectionedAddress Address, uint64_t Size, std::vector< uint32_t > &Result, std::optional< uint64_t > StmtSequenceOffset=std::nullopt) const
Fills the Result argument with the indices of the rows that correspond to the address range specified...
Standard .debug_line state machine structure.
object::SectionedAddress Address
The program-counter value corresponding to a machine instruction generated by the compiler and sectio...
const DWARFDebugLine::LineTable * LineTable
std::optional< uint32_t > DWARFToGSYMFileIndex(GsymCreator &Gsym, uint32_t DwarfFileIdx)
Convert a DWARF compile unit file index into a GSYM global file index.
CUInfo(DWARFContext &DICtx, DWARFCompileUnit *CU)
bool isHighestAddress(uint64_t Addr) const
Return true if Addr is the highest address for a given compile unit.
std::vector< uint32_t > FileCache
std::vector< CallSiteInfo > CallSites
uint64_t ReturnOffset
The return offset of the call site - relative to the function start.
std::vector< gsym_strp_t > MatchRegex
Offsets into the string table for function names regex patterns.
Function information in GSYM files encodes information for one contiguous address range.
std::optional< InlineInfo > Inline
uint64_t startAddress() const
uint64_t endAddress() const
std::optional< CallSiteInfoCollection > CallSites
gsym_strp_t Name
String table offset in the string table.
std::optional< LineTable > OptLineTable
Inline information stores the name of the inline function along with an array of address ranges.
std::vector< InlineInfo > Children
Line entries are used to encode the line tables in FunctionInfo objects.
static const uint64_t UndefSection