xref: /llvm-project/llvm/tools/llvm-gsymutil/llvm-gsymutil.cpp (revision 4a1c33d34c31893aa781ac43285ae2100a540fd4)
190e40a0bSGreg Clayton //===-- gsymutil.cpp - GSYM dumping and creation utility for llvm ---------===//
290e40a0bSGreg Clayton //
3c874dd53SChristopher Di Bella // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4c874dd53SChristopher Di Bella // See https://llvm.org/LICENSE.txt for license information.
5c874dd53SChristopher Di Bella // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
690e40a0bSGreg Clayton //
790e40a0bSGreg Clayton //===----------------------------------------------------------------------===//
890e40a0bSGreg Clayton 
990e40a0bSGreg Clayton #include "llvm/ADT/STLExtras.h"
1090e40a0bSGreg Clayton #include "llvm/DebugInfo/DIContext.h"
1190e40a0bSGreg Clayton #include "llvm/DebugInfo/DWARF/DWARFContext.h"
125147e594Salx32 #include "llvm/DebugInfo/GSYM/CallSiteInfo.h"
1390e40a0bSGreg Clayton #include "llvm/Object/Archive.h"
1490e40a0bSGreg Clayton #include "llvm/Object/ELFObjectFile.h"
1590e40a0bSGreg Clayton #include "llvm/Object/MachOUniversal.h"
1690e40a0bSGreg Clayton #include "llvm/Object/ObjectFile.h"
17a44fffb8SAlex Brachet #include "llvm/Option/ArgList.h"
18a44fffb8SAlex Brachet #include "llvm/Option/Option.h"
1990e40a0bSGreg Clayton #include "llvm/Support/CommandLine.h"
2090e40a0bSGreg Clayton #include "llvm/Support/Debug.h"
2190e40a0bSGreg Clayton #include "llvm/Support/Format.h"
22da1880ccSKevin Frei #include "llvm/Support/JSON.h"
23e161fcdeSAlex Brachet #include "llvm/Support/LLVMDriver.h"
2490e40a0bSGreg Clayton #include "llvm/Support/ManagedStatic.h"
2590e40a0bSGreg Clayton #include "llvm/Support/MemoryBuffer.h"
2690e40a0bSGreg Clayton #include "llvm/Support/PrettyStackTrace.h"
2790e40a0bSGreg Clayton #include "llvm/Support/Regex.h"
2890e40a0bSGreg Clayton #include "llvm/Support/Signals.h"
2990e40a0bSGreg Clayton #include "llvm/Support/TargetSelect.h"
3090e40a0bSGreg Clayton #include "llvm/Support/raw_ostream.h"
3162c7f035SArchibald Elliott #include "llvm/TargetParser/Triple.h"
3290e40a0bSGreg Clayton #include <algorithm>
3390e40a0bSGreg Clayton #include <cstring>
3490e40a0bSGreg Clayton #include <inttypes.h>
350ddc75fdSSimon Giesecke #include <iostream>
36d8e077e2SGreg Clayton #include <optional>
3790e40a0bSGreg Clayton #include <string>
3890e40a0bSGreg Clayton #include <system_error>
3990e40a0bSGreg Clayton #include <vector>
4090e40a0bSGreg Clayton 
4190e40a0bSGreg Clayton #include "llvm/DebugInfo/GSYM/DwarfTransformer.h"
4290e40a0bSGreg Clayton #include "llvm/DebugInfo/GSYM/FunctionInfo.h"
4390e40a0bSGreg Clayton #include "llvm/DebugInfo/GSYM/GsymCreator.h"
4490e40a0bSGreg Clayton #include "llvm/DebugInfo/GSYM/GsymReader.h"
4590e40a0bSGreg Clayton #include "llvm/DebugInfo/GSYM/InlineInfo.h"
4690e40a0bSGreg Clayton #include "llvm/DebugInfo/GSYM/LookupResult.h"
4790e40a0bSGreg Clayton #include "llvm/DebugInfo/GSYM/ObjectFileTransformer.h"
483bdc4c70SKevin Frei #include "llvm/DebugInfo/GSYM/OutputAggregator.h"
49ba3d808fSKazu Hirata #include <optional>
5090e40a0bSGreg Clayton 
5190e40a0bSGreg Clayton using namespace llvm;
5290e40a0bSGreg Clayton using namespace gsym;
5390e40a0bSGreg Clayton using namespace object;
5490e40a0bSGreg Clayton 
5590e40a0bSGreg Clayton /// @}
5690e40a0bSGreg Clayton /// Command line options.
5790e40a0bSGreg Clayton /// @{
5890e40a0bSGreg Clayton 
59a44fffb8SAlex Brachet using namespace llvm::opt;
60a44fffb8SAlex Brachet enum ID {
61a44fffb8SAlex Brachet   OPT_INVALID = 0, // This is not an option ID.
623f092f37SJan Svoboda #define OPTION(...) LLVM_MAKE_OPT_ID(__VA_ARGS__),
63a44fffb8SAlex Brachet #include "Opts.inc"
64a44fffb8SAlex Brachet #undef OPTION
65a44fffb8SAlex Brachet };
6690e40a0bSGreg Clayton 
67dd647e3eSChandler Carruth #define OPTTABLE_STR_TABLE_CODE
68a44fffb8SAlex Brachet #include "Opts.inc"
69dd647e3eSChandler Carruth #undef OPTTABLE_STR_TABLE_CODE
70dd647e3eSChandler Carruth 
71dd647e3eSChandler Carruth #define OPTTABLE_PREFIXES_TABLE_CODE
72dd647e3eSChandler Carruth #include "Opts.inc"
73dd647e3eSChandler Carruth #undef OPTTABLE_PREFIXES_TABLE_CODE
7490e40a0bSGreg Clayton 
75a44fffb8SAlex Brachet const opt::OptTable::Info InfoTable[] = {
763f092f37SJan Svoboda #define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__),
77a44fffb8SAlex Brachet #include "Opts.inc"
78a44fffb8SAlex Brachet #undef OPTION
79a44fffb8SAlex Brachet };
8090e40a0bSGreg Clayton 
81a44fffb8SAlex Brachet class GSYMUtilOptTable : public llvm::opt::GenericOptTable {
82a44fffb8SAlex Brachet public:
83dd647e3eSChandler Carruth   GSYMUtilOptTable()
84dd647e3eSChandler Carruth       : GenericOptTable(OptionStrTable, OptionPrefixesTable, InfoTable) {
85a44fffb8SAlex Brachet     setGroupedShortOptions(true);
86a44fffb8SAlex Brachet   }
87a44fffb8SAlex Brachet };
8890e40a0bSGreg Clayton 
89a44fffb8SAlex Brachet static bool Verbose;
90a44fffb8SAlex Brachet static std::vector<std::string> InputFilenames;
91a44fffb8SAlex Brachet static std::string ConvertFilename;
92a44fffb8SAlex Brachet static std::vector<std::string> ArchFilters;
93a44fffb8SAlex Brachet static std::string OutputFilename;
94da1880ccSKevin Frei static std::string JsonSummaryFile;
95a44fffb8SAlex Brachet static bool Verify;
96a44fffb8SAlex Brachet static unsigned NumThreads;
97a44fffb8SAlex Brachet static uint64_t SegmentSize;
98a44fffb8SAlex Brachet static bool Quiet;
99a44fffb8SAlex Brachet static std::vector<uint64_t> LookupAddresses;
100a44fffb8SAlex Brachet static bool LookupAddressesFromStdin;
1016f28b4b5Salx32 static bool UseMergedFunctions = false;
102558de0e1Salx32 static bool LoadDwarfCallSites = false;
1035147e594Salx32 static std::string CallSiteYamlPath;
104*4a1c33d3Salx32 static std::vector<std::string> MergedFunctionsFilters;
10590e40a0bSGreg Clayton 
106a44fffb8SAlex Brachet static void parseArgs(int argc, char **argv) {
107a44fffb8SAlex Brachet   GSYMUtilOptTable Tbl;
108a44fffb8SAlex Brachet   llvm::StringRef ToolName = argv[0];
109a44fffb8SAlex Brachet   llvm::BumpPtrAllocator A;
110a44fffb8SAlex Brachet   llvm::StringSaver Saver{A};
111a44fffb8SAlex Brachet   llvm::opt::InputArgList Args =
112a44fffb8SAlex Brachet       Tbl.parseArgs(argc, argv, OPT_UNKNOWN, Saver, [&](StringRef Msg) {
113a44fffb8SAlex Brachet         llvm::errs() << Msg << '\n';
114a44fffb8SAlex Brachet         std::exit(1);
115a44fffb8SAlex Brachet       });
116a44fffb8SAlex Brachet   if (Args.hasArg(OPT_help)) {
117a44fffb8SAlex Brachet     const char *Overview =
118a44fffb8SAlex Brachet         "A tool for dumping, searching and creating GSYM files.\n\n"
119a44fffb8SAlex Brachet         "Specify one or more GSYM paths as arguments to dump all of the "
120a44fffb8SAlex Brachet         "information in each GSYM file.\n"
121a44fffb8SAlex Brachet         "Specify a single GSYM file along with one or more --lookup options to "
122a44fffb8SAlex Brachet         "lookup addresses within that GSYM file.\n"
123a44fffb8SAlex Brachet         "Use the --convert option to specify a file with option --out-file "
124a44fffb8SAlex Brachet         "option to convert to GSYM format.\n";
12590e40a0bSGreg Clayton 
126a44fffb8SAlex Brachet     Tbl.printHelp(llvm::outs(), "llvm-gsymutil [options] <input GSYM files>",
127a44fffb8SAlex Brachet                   Overview);
128a44fffb8SAlex Brachet     std::exit(0);
129a44fffb8SAlex Brachet   }
130a44fffb8SAlex Brachet   if (Args.hasArg(OPT_version)) {
131a44fffb8SAlex Brachet     llvm::outs() << ToolName << '\n';
132a44fffb8SAlex Brachet     cl::PrintVersionMessage();
133a44fffb8SAlex Brachet     std::exit(0);
134a44fffb8SAlex Brachet   }
13590e40a0bSGreg Clayton 
136a44fffb8SAlex Brachet   Verbose = Args.hasArg(OPT_verbose);
13790e40a0bSGreg Clayton 
138a44fffb8SAlex Brachet   for (const llvm::opt::Arg *A : Args.filtered(OPT_INPUT))
139a44fffb8SAlex Brachet     InputFilenames.emplace_back(A->getValue());
14090e40a0bSGreg Clayton 
141a44fffb8SAlex Brachet   if (const llvm::opt::Arg *A = Args.getLastArg(OPT_convert_EQ))
142a44fffb8SAlex Brachet     ConvertFilename = A->getValue();
14390e40a0bSGreg Clayton 
144a44fffb8SAlex Brachet   for (const llvm::opt::Arg *A : Args.filtered(OPT_arch_EQ))
145a44fffb8SAlex Brachet     ArchFilters.emplace_back(A->getValue());
146d8e077e2SGreg Clayton 
147a44fffb8SAlex Brachet   if (const llvm::opt::Arg *A = Args.getLastArg(OPT_out_file_EQ))
148a44fffb8SAlex Brachet     OutputFilename = A->getValue();
1495f2d4b23SSimon Giesecke 
150da1880ccSKevin Frei   if (const llvm::opt::Arg *A = Args.getLastArg(OPT_json_summary_file_EQ))
151da1880ccSKevin Frei     JsonSummaryFile = A->getValue();
152da1880ccSKevin Frei 
153a44fffb8SAlex Brachet   Verify = Args.hasArg(OPT_verify);
15490e40a0bSGreg Clayton 
155a44fffb8SAlex Brachet   if (const llvm::opt::Arg *A = Args.getLastArg(OPT_num_threads_EQ)) {
156a44fffb8SAlex Brachet     StringRef S{A->getValue()};
157a44fffb8SAlex Brachet     if (!llvm::to_integer(S, NumThreads, 0)) {
158a44fffb8SAlex Brachet       llvm::errs() << ToolName << ": for the --num-threads option: '" << S
159a44fffb8SAlex Brachet                    << "' value invalid for uint argument!\n";
160a44fffb8SAlex Brachet       std::exit(1);
161a44fffb8SAlex Brachet     }
162a44fffb8SAlex Brachet   }
16390e40a0bSGreg Clayton 
164a44fffb8SAlex Brachet   if (const llvm::opt::Arg *A = Args.getLastArg(OPT_segment_size_EQ)) {
165a44fffb8SAlex Brachet     StringRef S{A->getValue()};
166a44fffb8SAlex Brachet     if (!llvm::to_integer(S, SegmentSize, 0)) {
167a44fffb8SAlex Brachet       llvm::errs() << ToolName << ": for the --segment-size option: '" << S
168a44fffb8SAlex Brachet                    << "' value invalid for uint argument!\n";
169a44fffb8SAlex Brachet       std::exit(1);
170a44fffb8SAlex Brachet     }
171a44fffb8SAlex Brachet   }
172a44fffb8SAlex Brachet 
173a44fffb8SAlex Brachet   Quiet = Args.hasArg(OPT_quiet);
174a44fffb8SAlex Brachet 
175a44fffb8SAlex Brachet   for (const llvm::opt::Arg *A : Args.filtered(OPT_address_EQ)) {
176a44fffb8SAlex Brachet     StringRef S{A->getValue()};
177a44fffb8SAlex Brachet     if (!llvm::to_integer(S, LookupAddresses.emplace_back(), 0)) {
178df06594aSWanyi Ye       llvm::errs() << ToolName << ": for the --address option: '" << S
179a44fffb8SAlex Brachet                    << "' value invalid for uint argument!\n";
180a44fffb8SAlex Brachet       std::exit(1);
181a44fffb8SAlex Brachet     }
182a44fffb8SAlex Brachet   }
183a44fffb8SAlex Brachet 
184a44fffb8SAlex Brachet   LookupAddressesFromStdin = Args.hasArg(OPT_addresses_from_stdin);
1856f28b4b5Salx32   UseMergedFunctions = Args.hasArg(OPT_merged_functions);
1865147e594Salx32 
1875147e594Salx32   if (Args.hasArg(OPT_callsites_yaml_file_EQ)) {
1885147e594Salx32     CallSiteYamlPath = Args.getLastArgValue(OPT_callsites_yaml_file_EQ);
1895147e594Salx32     if (CallSiteYamlPath.empty()) {
1905147e594Salx32       llvm::errs()
1915147e594Salx32           << ToolName
1925147e594Salx32           << ": --callsites-yaml-file option requires a non-empty argument.\n";
1935147e594Salx32       std::exit(1);
1945147e594Salx32     }
1955147e594Salx32   }
196558de0e1Salx32 
197558de0e1Salx32   LoadDwarfCallSites = Args.hasArg(OPT_dwarf_callsites);
198*4a1c33d3Salx32 
199*4a1c33d3Salx32   for (const llvm::opt::Arg *A :
200*4a1c33d3Salx32        Args.filtered(OPT_merged_functions_filter_EQ)) {
201*4a1c33d3Salx32     MergedFunctionsFilters.push_back(A->getValue());
202*4a1c33d3Salx32     // Validate the filter is only used with correct flags
203*4a1c33d3Salx32     if (LookupAddresses.empty() && !LookupAddressesFromStdin) {
204*4a1c33d3Salx32       llvm::errs() << ToolName
205*4a1c33d3Salx32                    << ": --merged-functions-filter can only be used with "
206*4a1c33d3Salx32                       "--address/--addresses-from-stdin\n";
207*4a1c33d3Salx32       std::exit(1);
208*4a1c33d3Salx32     }
209*4a1c33d3Salx32     if (!UseMergedFunctions) {
210*4a1c33d3Salx32       llvm::errs()
211*4a1c33d3Salx32           << ToolName
212*4a1c33d3Salx32           << ": --merged-functions-filter requires --merged-functions\n";
213*4a1c33d3Salx32       std::exit(1);
214*4a1c33d3Salx32     }
215*4a1c33d3Salx32   }
216a44fffb8SAlex Brachet }
217a44fffb8SAlex Brachet 
21890e40a0bSGreg Clayton /// @}
21990e40a0bSGreg Clayton //===----------------------------------------------------------------------===//
22090e40a0bSGreg Clayton 
221b68061a3SEllis Hoag static void error(Error Err) {
222b68061a3SEllis Hoag   if (!Err)
223b68061a3SEllis Hoag     return;
224b68061a3SEllis Hoag   WithColor::error() << toString(std::move(Err)) << "\n";
225b68061a3SEllis Hoag   exit(1);
226b68061a3SEllis Hoag }
227b68061a3SEllis Hoag 
22890e40a0bSGreg Clayton static void error(StringRef Prefix, llvm::Error Err) {
22990e40a0bSGreg Clayton   if (!Err)
23090e40a0bSGreg Clayton     return;
23190e40a0bSGreg Clayton   errs() << Prefix << ": " << Err << "\n";
23290e40a0bSGreg Clayton   consumeError(std::move(Err));
23390e40a0bSGreg Clayton   exit(1);
23490e40a0bSGreg Clayton }
23590e40a0bSGreg Clayton 
23690e40a0bSGreg Clayton static void error(StringRef Prefix, std::error_code EC) {
23790e40a0bSGreg Clayton   if (!EC)
23890e40a0bSGreg Clayton     return;
23990e40a0bSGreg Clayton   errs() << Prefix << ": " << EC.message() << "\n";
24090e40a0bSGreg Clayton   exit(1);
24190e40a0bSGreg Clayton }
24290e40a0bSGreg Clayton 
24390e40a0bSGreg Clayton static uint32_t getCPUType(MachOObjectFile &MachO) {
24490e40a0bSGreg Clayton   if (MachO.is64Bit())
24590e40a0bSGreg Clayton     return MachO.getHeader64().cputype;
24690e40a0bSGreg Clayton   else
24790e40a0bSGreg Clayton     return MachO.getHeader().cputype;
24890e40a0bSGreg Clayton }
24990e40a0bSGreg Clayton 
25090e40a0bSGreg Clayton /// Return true if the object file has not been filtered by an --arch option.
25190e40a0bSGreg Clayton static bool filterArch(MachOObjectFile &Obj) {
25290e40a0bSGreg Clayton   if (ArchFilters.empty())
25390e40a0bSGreg Clayton     return true;
25490e40a0bSGreg Clayton 
2554050b01bSGreg Clayton   Triple ObjTriple(Obj.getArchTriple());
2564050b01bSGreg Clayton   StringRef ObjArch = ObjTriple.getArchName();
25790e40a0bSGreg Clayton 
258d87f9e28SFangrui Song   for (StringRef Arch : ArchFilters) {
25990e40a0bSGreg Clayton     // Match name.
26090e40a0bSGreg Clayton     if (Arch == ObjArch)
26190e40a0bSGreg Clayton       return true;
26290e40a0bSGreg Clayton 
26390e40a0bSGreg Clayton     // Match architecture number.
26490e40a0bSGreg Clayton     unsigned Value;
265d87f9e28SFangrui Song     if (!Arch.getAsInteger(0, Value))
26690e40a0bSGreg Clayton       if (Value == getCPUType(Obj))
26790e40a0bSGreg Clayton         return true;
26890e40a0bSGreg Clayton   }
26990e40a0bSGreg Clayton   return false;
27090e40a0bSGreg Clayton }
27190e40a0bSGreg Clayton 
27290e40a0bSGreg Clayton /// Determine the virtual address that is considered the base address of an ELF
27390e40a0bSGreg Clayton /// object file.
27490e40a0bSGreg Clayton ///
275111fcb0dSFangrui Song /// The base address of an ELF file is the "p_vaddr" of the first program
27690e40a0bSGreg Clayton /// header whose "p_type" is PT_LOAD.
27790e40a0bSGreg Clayton ///
27890e40a0bSGreg Clayton /// \param ELFFile An ELF object file we will search.
27990e40a0bSGreg Clayton ///
28090e40a0bSGreg Clayton /// \returns A valid image base address if we are able to extract one.
28190e40a0bSGreg Clayton template <class ELFT>
282da2f5d0aSFangrui Song static std::optional<uint64_t>
283ffbce65fSGeorgii Rymar getImageBaseAddress(const object::ELFFile<ELFT> &ELFFile) {
284ffbce65fSGeorgii Rymar   auto PhdrRangeOrErr = ELFFile.program_headers();
28590e40a0bSGreg Clayton   if (!PhdrRangeOrErr) {
28690e40a0bSGreg Clayton     consumeError(PhdrRangeOrErr.takeError());
287b4482f7cSKazu Hirata     return std::nullopt;
28890e40a0bSGreg Clayton   }
28990e40a0bSGreg Clayton   for (const typename ELFT::Phdr &Phdr : *PhdrRangeOrErr)
29090e40a0bSGreg Clayton     if (Phdr.p_type == ELF::PT_LOAD)
29190e40a0bSGreg Clayton       return (uint64_t)Phdr.p_vaddr;
292b4482f7cSKazu Hirata   return std::nullopt;
29390e40a0bSGreg Clayton }
29490e40a0bSGreg Clayton 
29590e40a0bSGreg Clayton /// Determine the virtual address that is considered the base address of mach-o
29690e40a0bSGreg Clayton /// object file.
29790e40a0bSGreg Clayton ///
29890e40a0bSGreg Clayton /// The base address of a mach-o file is the vmaddr of the  "__TEXT" segment.
29990e40a0bSGreg Clayton ///
30090e40a0bSGreg Clayton /// \param MachO A mach-o object file we will search.
30190e40a0bSGreg Clayton ///
30290e40a0bSGreg Clayton /// \returns A valid image base address if we are able to extract one.
303da2f5d0aSFangrui Song static std::optional<uint64_t>
30490e40a0bSGreg Clayton getImageBaseAddress(const object::MachOObjectFile *MachO) {
30590e40a0bSGreg Clayton   for (const auto &Command : MachO->load_commands()) {
30690e40a0bSGreg Clayton     if (Command.C.cmd == MachO::LC_SEGMENT) {
30790e40a0bSGreg Clayton       MachO::segment_command SLC = MachO->getSegmentLoadCommand(Command);
30890e40a0bSGreg Clayton       StringRef SegName = SLC.segname;
30990e40a0bSGreg Clayton       if (SegName == "__TEXT")
31090e40a0bSGreg Clayton         return SLC.vmaddr;
31190e40a0bSGreg Clayton     } else if (Command.C.cmd == MachO::LC_SEGMENT_64) {
31290e40a0bSGreg Clayton       MachO::segment_command_64 SLC = MachO->getSegment64LoadCommand(Command);
31390e40a0bSGreg Clayton       StringRef SegName = SLC.segname;
31490e40a0bSGreg Clayton       if (SegName == "__TEXT")
31590e40a0bSGreg Clayton         return SLC.vmaddr;
31690e40a0bSGreg Clayton     }
31790e40a0bSGreg Clayton   }
318b4482f7cSKazu Hirata   return std::nullopt;
31990e40a0bSGreg Clayton }
32090e40a0bSGreg Clayton 
32190e40a0bSGreg Clayton /// Determine the virtual address that is considered the base address of an
32290e40a0bSGreg Clayton /// object file.
32390e40a0bSGreg Clayton ///
32490e40a0bSGreg Clayton /// Since GSYM files are used for symbolication, many clients will need to
32590e40a0bSGreg Clayton /// easily adjust addresses they find in stack traces so the lookups happen
32690e40a0bSGreg Clayton /// on unslid addresses from the original object file. If the base address of
32790e40a0bSGreg Clayton /// a GSYM file is set to the base address of the image, then this address
32890e40a0bSGreg Clayton /// adjusting is much easier.
32990e40a0bSGreg Clayton ///
33090e40a0bSGreg Clayton /// \param Obj An object file we will search.
33190e40a0bSGreg Clayton ///
33290e40a0bSGreg Clayton /// \returns A valid image base address if we are able to extract one.
333da2f5d0aSFangrui Song static std::optional<uint64_t> getImageBaseAddress(object::ObjectFile &Obj) {
33490e40a0bSGreg Clayton   if (const auto *MachO = dyn_cast<object::MachOObjectFile>(&Obj))
33590e40a0bSGreg Clayton     return getImageBaseAddress(MachO);
33690e40a0bSGreg Clayton   else if (const auto *ELFObj = dyn_cast<object::ELF32LEObjectFile>(&Obj))
33790e40a0bSGreg Clayton     return getImageBaseAddress(ELFObj->getELFFile());
33890e40a0bSGreg Clayton   else if (const auto *ELFObj = dyn_cast<object::ELF32BEObjectFile>(&Obj))
33990e40a0bSGreg Clayton     return getImageBaseAddress(ELFObj->getELFFile());
34090e40a0bSGreg Clayton   else if (const auto *ELFObj = dyn_cast<object::ELF64LEObjectFile>(&Obj))
34190e40a0bSGreg Clayton     return getImageBaseAddress(ELFObj->getELFFile());
34290e40a0bSGreg Clayton   else if (const auto *ELFObj = dyn_cast<object::ELF64BEObjectFile>(&Obj))
34390e40a0bSGreg Clayton     return getImageBaseAddress(ELFObj->getELFFile());
344b4482f7cSKazu Hirata   return std::nullopt;
34590e40a0bSGreg Clayton }
34690e40a0bSGreg Clayton 
3473bdc4c70SKevin Frei static llvm::Error handleObjectFile(ObjectFile &Obj, const std::string &OutFile,
3483bdc4c70SKevin Frei                                     OutputAggregator &Out) {
34990e40a0bSGreg Clayton   auto ThreadCount =
35090e40a0bSGreg Clayton       NumThreads > 0 ? NumThreads : std::thread::hardware_concurrency();
35190e40a0bSGreg Clayton 
3525f2d4b23SSimon Giesecke   GsymCreator Gsym(Quiet);
35390e40a0bSGreg Clayton 
35490e40a0bSGreg Clayton   // See if we can figure out the base address for a given object file, and if
35590e40a0bSGreg Clayton   // we can, then set the base address to use to this value. This will ease
35690e40a0bSGreg Clayton   // symbolication since clients can slide the GSYM lookup addresses by using
35790e40a0bSGreg Clayton   // the load bias of the shared library.
35890e40a0bSGreg Clayton   if (auto ImageBaseAddr = getImageBaseAddress(Obj))
35990e40a0bSGreg Clayton     Gsym.setBaseAddress(*ImageBaseAddr);
36090e40a0bSGreg Clayton 
36190e40a0bSGreg Clayton   // We need to know where the valid sections are that contain instructions.
36290e40a0bSGreg Clayton   // See header documentation for DWARFTransformer::SetValidTextRanges() for
36390e40a0bSGreg Clayton   // defails.
36490e40a0bSGreg Clayton   AddressRanges TextRanges;
36590e40a0bSGreg Clayton   for (const object::SectionRef &Sect : Obj.sections()) {
36690e40a0bSGreg Clayton     if (!Sect.isText())
36790e40a0bSGreg Clayton       continue;
36890e40a0bSGreg Clayton     const uint64_t Size = Sect.getSize();
36990e40a0bSGreg Clayton     if (Size == 0)
37090e40a0bSGreg Clayton       continue;
37190e40a0bSGreg Clayton     const uint64_t StartAddr = Sect.getAddress();
37290e40a0bSGreg Clayton     TextRanges.insert(AddressRange(StartAddr, StartAddr + Size));
37390e40a0bSGreg Clayton   }
37490e40a0bSGreg Clayton 
37590e40a0bSGreg Clayton   // Make sure there is DWARF to convert first.
376576f3f0cSGreg Clayton   std::unique_ptr<DWARFContext> DICtx = DWARFContext::create(
377576f3f0cSGreg Clayton       Obj,
378576f3f0cSGreg Clayton       /*RelocAction=*/DWARFContext::ProcessDebugRelocations::Process,
379576f3f0cSGreg Clayton       nullptr,
380576f3f0cSGreg Clayton       /*DWPName=*/"",
381576f3f0cSGreg Clayton       /*RecoverableErrorHandler=*/WithColor::defaultErrorHandler,
382576f3f0cSGreg Clayton       /*WarningHandler=*/WithColor::defaultWarningHandler,
383576f3f0cSGreg Clayton       /*ThreadSafe*/true);
38490e40a0bSGreg Clayton   if (!DICtx)
38590e40a0bSGreg Clayton     return createStringError(std::errc::invalid_argument,
38690e40a0bSGreg Clayton                              "unable to create DWARF context");
38790e40a0bSGreg Clayton 
38890e40a0bSGreg Clayton   // Make a DWARF transformer object and populate the ranges of the code
38990e40a0bSGreg Clayton   // so we don't end up adding invalid functions to GSYM data.
390558de0e1Salx32   DwarfTransformer DT(*DICtx, Gsym, LoadDwarfCallSites);
39190e40a0bSGreg Clayton   if (!TextRanges.empty())
39290e40a0bSGreg Clayton     Gsym.SetValidTextRanges(TextRanges);
39390e40a0bSGreg Clayton 
39490e40a0bSGreg Clayton   // Convert all DWARF to GSYM.
3953bdc4c70SKevin Frei   if (auto Err = DT.convert(ThreadCount, Out))
39690e40a0bSGreg Clayton     return Err;
39790e40a0bSGreg Clayton 
398cb5dc1faSalx32   // If enabled, merge functions with identical address ranges as merged
399cb5dc1faSalx32   // functions in the first FunctionInfo with that address range. Do this right
400cb5dc1faSalx32   // after loading the DWARF data so we don't have to deal with functions from
401cb5dc1faSalx32   // the symbol table.
4026f28b4b5Salx32   if (UseMergedFunctions)
403cb5dc1faSalx32     Gsym.prepareMergedFunctions(Out);
404cb5dc1faSalx32 
40590e40a0bSGreg Clayton   // Get the UUID and convert symbol table to GSYM.
4063bdc4c70SKevin Frei   if (auto Err = ObjectFileTransformer::convert(Obj, Out, Gsym))
40790e40a0bSGreg Clayton     return Err;
40890e40a0bSGreg Clayton 
4095147e594Salx32   // If any call site YAML files were specified, load them now.
4105147e594Salx32   if (!CallSiteYamlPath.empty())
4115147e594Salx32     if (auto Err = Gsym.loadCallSitesFromYAML(CallSiteYamlPath))
4125147e594Salx32       return Err;
4135147e594Salx32 
41490e40a0bSGreg Clayton   // Finalize the GSYM to make it ready to save to disk. This will remove
41590e40a0bSGreg Clayton   // duplicate FunctionInfo entries where we might have found an entry from
41690e40a0bSGreg Clayton   // debug info and also a symbol table entry from the object file.
4173bdc4c70SKevin Frei   if (auto Err = Gsym.finalize(Out))
41890e40a0bSGreg Clayton     return Err;
41990e40a0bSGreg Clayton 
42090e40a0bSGreg Clayton   // Save the GSYM file to disk.
4214a0ccfa8SKazu Hirata   llvm::endianness Endian = Obj.makeTriple().isLittleEndian()
4224a0ccfa8SKazu Hirata                                 ? llvm::endianness::little
4234a0ccfa8SKazu Hirata                                 : llvm::endianness::big;
424d8e077e2SGreg Clayton 
425d8e077e2SGreg Clayton   std::optional<uint64_t> OptSegmentSize;
426d8e077e2SGreg Clayton   if (SegmentSize > 0)
427d8e077e2SGreg Clayton     OptSegmentSize = SegmentSize;
428d8e077e2SGreg Clayton   if (auto Err = Gsym.save(OutFile, Endian, OptSegmentSize))
42990e40a0bSGreg Clayton     return Err;
43090e40a0bSGreg Clayton 
43190e40a0bSGreg Clayton   // Verify the DWARF if requested. This will ensure all the info in the DWARF
43290e40a0bSGreg Clayton   // can be looked up in the GSYM and that all lookups get matching data.
43390e40a0bSGreg Clayton   if (Verify) {
4343bdc4c70SKevin Frei     if (auto Err = DT.verify(OutFile, Out))
43590e40a0bSGreg Clayton       return Err;
43690e40a0bSGreg Clayton   }
43790e40a0bSGreg Clayton 
43890e40a0bSGreg Clayton   return Error::success();
43990e40a0bSGreg Clayton }
44090e40a0bSGreg Clayton 
44190e40a0bSGreg Clayton static llvm::Error handleBuffer(StringRef Filename, MemoryBufferRef Buffer,
4423bdc4c70SKevin Frei                                 const std::string &OutFile,
4433bdc4c70SKevin Frei                                 OutputAggregator &Out) {
44490e40a0bSGreg Clayton   Expected<std::unique_ptr<Binary>> BinOrErr = object::createBinary(Buffer);
44590e40a0bSGreg Clayton   error(Filename, errorToErrorCode(BinOrErr.takeError()));
44690e40a0bSGreg Clayton 
44790e40a0bSGreg Clayton   if (auto *Obj = dyn_cast<ObjectFile>(BinOrErr->get())) {
4484050b01bSGreg Clayton     Triple ObjTriple(Obj->makeTriple());
4494050b01bSGreg Clayton     auto ArchName = ObjTriple.getArchName();
45090e40a0bSGreg Clayton     outs() << "Output file (" << ArchName << "): " << OutFile << "\n";
4513bdc4c70SKevin Frei     if (auto Err = handleObjectFile(*Obj, OutFile, Out))
45290e40a0bSGreg Clayton       return Err;
45390e40a0bSGreg Clayton   } else if (auto *Fat = dyn_cast<MachOUniversalBinary>(BinOrErr->get())) {
45490e40a0bSGreg Clayton     // Iterate over all contained architectures and filter out any that were
45590e40a0bSGreg Clayton     // not specified with the "--arch <arch>" option. If the --arch option was
45690e40a0bSGreg Clayton     // not specified on the command line, we will process all architectures.
45790e40a0bSGreg Clayton     std::vector<std::unique_ptr<MachOObjectFile>> FilterObjs;
45890e40a0bSGreg Clayton     for (auto &ObjForArch : Fat->objects()) {
45990e40a0bSGreg Clayton       if (auto MachOOrErr = ObjForArch.getAsObjectFile()) {
46090e40a0bSGreg Clayton         auto &Obj = **MachOOrErr;
46190e40a0bSGreg Clayton         if (filterArch(Obj))
46290e40a0bSGreg Clayton           FilterObjs.emplace_back(MachOOrErr->release());
46390e40a0bSGreg Clayton       } else {
46490e40a0bSGreg Clayton         error(Filename, MachOOrErr.takeError());
46590e40a0bSGreg Clayton       }
46690e40a0bSGreg Clayton     }
46790e40a0bSGreg Clayton     if (FilterObjs.empty())
46890e40a0bSGreg Clayton       error(Filename, createStringError(std::errc::invalid_argument,
46990e40a0bSGreg Clayton                                         "no matching architectures found"));
47090e40a0bSGreg Clayton 
47190e40a0bSGreg Clayton     // Now handle each architecture we need to convert.
47290e40a0bSGreg Clayton     for (auto &Obj : FilterObjs) {
4734050b01bSGreg Clayton       Triple ObjTriple(Obj->getArchTriple());
4744050b01bSGreg Clayton       auto ArchName = ObjTriple.getArchName();
47590e40a0bSGreg Clayton       std::string ArchOutFile(OutFile);
47690e40a0bSGreg Clayton       // If we are only handling a single architecture, then we will use the
47790e40a0bSGreg Clayton       // normal output file. If we are handling multiple architectures append
47890e40a0bSGreg Clayton       // the architecture name to the end of the out file path so that we
47990e40a0bSGreg Clayton       // don't overwrite the previous architecture's gsym file.
48090e40a0bSGreg Clayton       if (FilterObjs.size() > 1) {
48190e40a0bSGreg Clayton         ArchOutFile.append(1, '.');
48290e40a0bSGreg Clayton         ArchOutFile.append(ArchName.str());
48390e40a0bSGreg Clayton       }
48490e40a0bSGreg Clayton       outs() << "Output file (" << ArchName << "): " << ArchOutFile << "\n";
4853bdc4c70SKevin Frei       if (auto Err = handleObjectFile(*Obj, ArchOutFile, Out))
48690e40a0bSGreg Clayton         return Err;
48790e40a0bSGreg Clayton     }
48890e40a0bSGreg Clayton   }
48990e40a0bSGreg Clayton   return Error::success();
49090e40a0bSGreg Clayton }
49190e40a0bSGreg Clayton 
49290e40a0bSGreg Clayton static llvm::Error handleFileConversionToGSYM(StringRef Filename,
4933bdc4c70SKevin Frei                                               const std::string &OutFile,
4943bdc4c70SKevin Frei                                               OutputAggregator &Out) {
49590e40a0bSGreg Clayton   ErrorOr<std::unique_ptr<MemoryBuffer>> BuffOrErr =
49690e40a0bSGreg Clayton       MemoryBuffer::getFileOrSTDIN(Filename);
49790e40a0bSGreg Clayton   error(Filename, BuffOrErr.getError());
49890e40a0bSGreg Clayton   std::unique_ptr<MemoryBuffer> Buffer = std::move(BuffOrErr.get());
4993bdc4c70SKevin Frei   return handleBuffer(Filename, *Buffer, OutFile, Out);
50090e40a0bSGreg Clayton }
50190e40a0bSGreg Clayton 
5023bdc4c70SKevin Frei static llvm::Error convertFileToGSYM(OutputAggregator &Out) {
50390e40a0bSGreg Clayton   // Expand any .dSYM bundles to the individual object files contained therein.
50490e40a0bSGreg Clayton   std::vector<std::string> Objects;
50590e40a0bSGreg Clayton   std::string OutFile = OutputFilename;
50690e40a0bSGreg Clayton   if (OutFile.empty()) {
50790e40a0bSGreg Clayton     OutFile = ConvertFilename;
50890e40a0bSGreg Clayton     OutFile += ".gsym";
50990e40a0bSGreg Clayton   }
51090e40a0bSGreg Clayton 
5113bdc4c70SKevin Frei   Out << "Input file: " << ConvertFilename << "\n";
51290e40a0bSGreg Clayton 
513b68061a3SEllis Hoag   if (auto DsymObjectsOrErr =
514b68061a3SEllis Hoag           MachOObjectFile::findDsymObjectMembers(ConvertFilename)) {
515b68061a3SEllis Hoag     if (DsymObjectsOrErr->empty())
516b68061a3SEllis Hoag       Objects.push_back(ConvertFilename);
517b68061a3SEllis Hoag     else
518b68061a3SEllis Hoag       llvm::append_range(Objects, *DsymObjectsOrErr);
519b68061a3SEllis Hoag   } else {
520b68061a3SEllis Hoag     error(DsymObjectsOrErr.takeError());
521b68061a3SEllis Hoag   }
52290e40a0bSGreg Clayton 
523d87f9e28SFangrui Song   for (StringRef Object : Objects)
5243bdc4c70SKevin Frei     if (Error Err = handleFileConversionToGSYM(Object, OutFile, Out))
52590e40a0bSGreg Clayton       return Err;
52690e40a0bSGreg Clayton   return Error::success();
52790e40a0bSGreg Clayton }
52890e40a0bSGreg Clayton 
5290ddc75fdSSimon Giesecke static void doLookup(GsymReader &Gsym, uint64_t Addr, raw_ostream &OS) {
5306f28b4b5Salx32   if (UseMergedFunctions) {
5316f28b4b5Salx32     if (auto Results = Gsym.lookupAll(Addr)) {
532*4a1c33d3Salx32       // If we have filters, count matching results first
533*4a1c33d3Salx32       size_t NumMatching = Results->size();
534*4a1c33d3Salx32       if (!MergedFunctionsFilters.empty()) {
535*4a1c33d3Salx32         NumMatching = 0;
536*4a1c33d3Salx32         for (const auto &Result : *Results) {
537*4a1c33d3Salx32           bool Matches = false;
538*4a1c33d3Salx32           for (const auto &Filter : MergedFunctionsFilters) {
539*4a1c33d3Salx32             Regex Pattern(Filter);
540*4a1c33d3Salx32             if (Pattern.match(Result.FuncName)) {
541*4a1c33d3Salx32               Matches = true;
542*4a1c33d3Salx32               break;
543*4a1c33d3Salx32             }
544*4a1c33d3Salx32           }
545*4a1c33d3Salx32           if (Matches)
546*4a1c33d3Salx32             NumMatching++;
547*4a1c33d3Salx32         }
548*4a1c33d3Salx32       }
549*4a1c33d3Salx32 
550*4a1c33d3Salx32       OS << "Found " << NumMatching << " function"
551*4a1c33d3Salx32          << (NumMatching != 1 ? "s" : "") << " at address " << HEX64(Addr)
552*4a1c33d3Salx32          << ":\n";
553*4a1c33d3Salx32 
5546f28b4b5Salx32       for (size_t i = 0; i < Results->size(); ++i) {
555*4a1c33d3Salx32         // Skip if doesn't match any filter
556*4a1c33d3Salx32         if (!MergedFunctionsFilters.empty()) {
557*4a1c33d3Salx32           bool Matches = false;
558*4a1c33d3Salx32           for (const auto &Filter : MergedFunctionsFilters) {
559*4a1c33d3Salx32             Regex Pattern(Filter);
560*4a1c33d3Salx32             if (Pattern.match(Results->at(i).FuncName)) {
561*4a1c33d3Salx32               Matches = true;
562*4a1c33d3Salx32               break;
563*4a1c33d3Salx32             }
564*4a1c33d3Salx32           }
565*4a1c33d3Salx32           if (!Matches)
566*4a1c33d3Salx32             continue;
567*4a1c33d3Salx32         }
568*4a1c33d3Salx32 
5696f28b4b5Salx32         OS << "   " << Results->at(i);
5706f28b4b5Salx32 
5716f28b4b5Salx32         if (i != Results->size() - 1)
5726f28b4b5Salx32           OS << "\n";
5736f28b4b5Salx32       }
5746f28b4b5Salx32     }
5756f28b4b5Salx32   } else { /* UseMergedFunctions == false */
5760ddc75fdSSimon Giesecke     if (auto Result = Gsym.lookup(Addr)) {
5773f1a391bSalx32       // If verbose is enabled dump the full function info for the address.
5780ddc75fdSSimon Giesecke       if (Verbose) {
5790ddc75fdSSimon Giesecke         if (auto FI = Gsym.getFunctionInfo(Addr)) {
5800ddc75fdSSimon Giesecke           OS << "FunctionInfo for " << HEX64(Addr) << ":\n";
5810ddc75fdSSimon Giesecke           Gsym.dump(OS, *FI);
5820ddc75fdSSimon Giesecke           OS << "\nLookupResult for " << HEX64(Addr) << ":\n";
5830ddc75fdSSimon Giesecke         }
5843f1a391bSalx32       }
585*4a1c33d3Salx32       // Don't print call site info if --merged-functions is not specified.
586*4a1c33d3Salx32       Result->CallSiteFuncRegex.clear();
5873f1a391bSalx32       OS << Result.get();
5883f1a391bSalx32     } else {
5893f1a391bSalx32       if (Verbose)
5903f1a391bSalx32         OS << "\nLookupResult for " << HEX64(Addr) << ":\n";
5913f1a391bSalx32       OS << HEX64(Addr) << ": ";
5923f1a391bSalx32       logAllUnhandledErrors(Result.takeError(), OS, "error: ");
5933f1a391bSalx32     }
5943f1a391bSalx32     if (Verbose)
5950ddc75fdSSimon Giesecke       OS << "\n";
5960ddc75fdSSimon Giesecke   }
5976f28b4b5Salx32 }
5980ddc75fdSSimon Giesecke 
599e161fcdeSAlex Brachet int llvm_gsymutil_main(int argc, char **argv, const llvm::ToolContext &) {
60090e40a0bSGreg Clayton   // Print a stack trace if we signal out.
60190e40a0bSGreg Clayton   sys::PrintStackTraceOnErrorSignal(argv[0]);
60290e40a0bSGreg Clayton   PrettyStackTraceProgram X(argc, argv);
60390e40a0bSGreg Clayton   llvm_shutdown_obj Y; // Call llvm_shutdown() on exit.
60490e40a0bSGreg Clayton 
60590e40a0bSGreg Clayton   llvm::InitializeAllTargets();
60690e40a0bSGreg Clayton 
607a44fffb8SAlex Brachet   parseArgs(argc, argv);
60890e40a0bSGreg Clayton 
60990e40a0bSGreg Clayton   raw_ostream &OS = outs();
61090e40a0bSGreg Clayton 
6113bdc4c70SKevin Frei   OutputAggregator Aggregation(&OS);
61290e40a0bSGreg Clayton   if (!ConvertFilename.empty()) {
61390e40a0bSGreg Clayton     // Convert DWARF to GSYM
61490e40a0bSGreg Clayton     if (!InputFilenames.empty()) {
61590e40a0bSGreg Clayton       OS << "error: no input files can be specified when using the --convert "
61690e40a0bSGreg Clayton             "option.\n";
61790e40a0bSGreg Clayton       return 1;
61890e40a0bSGreg Clayton     }
61990e40a0bSGreg Clayton     // Call error() if we have an error and it will exit with a status of 1
6203bdc4c70SKevin Frei     if (auto Err = convertFileToGSYM(Aggregation))
62190e40a0bSGreg Clayton       error("DWARF conversion failed: ", std::move(Err));
622da1880ccSKevin Frei 
6233bdc4c70SKevin Frei     // Report the errors from aggregator:
6243bdc4c70SKevin Frei     Aggregation.EnumerateResults([&](StringRef category, unsigned count) {
6253bdc4c70SKevin Frei       OS << category << " occurred " << count << " time(s)\n";
6263bdc4c70SKevin Frei     });
627da1880ccSKevin Frei     if (!JsonSummaryFile.empty()) {
628da1880ccSKevin Frei       std::error_code EC;
629da1880ccSKevin Frei       raw_fd_ostream JsonStream(JsonSummaryFile, EC, sys::fs::OF_Text);
630da1880ccSKevin Frei       if (EC) {
631da1880ccSKevin Frei         OS << "error opening aggregate error json file '" << JsonSummaryFile
632da1880ccSKevin Frei            << "' for writing: " << EC.message() << '\n';
633da1880ccSKevin Frei         return 1;
634da1880ccSKevin Frei       }
635da1880ccSKevin Frei 
636da1880ccSKevin Frei       llvm::json::Object Categories;
637da1880ccSKevin Frei       uint64_t ErrorCount = 0;
638da1880ccSKevin Frei       Aggregation.EnumerateResults([&](StringRef Category, unsigned Count) {
639da1880ccSKevin Frei         llvm::json::Object Val;
640da1880ccSKevin Frei         Val.try_emplace("count", Count);
641da1880ccSKevin Frei         Categories.try_emplace(Category, std::move(Val));
642da1880ccSKevin Frei         ErrorCount += Count;
643da1880ccSKevin Frei       });
644da1880ccSKevin Frei       llvm::json::Object RootNode;
645da1880ccSKevin Frei       RootNode.try_emplace("error-categories", std::move(Categories));
646da1880ccSKevin Frei       RootNode.try_emplace("error-count", ErrorCount);
647da1880ccSKevin Frei 
648da1880ccSKevin Frei       JsonStream << llvm::json::Value(std::move(RootNode));
649da1880ccSKevin Frei     }
65090e40a0bSGreg Clayton     return 0;
65190e40a0bSGreg Clayton   }
65290e40a0bSGreg Clayton 
6530ddc75fdSSimon Giesecke   if (LookupAddressesFromStdin) {
6540ddc75fdSSimon Giesecke     if (!LookupAddresses.empty() || !InputFilenames.empty()) {
6550ddc75fdSSimon Giesecke       OS << "error: no input files or addresses can be specified when using "
6560ddc75fdSSimon Giesecke             "the --addresses-from-stdin "
6570ddc75fdSSimon Giesecke             "option.\n";
6580ddc75fdSSimon Giesecke       return 1;
6590ddc75fdSSimon Giesecke     }
6600ddc75fdSSimon Giesecke 
6610ddc75fdSSimon Giesecke     std::string InputLine;
6620ddc75fdSSimon Giesecke     std::string CurrentGSYMPath;
663ba3d808fSKazu Hirata     std::optional<Expected<GsymReader>> CurrentGsym;
6640ddc75fdSSimon Giesecke 
6650ddc75fdSSimon Giesecke     while (std::getline(std::cin, InputLine)) {
6660ddc75fdSSimon Giesecke       // Strip newline characters.
6670ddc75fdSSimon Giesecke       std::string StrippedInputLine(InputLine);
6680ddc75fdSSimon Giesecke       llvm::erase_if(StrippedInputLine,
6690ddc75fdSSimon Giesecke                      [](char c) { return c == '\r' || c == '\n'; });
6700ddc75fdSSimon Giesecke 
6710ddc75fdSSimon Giesecke       StringRef AddrStr, GSYMPath;
6720ddc75fdSSimon Giesecke       std::tie(AddrStr, GSYMPath) =
6730ddc75fdSSimon Giesecke           llvm::StringRef{StrippedInputLine}.split(' ');
6740ddc75fdSSimon Giesecke 
6750ddc75fdSSimon Giesecke       if (GSYMPath != CurrentGSYMPath) {
6760ddc75fdSSimon Giesecke         CurrentGsym = GsymReader::openFile(GSYMPath);
6770ddc75fdSSimon Giesecke         if (!*CurrentGsym)
6780ddc75fdSSimon Giesecke           error(GSYMPath, CurrentGsym->takeError());
6799cf60d84SVictor Michel         CurrentGSYMPath = GSYMPath;
6800ddc75fdSSimon Giesecke       }
6810ddc75fdSSimon Giesecke 
6820ddc75fdSSimon Giesecke       uint64_t Addr;
6830ddc75fdSSimon Giesecke       if (AddrStr.getAsInteger(0, Addr)) {
6840ddc75fdSSimon Giesecke         OS << "error: invalid address " << AddrStr
6850ddc75fdSSimon Giesecke            << ", expected: Address GsymFile.\n";
6860ddc75fdSSimon Giesecke         return 1;
6870ddc75fdSSimon Giesecke       }
6880ddc75fdSSimon Giesecke 
6890ddc75fdSSimon Giesecke       doLookup(**CurrentGsym, Addr, OS);
6900ddc75fdSSimon Giesecke 
6910ddc75fdSSimon Giesecke       OS << "\n";
6920ddc75fdSSimon Giesecke       OS.flush();
6930ddc75fdSSimon Giesecke     }
6940ddc75fdSSimon Giesecke 
6950ddc75fdSSimon Giesecke     return EXIT_SUCCESS;
6960ddc75fdSSimon Giesecke   }
6970ddc75fdSSimon Giesecke 
69890e40a0bSGreg Clayton   // Dump or access data inside GSYM files
69990e40a0bSGreg Clayton   for (const auto &GSYMPath : InputFilenames) {
70090e40a0bSGreg Clayton     auto Gsym = GsymReader::openFile(GSYMPath);
70190e40a0bSGreg Clayton     if (!Gsym)
70290e40a0bSGreg Clayton       error(GSYMPath, Gsym.takeError());
70390e40a0bSGreg Clayton 
70490e40a0bSGreg Clayton     if (LookupAddresses.empty()) {
70590e40a0bSGreg Clayton       Gsym->dump(outs());
70690e40a0bSGreg Clayton       continue;
70790e40a0bSGreg Clayton     }
70890e40a0bSGreg Clayton 
70990e40a0bSGreg Clayton     // Lookup an address in a GSYM file and print any matches.
71090e40a0bSGreg Clayton     OS << "Looking up addresses in \"" << GSYMPath << "\":\n";
71190e40a0bSGreg Clayton     for (auto Addr : LookupAddresses) {
7120ddc75fdSSimon Giesecke       doLookup(*Gsym, Addr, OS);
71390e40a0bSGreg Clayton     }
71490e40a0bSGreg Clayton   }
71590e40a0bSGreg Clayton   return EXIT_SUCCESS;
71690e40a0bSGreg Clayton }
717