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