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 @@ -112,7 +112,10 @@ cl::value_desc("addr"), cat(LookupOptions)); - +static opt LookupAddressesFromStdin( + "addresses-from-stdin", + desc("Lookup addresses in a GSYM file that are read from stdin"), + cat(LookupOptions)); } // namespace /// @} @@ -133,7 +136,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 +273,6 @@ return llvm::None; } - static llvm::Error handleObjectFile(ObjectFile &Obj, const std::string &OutFile) { auto ThreadCount = @@ -306,8 +307,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 +330,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 +360,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 +375,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 +425,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 +462,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 +485,51 @@ 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; + } + + const int kMaxInputStringLength = 1024; + char InputString[kMaxInputStringLength]; + std::string CurrentGSYMPath; + llvm::Optional> CurrentGsym; + + while (fgets(InputString, sizeof(InputString), stdin)) { + // Strip newline characters. + std::string StrippedInputString(InputString); + llvm::erase_if(StrippedInputString, + [](char c) { return c == '\r' || c == '\n'; }); + + StringRef AddrStr, GSYMPath; + std::tie(AddrStr, GSYMPath) = + llvm::StringRef{StrippedInputString}.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 +543,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;