Skip to content

Commit 40a1484

Browse files
author
Alex B
committed
[llvm-gsymutil] Add option to load callsites from DWARF
1 parent 1961138 commit 40a1484

File tree

5 files changed

+77
-3
lines changed

5 files changed

+77
-3
lines changed

llvm/include/llvm/DebugInfo/GSYM/DwarfTransformer.h

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,19 @@ class OutputAggregator;
3232
/// function information. Creating a separate class to transform this data
3333
/// allows this class to be unit tested.
3434
class DwarfTransformer {
35-
public:
3635

36+
public:
3737
/// Create a DWARF transformer.
3838
///
3939
/// \param D The DWARF to use when converting to GSYM.
4040
///
4141
/// \param G The GSYM creator to populate with the function information
4242
/// from the debug info.
43-
DwarfTransformer(DWARFContext &D, GsymCreator &G) : DICtx(D), Gsym(G) {}
43+
///
44+
/// \param LDCS Flag to indicate weather we should load the call site
45+
/// information from DWARF `DW_TAG_call_site` entries
46+
DwarfTransformer(DWARFContext &D, GsymCreator &G, bool LDCS = false)
47+
: DICtx(D), Gsym(G), LoadDwarfCallSites(LDCS) {}
4448

4549
/// Extract the DWARF from the supplied object file and convert it into the
4650
/// Gsym format in the GsymCreator object that is passed in. Returns an
@@ -83,8 +87,16 @@ class DwarfTransformer {
8387
/// \param Die The DWARF debug info entry to parse.
8488
void handleDie(OutputAggregator &Strm, CUInfo &CUI, DWARFDie Die);
8589

90+
/// Parse call site information from DWARF
91+
///
92+
/// \param CUI The compile unit info for the current CU.
93+
/// \param Die The DWARFDie for the function.
94+
/// \param FI The FunctionInfo for the function being populated.
95+
void parseCallSiteInfoFromDwarf(CUInfo &CUI, DWARFDie Die, FunctionInfo &FI);
96+
8697
DWARFContext &DICtx;
8798
GsymCreator &Gsym;
99+
bool LoadDwarfCallSites;
88100

89101
friend class DwarfTransformerTest;
90102
};

llvm/lib/DebugInfo/GSYM/DwarfTransformer.cpp

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -543,6 +543,11 @@ void DwarfTransformer::handleDie(OutputAggregator &Out, CUInfo &CUI,
543543
FI.Inline = std::nullopt;
544544
}
545545
}
546+
547+
// If dwarf-callsites flag is set, parse DW_TAG_call_site DIEs.
548+
if (LoadDwarfCallSites)
549+
parseCallSiteInfoFromDwarf(CUI, Die, FI);
550+
546551
Gsym.addFunctionInfo(std::move(FI));
547552
}
548553
} break;
@@ -553,6 +558,57 @@ void DwarfTransformer::handleDie(OutputAggregator &Out, CUInfo &CUI,
553558
handleDie(Out, CUI, ChildDie);
554559
}
555560

561+
void DwarfTransformer::parseCallSiteInfoFromDwarf(CUInfo &CUI, DWARFDie Die,
562+
FunctionInfo &FI) {
563+
// Parse all DW_TAG_call_site DIEs that are children of this subprogram DIE.
564+
// DWARF specification:
565+
// - DW_TAG_call_site can have DW_AT_call_return_pc for return address offset.
566+
// - DW_AT_call_origin might point to a DIE of the function being called.
567+
// For simplicity, we will just extract return_offset and possibly target name
568+
// if available.
569+
570+
CallSiteInfoCollection CSIC;
571+
572+
for (DWARFDie Child : Die.children()) {
573+
if (Child.getTag() == dwarf::DW_TAG_call_site) {
574+
CallSiteInfo CSI;
575+
// DW_AT_call_return_pc: the return PC (address). We'll convert it to
576+
// offset relative to FI's start.
577+
uint64_t ReturnPC =
578+
dwarf::toAddress(Child.find(dwarf::DW_AT_call_return_pc), 0);
579+
if (ReturnPC < FI.startAddress() || ReturnPC >= FI.endAddress())
580+
continue;
581+
582+
CSI.ReturnOffset = ReturnPC - FI.startAddress();
583+
584+
// Attempt to get function name from DW_AT_call_origin. If present, we can
585+
// insert it as a match regex.
586+
if (DWARFDie OriginDie = Child.getAttributeValueAsReferencedDie(
587+
dwarf::DW_AT_call_origin)) {
588+
if (auto Name = OriginDie.getName(DINameKind::ShortName)) {
589+
uint32_t NameOff = Gsym.insertString(Name, /*Copy=*/false);
590+
CSI.MatchRegex.push_back(NameOff);
591+
}
592+
}
593+
594+
// For now, we won't attempt to deduce InternalCall/ExternalCall flags
595+
// from DWARF.
596+
CSI.Flags = CallSiteInfo::Flags::None;
597+
598+
CSIC.CallSites.push_back(CSI);
599+
}
600+
}
601+
602+
if (!CSIC.CallSites.empty()) {
603+
if (!FI.CallSites)
604+
FI.CallSites = CallSiteInfoCollection();
605+
// Append parsed DWARF callsites:
606+
FI.CallSites->CallSites.insert(FI.CallSites->CallSites.end(),
607+
CSIC.CallSites.begin(),
608+
CSIC.CallSites.end());
609+
}
610+
}
611+
556612
Error DwarfTransformer::convert(uint32_t NumThreads, OutputAggregator &Out) {
557613
size_t NumBefore = Gsym.getNumFunctionInfos();
558614
auto getDie = [&](DWARFUnit &DwarfUnit) -> DWARFDie {

llvm/test/tools/llvm-gsymutil/ARM_AArch64/macho-gsym-merged-callsites-dsym.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@
44
# RUN: yaml2obj %t/merged_callsites.dSYM.yaml -o %t/merged_callsites.dSYM
55

66
# RUN: llvm-gsymutil --convert=%t/merged_callsites.dSYM --merged-functions --callsites-yaml-file=%t/callsites.yaml -o %t/call_sites_dSYM.gsym
7+
# RUN: llvm-gsymutil --convert=%t/merged_callsites.dSYM --merged-functions --dwarf-callsites -o %t/dwarf_call_sites_dSYM.gsym
78

89
# Dump the GSYM file and check the output for callsite information
910
# RUN: llvm-gsymutil %t/call_sites_dSYM.gsym | FileCheck --check-prefix=CHECK-MERGED-CALLSITES %s
11+
# RUN: llvm-gsymutil %t/dwarf_call_sites_dSYM.gsym | FileCheck --check-prefix=CHECK-MERGED-CALLSITES %s
1012

1113
# CHECK-MERGED-CALLSITES: FunctionInfo @ 0x[[#%x,FUNC4_1:]]: [0x[[#%x,FUNC4_1_START:]] - 0x[[#%x,FUNC4_1_END:]]) "function4_copy1"
1214
# CHECK-MERGED-CALLSITES: ++ Merged FunctionInfos[0]:

llvm/tools/llvm-gsymutil/Opts.td

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ defm convert :
1818
"Convert the specified file to the GSYM format.\nSupported files include ELF and mach-o files that will have their debug info (DWARF) and symbol table converted">;
1919
def merged_functions :
2020
FF<"merged-functions", "Encode merged function information for functions in debug info that have matching address ranges.\nWithout this option one function per unique address range will be emitted.">;
21+
def dwarf_callsites : FF<"dwarf-callsites", "Load call site info from DWARF, if available">;
2122
defm callsites_yaml_file :
2223
Eq<"callsites-yaml-file", "Load call site info from YAML file. Useful for testing.">, Flags<[HelpHidden]>;
2324
defm arch :

llvm/tools/llvm-gsymutil/llvm-gsymutil.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ static bool Quiet;
9797
static std::vector<uint64_t> LookupAddresses;
9898
static bool LookupAddressesFromStdin;
9999
static bool StoreMergedFunctionInfo = false;
100+
static bool LoadDwarfCallSites = false;
100101
static std::string CallSiteYamlPath;
101102

102103
static void parseArgs(int argc, char **argv) {
@@ -189,6 +190,8 @@ static void parseArgs(int argc, char **argv) {
189190
std::exit(1);
190191
}
191192
}
193+
194+
LoadDwarfCallSites = Args.hasArg(OPT_dwarf_callsites);
192195
}
193196

194197
/// @}
@@ -363,7 +366,7 @@ static llvm::Error handleObjectFile(ObjectFile &Obj, const std::string &OutFile,
363366

364367
// Make a DWARF transformer object and populate the ranges of the code
365368
// so we don't end up adding invalid functions to GSYM data.
366-
DwarfTransformer DT(*DICtx, Gsym);
369+
DwarfTransformer DT(*DICtx, Gsym, LoadDwarfCallSites);
367370
if (!TextRanges.empty())
368371
Gsym.SetValidTextRanges(TextRanges);
369372

0 commit comments

Comments
 (0)