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();
664 "warning: Unable to retrieve DWO .debug_info section for some "
665 "object files. (Remove the --quiet flag for full output)",
669 {dwarf::DW_AT_dwo_name, dwarf::DW_AT_GNU_dwo_name}),
671 OS <<
"warning: Unable to retrieve DWO .debug_info section for "
680 if (NumThreads == 1) {
683 for (
const auto &
CU : DICtx.compile_units()) {
686 handleDie(Out, CUI, Die);
696 for (
const auto &
CU : DICtx.compile_units())
697 CU->getAbbreviations();
702 for (
const auto &
CU : DICtx.compile_units())
703 pool.
async([&
CU]() {
CU->getUnitDIE(
false ); });
708 for (
const auto &
CU : DICtx.compile_units()) {
712 pool.
async([
this, CUI, &LogMutex, &Out, Die]()
mutable {
716 handleDie(ThreadOut, CUI, Die);
718 std::lock_guard<std::mutex> guard(LogMutex);
722 Out.
Merge(ThreadOut);
728 size_t FunctionsAddedCount = Gsym.getNumFunctionInfos() - NumBefore;
729 Out <<
"Loaded " << FunctionsAddedCount <<
" functions from DWARF.\n";
735 Out <<
"Verifying GSYM file \"" << GsymPath <<
"\":\n";
741 std::unique_ptr<GsymReader> &Gsym = *GsymOrErr;
743 auto NumAddrs = Gsym->getNumAddresses();
746 DILineInfoSpecifier::FunctionNameKind::LinkageName);
747 std::string gsymFilename;
749 auto FuncAddr = Gsym->getAddress(
I);
752 "failed to extract address[%i]",
I);
754 auto FI = Gsym->getFunctionInfo(*FuncAddr);
757 std::errc::invalid_argument,
758 "failed to extract function info for address 0x%" PRIu64, *FuncAddr);
760 for (
auto Addr = *FuncAddr; Addr < *FuncAddr + FI->
size(); ++Addr) {
763 auto LR = Gsym->lookup(Addr);
765 return LR.takeError();
767 auto DwarfInlineInfos =
768 DICtx.getInliningInfoForAddress(SectAddr, DLIS);
769 uint32_t NumDwarfInlineInfos = DwarfInlineInfos.getNumberOfFrames();
770 if (NumDwarfInlineInfos == 0) {
771 DwarfInlineInfos.addFrame(
772 DICtx.getLineInfoForAddress(SectAddr, DLIS).value_or(
DILineInfo()));
776 if (NumDwarfInlineInfos == 1 &&
777 DwarfInlineInfos.getFrame(0).FileName ==
"<invalid>") {
779 NumDwarfInlineInfos = 0;
781 if (NumDwarfInlineInfos > 0 &&
782 NumDwarfInlineInfos != LR->Locations.size()) {
785 Log <<
"error: address " <<
HEX64(Addr) <<
" has "
786 << NumDwarfInlineInfos <<
" DWARF inline frames and GSYM has "
787 << LR->Locations.size() <<
"\n";
788 Log <<
" " << NumDwarfInlineInfos <<
" DWARF frames:\n";
789 for (
size_t Idx = 0; Idx < NumDwarfInlineInfos; ++Idx) {
790 const auto &dii = DwarfInlineInfos.getFrame(Idx);
791 Log <<
" [" << Idx <<
"]: " << dii.FunctionName <<
" @ "
792 << dii.FileName <<
':' << dii.Line <<
'\n';
794 Log <<
" " << LR->Locations.size() <<
" GSYM frames:\n";
795 for (
size_t Idx = 0,
count = LR->Locations.size(); Idx <
count;
797 const auto &gii = LR->Locations[Idx];
798 Log <<
" [" << Idx <<
"]: " << gii.Name <<
" @ " << gii.Dir
799 <<
'/' << gii.Base <<
':' << gii.Line <<
'\n';
801 Gsym->dump(Log, *FI);
806 for (
size_t Idx = 0,
count = LR->Locations.size(); Idx <
count;
808 const auto &gii = LR->Locations[Idx];
809 if (Idx < NumDwarfInlineInfos) {
810 const auto &dii = DwarfInlineInfos.getFrame(Idx);
811 gsymFilename = LR->getSourceFile(Idx);
814 Out <<
"error: address " <<
HEX64(Addr) <<
" DWARF function \""
815 << dii.FunctionName.c_str()
816 <<
"\" doesn't match GSYM function \"" << gii.Name <<
"\"\n";
819 if (dii.FileName != gsymFilename)
820 Out <<
"error: address " <<
HEX64(Addr) <<
" DWARF path \""
821 << dii.FileName.c_str() <<
"\" doesn't match GSYM path \""
822 << gsymFilename.c_str() <<
"\"\n";
824 if (dii.Line != gii.Line)
825 Out <<
"error: address " <<
HEX64(Addr) <<
" DWARF line "
826 << 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