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)
441 OS <<
"warning: duplicate line table detected for DIE:\n";
445 Out.
Report(
"Non-monotonically increasing addresses",
447 OS <<
"error: line table has addresses that do not "
448 <<
"monotonically increase:\n";
449 for (
uint32_t RowIndex2 : RowVector)
458 if (LastLE && LastLE->File == FileIdx && LastLE->Line == Row.Line)
463 if (Row.EndSequence) {
483 case dwarf::DW_TAG_subprogram: {
485 if (!RangesOrError) {
494 Out.
Report(
"Function has no name", [&](raw_ostream &OS) {
496 <<
" has no name\n ";
510 for (
const DWARFAddressRange &
Range : Ranges) {
526 if (!Gsym.IsValidTextAddress(
Range.LowPC)) {
531 if (
Range.LowPC != 0) {
533 Out.
Report(
"Address range starts outside executable section",
534 [&](raw_ostream &OS) {
535 OS <<
"warning: DIE has an address range whose "
537 "is not in any executable sections ("
538 << *Gsym.GetValidTextRanges()
539 <<
") and will not be processed:\n";
548 FI.
Name = *NameIndex;
554 FI.
Inline->Name = *NameIndex;
556 bool WarnIfEmpty =
true;
558 AllSubprogramRanges, WarnIfEmpty);
568 if (FI.
Inline->Children.empty()) {
570 Out.
Report(
"DIE contains inline functions with no valid ranges",
571 [&](raw_ostream &OS) {
572 OS <<
"warning: DIE contains inline function "
573 "information that has no valid ranges, removing "
574 "inline information:\n";
582 if (LoadDwarfCallSites)
583 parseCallSiteInfoFromDwarf(CUI, Die, FI);
585 Gsym.addFunctionInfo(std::move(FI));
591 for (DWARFDie ChildDie : Die.
children())
592 handleDie(Out, CUI, ChildDie);
595void DwarfTransformer::parseCallSiteInfoFromDwarf(
CUInfo &CUI, DWARFDie Die,
604 CallSiteInfoCollection CSIC;
606 for (DWARFDie Child : Die.
children()) {
607 if (Child.getTag() != dwarf::DW_TAG_call_site)
622 if (DWARFDie OriginDie =
623 Child.getAttributeValueAsReferencedDie(dwarf::DW_AT_call_origin)) {
626 if (
const char *LinkName = OriginDie.getLinkageName()) {
627 gsym_strp_t LinkNameOff = Gsym.insertString(LinkName,
false);
629 }
else if (
const char *
ShortName = OriginDie.getShortName()) {
651 size_t NumBefore = Gsym.getNumFunctionInfos();
661 "warning: Unable to retrieve DWO .debug_info section for some "
662 "object files. (Remove the --quiet flag for full output)",
666 {dwarf::DW_AT_dwo_name, dwarf::DW_AT_GNU_dwo_name}),
668 OS <<
"warning: Unable to retrieve DWO .debug_info section for "
677 if (NumThreads == 1) {
680 for (
const auto &
CU : DICtx.compile_units()) {
683 handleDie(Out, CUI, Die);
693 for (
const auto &
CU : DICtx.compile_units())
694 CU->getAbbreviations();
699 for (
const auto &
CU : DICtx.compile_units())
700 pool.
async([&
CU]() {
CU->getUnitDIE(
false ); });
705 for (
const auto &
CU : DICtx.compile_units()) {
709 pool.
async([
this, CUI, &LogMutex, &Out, Die]()
mutable {
714 handleDie(ThreadOut, CUI, Die);
716 std::lock_guard<std::mutex> guard(LogMutex);
720 Out.
Merge(ThreadOut);
726 size_t FunctionsAddedCount = Gsym.getNumFunctionInfos() - NumBefore;
727 Out <<
"Loaded " << FunctionsAddedCount <<
" functions from DWARF.\n";
733 Out <<
"Verifying GSYM file \"" << GsymPath <<
"\":\n";
739 std::unique_ptr<GsymReader> &Gsym = *GsymOrErr;
741 auto NumAddrs = Gsym->getNumAddresses();
744 DILineInfoSpecifier::FunctionNameKind::LinkageName);
745 std::string gsymFilename;
747 auto FuncAddr = Gsym->getAddress(
I);
750 "failed to extract address[%i]",
I);
752 auto FI = Gsym->getFunctionInfo(*FuncAddr);
755 std::errc::invalid_argument,
756 "failed to extract function info for address 0x%" PRIu64, *FuncAddr);
758 for (
auto Addr = *FuncAddr; Addr < *FuncAddr + FI->
size(); ++Addr) {
761 auto LR = Gsym->lookup(Addr);
763 return LR.takeError();
765 auto DwarfInlineInfos =
766 DICtx.getInliningInfoForAddress(SectAddr, DLIS);
767 uint32_t NumDwarfInlineInfos = DwarfInlineInfos.getNumberOfFrames();
768 if (NumDwarfInlineInfos == 0) {
769 DwarfInlineInfos.addFrame(
770 DICtx.getLineInfoForAddress(SectAddr, DLIS).value_or(
DILineInfo()));
774 if (NumDwarfInlineInfos == 1 &&
775 DwarfInlineInfos.getFrame(0).FileName ==
"<invalid>") {
777 NumDwarfInlineInfos = 0;
779 if (NumDwarfInlineInfos > 0 &&
780 NumDwarfInlineInfos != LR->Locations.size()) {
783 Log <<
"error: address " <<
HEX64(Addr) <<
" has "
784 << NumDwarfInlineInfos <<
" DWARF inline frames and GSYM has "
785 << LR->Locations.size() <<
"\n";
786 Log <<
" " << NumDwarfInlineInfos <<
" DWARF frames:\n";
787 for (
size_t Idx = 0; Idx < NumDwarfInlineInfos; ++Idx) {
788 const auto &dii = DwarfInlineInfos.getFrame(Idx);
789 Log <<
" [" << Idx <<
"]: " << dii.FunctionName <<
" @ "
790 << dii.FileName <<
':' << dii.Line <<
'\n';
792 Log <<
" " << LR->Locations.size() <<
" GSYM frames:\n";
793 for (
size_t Idx = 0,
count = LR->Locations.size(); Idx <
count;
795 const auto &gii = LR->Locations[Idx];
796 Log <<
" [" << Idx <<
"]: " << gii.Name <<
" @ " << gii.Dir
797 <<
'/' << gii.Base <<
':' << gii.Line <<
'\n';
799 Gsym->dump(Log, *FI);
804 for (
size_t Idx = 0,
count = LR->Locations.size(); Idx <
count;
806 const auto &gii = LR->Locations[Idx];
807 if (Idx < NumDwarfInlineInfos) {
808 const auto &dii = DwarfInlineInfos.getFrame(Idx);
809 gsymFilename = LR->getSourceFile(Idx);
812 Out <<
"error: address " <<
HEX64(Addr) <<
" DWARF function \""
813 << dii.FunctionName.c_str()
814 <<
"\" doesn't match GSYM function \"" << gii.Name <<
"\"\n";
817 if (dii.FileName != gsymFilename)
818 Out <<
"error: address " <<
HEX64(Addr) <<
" DWARF path \""
819 << dii.FileName.c_str() <<
"\" doesn't match GSYM path \""
820 << gsymFilename.c_str() <<
"\"\n";
822 if (dii.Line != gii.Line)
823 Out <<
"error: address " <<
HEX64(Addr) <<
" DWARF line "
824 << 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