diff --git a/llvm/test/tools/llvm-gsymutil/X86/elf-dwarf.yaml b/llvm/test/tools/llvm-gsymutil/X86/elf-dwarf.yaml --- a/llvm/test/tools/llvm-gsymutil/X86/elf-dwarf.yaml +++ b/llvm/test/tools/llvm-gsymutil/X86/elf-dwarf.yaml @@ -5,6 +5,8 @@ # RUN: yaml2obj %s -o %t # RUN: llvm-gsymutil --convert %t -o %t.gsym 2>&1 | FileCheck %s --check-prefix=CONVERT # RUN: llvm-gsymutil --address=0x400391 --address=0x4004cd %t.gsym 2>&1 | FileCheck %s --check-prefix=ADDR +# RUN: echo -e "0x400391 %/t.gsym\n0x4004cd %/t.gsym" | llvm-gsymutil --addresses-from-stdin 2>&1 | FileCheck %s --check-prefix=ADDRI --dump-input=always +# RUN: llvm-gsymutil --address=0x400391 --address=0x4004cd --verbose %t.gsym 2>&1 | FileCheck %s --check-prefix=ADDRV --dump-input=always # RUN: llvm-gsymutil --address=0x400391 --address=0x4004cd --verbose %t.gsym 2>&1 | FileCheck %s --check-prefix=ADDRV --dump-input=always # RUN: llvm-gsymutil %t.gsym 2>&1 | FileCheck %s --check-prefix=DUMP @@ -12,6 +14,11 @@ # ADDR: 0x0000000000400391: _init # ADDR: 0x00000000004004cd: main @ /tmp/main.cpp:1 +# ADDRI: 0x0000000000400391: _init +# ADDRI-EMPTY: +# ADDRI: 0x00000000004004cd: main @ /tmp/main.cpp:1 +# ADDRI-EMPTY: + # ADDRV: Looking up addresses in "{{.*\.yaml\.tmp\.gsym}}": # ADDRV: FunctionInfo for 0x0000000000400391: # ADDRV: [0x0000000000400390 - 0x0000000000400390) "_init" diff --git a/llvm/test/tools/llvm-gsymutil/cmdline.test b/llvm/test/tools/llvm-gsymutil/cmdline.test --- a/llvm/test/tools/llvm-gsymutil/cmdline.test +++ b/llvm/test/tools/llvm-gsymutil/cmdline.test @@ -14,8 +14,13 @@ HELP: --version HELP: Lookup Options: HELP: --address= +HELP: --addresses-from-stdin HELP: Options: HELP: --verbose RUN: llvm-gsymutil --version 2>&1 | FileCheck --check-prefix=VERSION %s VERSION: {{ version }} + +RUN: not llvm-gsymutil --addresses-from-stdin --address 0x12345678 | FileCheck --check-prefix=INCOMPATIBLE %s +RUN: not llvm-gsymutil --addresses-from-stdin llvm-gsymutil | FileCheck --check-prefix=INCOMPATIBLE %s +INCOMPATIBLE: error: no input files or addresses can be specified when using the --addresses-from-stdin option. diff --git a/llvm/tools/llvm-gsymutil/llvm-gsymutil.cpp b/llvm/tools/llvm-gsymutil/llvm-gsymutil.cpp --- a/llvm/tools/llvm-gsymutil/llvm-gsymutil.cpp +++ b/llvm/tools/llvm-gsymutil/llvm-gsymutil.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -112,7 +113,11 @@ cl::value_desc("addr"), cat(LookupOptions)); - +static opt LookupAddressesFromStdin( + "addresses-from-stdin", + desc("Lookup addresses in a GSYM file that are read from stdin\nEach input " + "line is expected to be of the following format: "), + cat(LookupOptions)); } // namespace /// @} @@ -133,7 +138,6 @@ exit(1); } - /// If the input path is a .dSYM bundle (as created by the dsymutil tool), /// replace it with individual entries for each of the object files inside the /// bundle otherwise return the input path. @@ -271,7 +275,6 @@ return llvm::None; } - static llvm::Error handleObjectFile(ObjectFile &Obj, const std::string &OutFile) { auto ThreadCount = @@ -306,8 +309,7 @@ if (!DICtx) return createStringError(std::errc::invalid_argument, "unable to create DWARF context"); - logAllUnhandledErrors(DICtx->loadRegisterInfo(Obj), OS, - "DwarfTransformer: "); + logAllUnhandledErrors(DICtx->loadRegisterInfo(Obj), OS, "DwarfTransformer: "); // Make a DWARF transformer object and populate the ranges of the code // so we don't end up adding invalid functions to GSYM data. @@ -330,8 +332,8 @@ return Err; // Save the GSYM file to disk. - support::endianness Endian = Obj.makeTriple().isLittleEndian() ? - support::little : support::big; + support::endianness Endian = + Obj.makeTriple().isLittleEndian() ? support::little : support::big; if (auto Err = Gsym.save(OutFile.c_str(), Endian)) return Err; @@ -360,7 +362,7 @@ // Iterate over all contained architectures and filter out any that were // not specified with the "--arch " option. If the --arch option was // not specified on the command line, we will process all architectures. - std::vector< std::unique_ptr > FilterObjs; + std::vector> FilterObjs; for (auto &ObjForArch : Fat->objects()) { if (auto MachOOrErr = ObjForArch.getAsObjectFile()) { auto &Obj = **MachOOrErr; @@ -375,7 +377,7 @@ "no matching architectures found")); // Now handle each architecture we need to convert. - for (auto &Obj: FilterObjs) { + for (auto &Obj : FilterObjs) { Triple ObjTriple(Obj->getArchTriple()); auto ArchName = ObjTriple.getArchName(); std::string ArchOutFile(OutFile); @@ -425,6 +427,27 @@ return Error::success(); } +static void doLookup(GsymReader &Gsym, uint64_t Addr, raw_ostream &OS) { + if (auto Result = Gsym.lookup(Addr)) { + // If verbose is enabled dump the full function info for the address. + if (Verbose) { + if (auto FI = Gsym.getFunctionInfo(Addr)) { + OS << "FunctionInfo for " << HEX64(Addr) << ":\n"; + Gsym.dump(OS, *FI); + OS << "\nLookupResult for " << HEX64(Addr) << ":\n"; + } + } + OS << Result.get(); + } else { + if (Verbose) + OS << "\nLookupResult for " << HEX64(Addr) << ":\n"; + OS << HEX64(Addr) << ": "; + logAllUnhandledErrors(Result.takeError(), OS, "error: "); + } + if (Verbose) + OS << "\n"; +} + int main(int argc, char const *argv[]) { // Print a stack trace if we signal out. sys::PrintStackTraceOnErrorSignal(argv[0]); @@ -441,8 +464,7 @@ "lookup addresses within that GSYM file.\n" "Use the --convert option to specify a file with option --out-file " "option to convert to GSYM format.\n"; - HideUnrelatedOptions( - {&GeneralOptions, &ConversionOptions, &LookupOptions}); + HideUnrelatedOptions({&GeneralOptions, &ConversionOptions, &LookupOptions}); cl::ParseCommandLineOptions(argc, argv, Overview); if (Help) { @@ -465,6 +487,50 @@ return 0; } + if (LookupAddressesFromStdin) { + if (!LookupAddresses.empty() || !InputFilenames.empty()) { + OS << "error: no input files or addresses can be specified when using " + "the --addresses-from-stdin " + "option.\n"; + return 1; + } + + std::string InputLine; + std::string CurrentGSYMPath; + llvm::Optional> CurrentGsym; + + while (std::getline(std::cin, InputLine)) { + // Strip newline characters. + std::string StrippedInputLine(InputLine); + llvm::erase_if(StrippedInputLine, + [](char c) { return c == '\r' || c == '\n'; }); + + StringRef AddrStr, GSYMPath; + std::tie(AddrStr, GSYMPath) = + llvm::StringRef{StrippedInputLine}.split(' '); + + if (GSYMPath != CurrentGSYMPath) { + CurrentGsym = GsymReader::openFile(GSYMPath); + if (!*CurrentGsym) + error(GSYMPath, CurrentGsym->takeError()); + } + + uint64_t Addr; + if (AddrStr.getAsInteger(0, Addr)) { + OS << "error: invalid address " << AddrStr + << ", expected: Address GsymFile.\n"; + return 1; + } + + doLookup(**CurrentGsym, Addr, OS); + + OS << "\n"; + OS.flush(); + } + + return EXIT_SUCCESS; + } + // Dump or access data inside GSYM files for (const auto &GSYMPath : InputFilenames) { auto Gsym = GsymReader::openFile(GSYMPath); @@ -478,25 +544,8 @@ // Lookup an address in a GSYM file and print any matches. OS << "Looking up addresses in \"" << GSYMPath << "\":\n"; - for (auto Addr: LookupAddresses) { - if (auto Result = Gsym->lookup(Addr)) { - // If verbose is enabled dump the full function info for the address. - if (Verbose) { - if (auto FI = Gsym->getFunctionInfo(Addr)) { - OS << "FunctionInfo for " << HEX64(Addr) << ":\n"; - Gsym->dump(OS, *FI); - OS << "\nLookupResult for " << HEX64(Addr) << ":\n"; - } - } - OS << Result.get(); - } else { - if (Verbose) - OS << "\nLookupResult for " << HEX64(Addr) << ":\n"; - OS << HEX64(Addr) << ": "; - logAllUnhandledErrors(Result.takeError(), OS, "error: "); - } - if (Verbose) - OS << "\n"; + for (auto Addr : LookupAddresses) { + doLookup(*Gsym, Addr, OS); } } return EXIT_SUCCESS;