llvm.org GIT mirror llvm / 1ac3f3e
[Symbolize] Check if the PE file has a PDB and emit an error if we can't load it Summary: Previously we would try to load PDBs for every PE executable we tried to symbolize. If that failed, we would fall back to DWARF. If there wasn't any DWARF, we'd print mostly useless symbol information using the export table. With this change, we only try to load PDBs for executables that claim to have them. If that fails, we can now print an error rather than falling back silently. This should make it a lot easier to diagnose and fix common symbolization issues, such as not having DIA or not having a PDB. Reviewers: zturner, eugenis Subscribers: llvm-commits Differential Revision: http://reviews.llvm.org/D20982 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@271725 91177308-0d34-0410-b5e6-96231b3b80d8 Reid Kleckner 3 years ago
9 changed file(s) with 166 addition(s) and 91 deletion(s). Raw diff Collapse all Expand all
4848 flush();
4949 }
5050
51 ErrorOr symbolizeCode(const std::string &ModuleName,
52 uint64_t ModuleOffset);
53 ErrorOr symbolizeInlinedCode(const std::string &ModuleName,
54 uint64_t ModuleOffset);
55 ErrorOr symbolizeData(const std::string &ModuleName,
56 uint64_t ModuleOffset);
51 Expected symbolizeCode(const std::string &ModuleName,
52 uint64_t ModuleOffset);
53 Expected symbolizeInlinedCode(const std::string &ModuleName,
54 uint64_t ModuleOffset);
55 Expected symbolizeData(const std::string &ModuleName,
56 uint64_t ModuleOffset);
5757 void flush();
5858 static std::string DemangleName(const std::string &Name,
5959 const SymbolizableModule *ModInfo);
6363 // corresponding debug info. These objects can be the same.
6464 typedef std::pair ObjectPair;
6565
66 ErrorOr
66 /// Returns a SymbolizableModule or an error if loading debug info failed.
67 /// Only one attempt is made to load a module, and errors during loading are
68 /// only reported once. Subsequent calls to get module info for a module that
69 /// failed to load will return nullptr.
70 Expected
6771 getOrCreateModuleInfo(const std::string &ModuleName);
72
6873 ObjectFile *lookUpDsymFile(const std::string &Path,
6974 const MachOObjectFile *ExeObj,
7075 const std::string &ArchName);
7378 const std::string &ArchName);
7479
7580 /// \brief Returns pair of pointers to object and debug object.
76 ErrorOr getOrCreateObjectPair(const std::string &Path,
81 Expected getOrCreateObjectPair(const std::string &Path,
7782 const std::string &ArchName);
7883
7984 /// \brief Return a pointer to object file at specified path, for a specified
8085 /// architecture (e.g. if path refers to a Mach-O universal binary, only one
8186 /// object file from it will be returned).
82 ErrorOr getOrCreateObject(const std::string &Path,
87 Expected getOrCreateObject(const std::string &Path,
8388 const std::string &ArchName);
8489
85 std::mapErrorOr>> Modules;
90 std::mapstd::unique_ptr>> Modules;
8691
8792 /// \brief Contains cached results of getOrCreateObjectPair().
88 std::map, ErrorOr>
93 std::map, ObjectPair>
8994 ObjectPairForPathArch;
9095
9196 /// \brief Contains parsed binary for each path, or parsing error.
92 std::mapErrorOr>> BinaryForPath;
97 std::mapOwningBinary>> BinaryForPath;
9398
9499 /// \brief Parsed object file for path/architecture pair, where "path" refers
95100 /// to Mach-O universal binary.
96 std::map, ErrorOr>>
101 std::map, std::unique_ptr>>
97102 ObjectForUBPathAndArch;
98103
99104 Options Opts;
869869 std::error_code getHintName(uint32_t Rva, uint16_t &Hint,
870870 StringRef &Name) const;
871871
872 /// Get PDB information out of a codeview debug directory entry.
872873 std::error_code getDebugPDBInfo(const debug_directory *DebugDir,
873874 const debug_pdb_info *&Info,
875 StringRef &PDBFileName) const;
876
877 /// Get PDB information from an executable. If the information is not present,
878 /// Info will be set to nullptr and PDBFileName will be empty. An error is
879 /// returned only on corrupt object files. Convenience accessor that can be
880 /// used if the debug directory is not already handy.
881 std::error_code getDebugPDBInfo(const debug_pdb_info *&Info,
874882 StringRef &PDBFileName) const;
875883
876884 bool isRelocatableObject() const override;
4949 namespace llvm {
5050 namespace symbolize {
5151
52 ErrorOr LLVMSymbolizer::symbolizeCode(const std::string &ModuleName,
52 Expected LLVMSymbolizer::symbolizeCode(const std::string &ModuleName,
5353 uint64_t ModuleOffset) {
54 auto InfoOrErr = getOrCreateModuleInfo(ModuleName);
55 if (auto EC = InfoOrErr.getError())
56 return EC;
57 SymbolizableModule *Info = InfoOrErr.get();
54 SymbolizableModule *Info;
55 if (auto InfoOrErr = getOrCreateModuleInfo(ModuleName))
56 Info = InfoOrErr.get();
57 else
58 return InfoOrErr.takeError();
59
60 // A null module means an error has already been reported. Return an empty
61 // result.
62 if (!Info)
63 return DILineInfo();
5864
5965 // If the user is giving us relative addresses, add the preferred base of the
6066 // object to the offset before we do the query. It's what DIContext expects.
6874 return LineInfo;
6975 }
7076
71 ErrorOr
77 Expected
7278 LLVMSymbolizer::symbolizeInlinedCode(const std::string &ModuleName,
7379 uint64_t ModuleOffset) {
74 auto InfoOrErr = getOrCreateModuleInfo(ModuleName);
75 if (auto EC = InfoOrErr.getError())
76 return EC;
77 SymbolizableModule *Info = InfoOrErr.get();
80 SymbolizableModule *Info;
81 if (auto InfoOrErr = getOrCreateModuleInfo(ModuleName))
82 Info = InfoOrErr.get();
83 else
84 return InfoOrErr.takeError();
85
86 // A null module means an error has already been reported. Return an empty
87 // result.
88 if (!Info)
89 return DIInliningInfo();
7890
7991 // If the user is giving us relative addresses, add the preferred base of the
8092 // object to the offset before we do the query. It's what DIContext expects.
92104 return InlinedContext;
93105 }
94106
95 ErrorOr LLVMSymbolizer::symbolizeData(const std::string &ModuleName,
96 uint64_t ModuleOffset) {
97 auto InfoOrErr = getOrCreateModuleInfo(ModuleName);
98 if (auto EC = InfoOrErr.getError())
99 return EC;
100 SymbolizableModule *Info = InfoOrErr.get();
107 Expected LLVMSymbolizer::symbolizeData(const std::string &ModuleName,
108 uint64_t ModuleOffset) {
109 SymbolizableModule *Info;
110 if (auto InfoOrErr = getOrCreateModuleInfo(ModuleName))
111 Info = InfoOrErr.get();
112 else
113 return InfoOrErr.takeError();
114
115 // A null module means an error has already been reported. Return an empty
116 // result.
117 if (!Info)
118 return DIGlobal();
101119
102120 // If the user is giving us relative addresses, add the preferred base of
103121 // the object to the offset before we do the query. It's what DIContext
231249 }
232250 for (const auto &Path : DsymPaths) {
233251 auto DbgObjOrErr = getOrCreateObject(Path, ArchName);
234 if (!DbgObjOrErr)
252 if (!DbgObjOrErr) {
253 // Ignore errors, the file might not exist.
254 consumeError(DbgObjOrErr.takeError());
235255 continue;
256 }
236257 ObjectFile *DbgObj = DbgObjOrErr.get();
258 if (!DbgObj)
259 continue;
237260 const MachOObjectFile *MachDbgObj = dyn_cast(DbgObj);
238261 if (!MachDbgObj)
239262 continue;
254277 if (!findDebugBinary(Path, DebuglinkName, CRCHash, DebugBinaryPath))
255278 return nullptr;
256279 auto DbgObjOrErr = getOrCreateObject(DebugBinaryPath, ArchName);
257 if (!DbgObjOrErr)
280 if (!DbgObjOrErr) {
281 // Ignore errors, the file might not exist.
282 consumeError(DbgObjOrErr.takeError());
258283 return nullptr;
284 }
259285 return DbgObjOrErr.get();
260286 }
261287
262 ErrorOr
288 Expected
263289 LLVMSymbolizer::getOrCreateObjectPair(const std::string &Path,
264290 const std::string &ArchName) {
265291 const auto &I = ObjectPairForPathArch.find(std::make_pair(Path, ArchName));
266 if (I != ObjectPairForPathArch.end())
292 if (I != ObjectPairForPathArch.end()) {
267293 return I->second;
294 }
268295
269296 auto ObjOrErr = getOrCreateObject(Path, ArchName);
270 if (auto EC = ObjOrErr.getError()) {
271 ObjectPairForPathArch.insert(
272 std::make_pair(std::make_pair(Path, ArchName), EC));
273 return EC;
297 if (!ObjOrErr) {
298 ObjectPairForPathArch.insert(std::make_pair(std::make_pair(Path, ArchName),
299 ObjectPair(nullptr, nullptr)));
300 return ObjOrErr.takeError();
274301 }
275302
276303 ObjectFile *Obj = ObjOrErr.get();
289316 return Res;
290317 }
291318
292 ErrorOr
319 Expected
293320 LLVMSymbolizer::getOrCreateObject(const std::string &Path,
294321 const std::string &ArchName) {
295322 const auto &I = BinaryForPath.find(Path);
297324 if (I == BinaryForPath.end()) {
298325 Expected> BinOrErr = createBinary(Path);
299326 if (!BinOrErr) {
300 auto EC = errorToErrorCode(BinOrErr.takeError());
301 BinaryForPath.insert(std::make_pair(Path, EC));
302 return EC;
327 BinaryForPath.insert({Path, OwningBinary()});
328 return BinOrErr.takeError();
303329 }
304330 Bin = BinOrErr->getBinary();
305331 BinaryForPath.insert(std::make_pair(Path, std::move(BinOrErr.get())));
306 } else if (auto EC = I->second.getError()) {
307 return EC;
308332 } else {
309 Bin = I->second->getBinary();
310 }
311
312 assert(Bin != nullptr);
313
314 if (MachOUniversalBinary *UB = dyn_cast(Bin)) {
333 Bin = I->second.getBinary();
334 }
335
336 if (!Bin)
337 return static_cast(nullptr);
338
339 if (MachOUniversalBinary *UB = dyn_cast_or_null(Bin)) {
315340 const auto &I = ObjectForUBPathAndArch.find(std::make_pair(Path, ArchName));
316341 if (I != ObjectForUBPathAndArch.end()) {
317 if (auto EC = I->second.getError())
318 return EC;
319 return I->second->get();
342 return I->second.get();
320343 }
321344 Expected> ObjOrErr =
322345 UB->getObjectForArch(ArchName);
323346 if (!ObjOrErr) {
324 auto EC = errorToErrorCode(ObjOrErr.takeError());
325 ObjectForUBPathAndArch.insert(
326 std::make_pair(std::make_pair(Path, ArchName), EC));
327 return EC;
347 ObjectForUBPathAndArch.insert(std::make_pair(
348 std::make_pair(Path, ArchName), std::unique_ptr()));
349 return ObjOrErr.takeError();
328350 }
329351 ObjectFile *Res = ObjOrErr->get();
330352 ObjectForUBPathAndArch.insert(std::make_pair(std::make_pair(Path, ArchName),
334356 if (Bin->isObject()) {
335357 return cast(Bin);
336358 }
337 return object_error::arch_not_found;
338 }
339
340 ErrorOr
359 return errorCodeToError(object_error::arch_not_found);
360 }
361
362 Expected
341363 LLVMSymbolizer::getOrCreateModuleInfo(const std::string &ModuleName) {
342364 const auto &I = Modules.find(ModuleName);
343365 if (I != Modules.end()) {
344 auto &InfoOrErr = I->second;
345 if (auto EC = InfoOrErr.getError())
346 return EC;
347 return InfoOrErr->get();
366 return I->second.get();
348367 }
349368 std::string BinaryName = ModuleName;
350369 std::string ArchName = Opts.DefaultArch;
358377 }
359378 }
360379 auto ObjectsOrErr = getOrCreateObjectPair(BinaryName, ArchName);
361 if (auto EC = ObjectsOrErr.getError()) {
380 if (!ObjectsOrErr) {
362381 // Failed to find valid object file.
363 Modules.insert(std::make_pair(ModuleName, EC));
364 return EC;
382 Modules.insert(
383 std::make_pair(ModuleName, std::unique_ptr()));
384 return ObjectsOrErr.takeError();
365385 }
366386 ObjectPair Objects = ObjectsOrErr.get();
367387
368388 std::unique_ptr Context;
389 // If this is a COFF object containing PDB info, use a PDBContext to
390 // symbolize. Otherwise, use DWARF.
369391 if (auto CoffObject = dyn_cast(Objects.first)) {
370 using namespace pdb;
371 // If this is a COFF object, assume it contains PDB debug information. If
372 // we don't find any we will fall back to the DWARF case.
373 std::unique_ptr Session;
374 auto Error = loadDataForEXE(
375 PDB_ReaderType::DIA, Objects.first->getFileName(), Session);
376 if (!Error) {
392 const debug_pdb_info *PDBInfo;
393 StringRef PDBFileName;
394 auto EC = CoffObject->getDebugPDBInfo(PDBInfo, PDBFileName);
395 if (!EC && PDBInfo != nullptr) {
396 using namespace pdb;
397 std::unique_ptr Session;
398 if (auto Err = loadDataForEXE(PDB_ReaderType::DIA,
399 Objects.first->getFileName(), Session)) {
400 Modules.insert(
401 std::make_pair(ModuleName, std::unique_ptr()));
402 return std::move(Err);
403 }
377404 Context.reset(new PDBContext(*CoffObject, std::move(Session)));
378 } else {
379 // Drop error
380 handleAllErrors(std::move(Error),
381 [](const ErrorInfoBase &) { return Error::success(); });
382405 }
383406 }
384407 if (!Context)
386409 assert(Context);
387410 auto InfoOrErr =
388411 SymbolizableObjectFile::create(Objects.first, std::move(Context));
412 std::unique_ptr SymMod;
413 if (InfoOrErr)
414 SymMod = std::move(InfoOrErr.get());
389415 auto InsertResult =
390 Modules.insert(std::make_pair(ModuleName, std::move(InfoOrErr)));
416 Modules.insert(std::make_pair(ModuleName, std::move(SymMod)));
391417 assert(InsertResult.second);
392 if (auto EC = InsertResult.first->second.getError())
393 return EC;
394 return InsertResult.first->second->get();
418 if (auto EC = InfoOrErr.getError())
419 return errorCodeToError(EC);
420 return InsertResult.first->second.get();
395421 }
396422
397423 namespace {
501501 InfoBytes.size());
502502 // Truncate the name at the first null byte. Ignore any padding.
503503 PDBFileName = PDBFileName.split('\0').first;
504 return std::error_code();
505 }
506
507 std::error_code COFFObjectFile::getDebugPDBInfo(const debug_pdb_info *&PDBInfo,
508 StringRef &PDBFileName) const {
509 for (const debug_directory &D : debug_directories())
510 if (D.Type == COFF::IMAGE_DEBUG_TYPE_CODEVIEW)
511 return getDebugPDBInfo(&D, PDBInfo, PDBFileName);
512 // If we get here, there is no PDB info to return.
513 PDBInfo = nullptr;
514 PDBFileName = StringRef();
504515 return std::error_code();
505516 }
506517
0 RUN: grep '^ADDR:' %s | sed -s 's/ADDR: //' \
1 RUN: | llvm-symbolizer -obj="%p/Inputs/missing_pdb.exe" 2>%t.err \
2 RUN: | FileCheck %s
3 RUN: FileCheck --check-prefix=ERROR %s < %t.err
4
5 ADDR: 0x401000
6 ADDR: 0x401001
7
8 llvm-symbolizer should print one error and two unknown line info records.
9
10 ERROR: LLVMSymbolizer: error reading file: PDB Error: Unable to load PDB. Make sure the file exists and is readable.
11 ERROR-NOT: error reading file
12
13 CHECK: ??
14 CHECK: ??:0:0
15 CHECK: ??
16 CHECK: ??:0:0
8585 "print-source-context-lines", cl::init(0),
8686 cl::desc("Print N number of source file context"));
8787
88 static bool error(std::error_code ec) {
89 if (!ec)
88 template
89 static bool error(Expected &ResOrErr) {
90 if (ResOrErr)
9091 return false;
91 errs() << "LLVMSymbolizer: error reading file: " << ec.message() << ".\n";
92 logAllUnhandledErrors(ResOrErr.takeError(), errs(),
93 "LLVMSymbolizer: error reading file: ");
9294 return true;
9395 }
9496
184186 }
185187 if (IsData) {
186188 auto ResOrErr = Symbolizer.symbolizeData(ModuleName, ModuleOffset);
187 Printer << (error(ResOrErr.getError()) ? DIGlobal() : ResOrErr.get());
189 Printer << (error(ResOrErr) ? DIGlobal() : ResOrErr.get());
188190 } else if (ClPrintInlining) {
189191 auto ResOrErr = Symbolizer.symbolizeInlinedCode(ModuleName, ModuleOffset);
190 Printer << (error(ResOrErr.getError()) ? DIInliningInfo()
192 Printer << (error(ResOrErr) ? DIInliningInfo()
191193 : ResOrErr.get());
192194 } else {
193195 auto ResOrErr = Symbolizer.symbolizeCode(ModuleName, ModuleOffset);
194 Printer << (error(ResOrErr.getError()) ? DILineInfo() : ResOrErr.get());
196 Printer << (error(ResOrErr) ? DILineInfo() : ResOrErr.get());
195197 }
196198 outs() << "\n";
197199 outs().flush();
134134 FailIfError(E.getError());
135135 }
136136
137 template static void FailIfError(Expected &E) {
138 if (E)
139 return;
140 logAllUnhandledErrors(E.takeError(), errs(), "Error: ");
141 }
142
137143 static void FailIfNotEmpty(const llvm::Twine &E) {
138144 if (E.str().empty())
139145 return;
7575 if (Begin == End)
7676 return nullptr;
7777
78 ErrorOr LineInfo = Symbolizer.symbolizeCode(Filename, Addr);
79 if (LineInfo) {
78 if (Expected LineInfo =
79 Symbolizer.symbolizeCode(Filename, Addr)) {
8080 llvm::outs() << LineInfo->FileName << ':' << LineInfo->Line << ' '
8181 << LineInfo->FunctionName << ' ';
8282 } else {
83 llvm::outs() << " ";
83 logAllUnhandledErrors(LineInfo.takeError(), llvm::outs(), " ");
8484 }
8585
8686 switch (KindFromData(Data, SizeofPtr)) {