lemo updated this revision to Diff 177329.
lemo marked 3 inline comments as done.
lemo added a comment.
Incorporating feedback + adding a test case
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D55142/new/
https://reviews.llvm.org/D55142
Files:
lit/Minidump/Windows/Sigsegv/Inputs/sigsegv.cpp
lit/Minidump/Windows/Sigsegv/Inputs/sigsegv.dmp
lit/Minidump/Windows/Sigsegv/Inputs/sigsegv.lldbinit
lit/Minidump/Windows/Sigsegv/Inputs/sigsegv.pdb
lit/Minidump/Windows/Sigsegv/sigsegv.test
source/Plugins/Process/minidump/MinidumpParser.cpp
source/Plugins/Process/minidump/MinidumpParser.h
source/Plugins/Process/minidump/ProcessMinidump.cpp
source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.cpp
source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.h
source/Plugins/SymbolFile/NativePDB/PdbIndex.cpp
source/Plugins/SymbolFile/NativePDB/PdbIndex.h
source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
Index: source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
===================================================================
--- source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
+++ source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp
@@ -30,6 +30,7 @@
#include "lldb/Symbol/SymbolVendor.h"
#include "lldb/Symbol/Variable.h"
#include "lldb/Symbol/VariableList.h"
+#include "lldb/Utility/UUID.h"
#include "llvm/DebugInfo/CodeView/CVRecord.h"
#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
@@ -102,33 +103,59 @@
}
static std::unique_ptr<PDBFile>
-loadMatchingPDBFile(std::string exe_path, llvm::BumpPtrAllocator &allocator) {
- // Try to find a matching PDB for an EXE.
+loadMatchingPDBFile(lldb_private::ObjectFile& obj_file,
+ llvm::BumpPtrAllocator &allocator) {
using namespace llvm::object;
- auto expected_binary = createBinary(exe_path);
- // If the file isn't a PE/COFF executable, fail.
- if (!expected_binary) {
- llvm::consumeError(expected_binary.takeError());
- return nullptr;
- }
- OwningBinary<Binary> binary = std::move(*expected_binary);
+ // Try to find a matching PDB for an EXE.
+ std::string pdb_file;
+ llvm::codeview::GUID guid;
- auto *obj = llvm::dyn_cast<llvm::object::COFFObjectFile>(binary.getBinary());
- if (!obj)
- return nullptr;
- const llvm::codeview::DebugInfo *pdb_info = nullptr;
+ auto expected_binary = createBinary(obj_file.GetFileSpec().GetPath());
+ if (expected_binary) {
+ OwningBinary<Binary> binary = std::move(*expected_binary);
- // If it doesn't have a debug directory, fail.
- llvm::StringRef pdb_file;
- auto ec = obj->getDebugPDBInfo(pdb_info, pdb_file);
- if (ec)
- return nullptr;
+ auto *obj = llvm::dyn_cast<COFFObjectFile>(binary.getBinary());
+ if (!obj)
+ return nullptr;
+
+ const llvm::codeview::DebugInfo *pdb_info = nullptr;
+ llvm::StringRef pdb_file_name_ref;
+ if (obj->getDebugPDBInfo(pdb_info, pdb_file_name_ref)) {
+ // If it doesn't have a debug directory, fail.
+ return nullptr;
+ }
+ pdb_file = pdb_file_name_ref;
+
+ // Extract the debug GUID from the debug directory
+ memcpy(&guid, pdb_info->PDB70.Signature, sizeof(guid));
+ } else {
+ // If the file isn't a PE/COFF executable, look for the PDB in the
+ // current directory. This provides a basic solution for debugging minidumps
+ // although it's only a stop-gap (until we implement a SymbolVendor)
+ //
+ // TODO: Implement a SymbolVendor for PDBs.
+ //
+ llvm::consumeError(expected_binary.takeError());
+ pdb_file = obj_file.GetFileSpec()
+ .GetFileNameStrippingExtension()
+ .GetStringRef()
+ .str();
+ pdb_file += ".pdb";
+
+ // Extract the debug GUID from the ObjectFile
+ lldb_private::UUID uuid;
+ obj_file.GetUUID(&uuid);
+ auto uuid_bytes = uuid.GetBytes();
+ if (uuid_bytes.size() != sizeof(guid) + 4) // CvRecordPdb70
+ return nullptr;
+ memcpy(&guid, uuid_bytes.data(), sizeof(guid));
+ }
// if the file doesn't exist, is not a pdb, or doesn't have a matching guid,
// fail.
llvm::file_magic magic;
- ec = llvm::identify_magic(pdb_file, magic);
+ auto ec = llvm::identify_magic(pdb_file, magic);
if (ec || magic != llvm::file_magic::pdb)
return nullptr;
std::unique_ptr<PDBFile> pdb = loadPDBFile(pdb_file, allocator);
@@ -140,11 +167,11 @@
llvm::consumeError(expected_info.takeError());
return nullptr;
}
- llvm::codeview::GUID guid;
- memcpy(&guid, pdb_info->PDB70.Signature, 16);
+ // TODO: we need to compare the age, in addition to the GUID
if (expected_info->getGuid() != guid)
return nullptr;
+
return pdb;
}
@@ -521,7 +548,7 @@
if (!m_index) {
// Lazily load and match the PDB file, but only do this once.
std::unique_ptr<PDBFile> file_up =
- loadMatchingPDBFile(m_obj_file->GetFileSpec().GetPath(), m_allocator);
+ loadMatchingPDBFile(*m_obj_file, m_allocator);
if (!file_up) {
auto module_sp = m_obj_file->GetModule();
@@ -1459,11 +1486,10 @@
llvm::Optional<uint16_t> modi = m_index->GetModuleIndexForVa(file_addr);
if (!modi)
return 0;
- CompilandIndexItem *cci = m_index->compilands().GetCompiland(*modi);
- if (!cci)
+ if (!m_index->compilands().HasCompilandInfo(*modi))
return 0;
-
- sc.comp_unit = GetOrCreateCompileUnit(*cci).get();
+ CompilandIndexItem cci = m_index->compilands().GetOrCreateCompiland(*modi);
+ sc.comp_unit = GetOrCreateCompileUnit(cci).get();
resolved_flags |= eSymbolContextCompUnit;
}
Index: source/Plugins/SymbolFile/NativePDB/PdbIndex.h
===================================================================
--- source/Plugins/SymbolFile/NativePDB/PdbIndex.h
+++ source/Plugins/SymbolFile/NativePDB/PdbIndex.h
@@ -103,7 +103,7 @@
/// Maps virtual address to module index
llvm::IntervalMap<lldb::addr_t, uint16_t> m_va_to_modi;
- /// The address at which the program has been loaded into memory.
+ /// The address at which the module has been loaded into memory.
lldb::addr_t m_load_address = 0;
PdbIndex();
@@ -126,6 +126,8 @@
llvm::pdb::TpiStream &tpi() { return *m_tpi; }
const llvm::pdb::TpiStream &tpi() const { return *m_tpi; }
+ bool hasIpiStream() const { return m_ipi != nullptr; }
+
llvm::pdb::TpiStream &ipi() { return *m_ipi; }
const llvm::pdb::TpiStream &ipi() const { return *m_ipi; }
Index: source/Plugins/SymbolFile/NativePDB/PdbIndex.cpp
===================================================================
--- source/Plugins/SymbolFile/NativePDB/PdbIndex.cpp
+++ source/Plugins/SymbolFile/NativePDB/PdbIndex.cpp
@@ -46,12 +46,15 @@
std::unique_ptr<PdbIndex> result(new PdbIndex());
ASSIGN_PTR_OR_RETURN(result->m_dbi, file->getPDBDbiStream());
ASSIGN_PTR_OR_RETURN(result->m_tpi, file->getPDBTpiStream());
- ASSIGN_PTR_OR_RETURN(result->m_ipi, file->getPDBIpiStream());
ASSIGN_PTR_OR_RETURN(result->m_info, file->getPDBInfoStream());
ASSIGN_PTR_OR_RETURN(result->m_publics, file->getPDBPublicsStream());
ASSIGN_PTR_OR_RETURN(result->m_globals, file->getPDBGlobalsStream());
ASSIGN_PTR_OR_RETURN(result->m_symrecords, file->getPDBSymbolStream());
+ // The IPI stream is not always present
+ if (file->hasPDBIpiStream())
+ ASSIGN_PTR_OR_RETURN(result->m_ipi, file->getPDBIpiStream());
+
result->m_tpi->buildHashMap();
result->m_file = std::move(file);
@@ -113,6 +116,7 @@
// range, so we have to subtract 1.
m_imap.insert(va, end - 1, C.Imod);
}
+
void visit(const SectionContrib2 &C) override { visit(C.Base); }
};
Visitor v(*this, m_va_to_modi);
@@ -129,6 +133,11 @@
continue;
SegmentOffset so = GetSegmentAndOffset(*iter);
+ if (so.segment == 0) {
+ // TODO: https://bugs.llvm.org/show_bug.cgi?id=39882
+ lldbassert(so.offset == 0);
+ continue;
+ }
lldb::addr_t va = MakeVirtualAddress(so);
// We need to add 4 here to adjust for the codeview debug magic
@@ -147,7 +156,9 @@
// MakeVirtualAddress are much higher than the odds of encountering bad
// debug info, so assert that this item was inserted in the map as opposed
// to having already been there.
- lldbassert(insert_result.second);
+ //
+ // TODO: https://bugs.llvm.org/show_bug.cgi?id=39897
+ //lldbassert(insert_result.second);
}
}
Index: source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.h
===================================================================
--- source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.h
+++ source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.h
@@ -88,6 +88,8 @@
CompilandIndexItem *GetCompiland(uint16_t modi);
llvm::SmallString<64> GetMainSourceFile(const CompilandIndexItem &item) const;
+
+ bool HasCompilandInfo(uint16_t modi) const;
};
} // namespace npdb
} // namespace lldb_private
Index: source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.cpp
===================================================================
--- source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.cpp
+++ source/Plugins/SymbolFile/NativePDB/CompileUnitIndex.cpp
@@ -64,6 +64,9 @@
BuildInfoSym bis(SymbolRecordKind::BuildInfoSym);
llvm::cantFail(SymbolDeserializer::deserializeAs<BuildInfoSym>(sym, bis));
+ if (!index.hasIpiStream())
+ return;
+
// S_BUILDINFO just points to an LF_BUILDINFO in the IPI stream. Let's do
// a little extra work to pull out the LF_BUILDINFO.
LazyRandomTypeCollection &types = index.ipi().typeCollection();
@@ -113,6 +116,13 @@
: m_id(id), m_debug_stream(std::move(debug_stream)),
m_module_descriptor(std::move(descriptor)) {}
+bool CompileUnitIndex::HasCompilandInfo(uint16_t modi) const {
+ const DbiModuleList &modules = m_index.dbi().modules();
+ llvm::pdb::DbiModuleDescriptor descriptor = modules.getModuleDescriptor(modi);
+ uint16_t stream = descriptor.getModuleStreamIndex();
+ return stream != kInvalidStreamIndex;
+}
+
CompilandIndexItem &CompileUnitIndex::GetOrCreateCompiland(uint16_t modi) {
auto result = m_comp_units.try_emplace(modi, nullptr);
if (!result.second)
@@ -125,6 +135,7 @@
uint16_t stream = descriptor.getModuleStreamIndex();
std::unique_ptr<llvm::msf::MappedBlockStream> stream_data =
m_index.pdb().createIndexedStream(stream);
+ lldbassert(stream_data);
llvm::pdb::ModuleDebugStreamRef debug_stream(descriptor,
std::move(stream_data));
cantFail(debug_stream.reload());
Index: source/Plugins/Process/minidump/ProcessMinidump.cpp
===================================================================
--- source/Plugins/Process/minidump/ProcessMinidump.cpp
+++ source/Plugins/Process/minidump/ProcessMinidump.cpp
@@ -22,19 +22,86 @@
#include "lldb/Utility/LLDBAssert.h"
#include "lldb/Utility/Log.h"
#include "lldb/Utility/State.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/SymbolVendor.h"
+#include "lldb/Utility/Timer.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Threading.h"
#include "Plugins/Process/Utility/StopInfoMachException.h"
+
// C includes
// C++ includes
+#include <memory>
using namespace lldb;
using namespace lldb_private;
using namespace minidump;
//------------------------------------------------------------------
+/// A minimal ObjectFile implementation intended to enable the ability to
+/// consume debug information even when the module binary is not available
+///
+/// See also: PlaceholderModule
+//------------------------------------------------------------------
+class PlaceholderObjectFile : public ObjectFile {
+public:
+ PlaceholderObjectFile(const lldb::ModuleSP &module_sp, const UUID &uuid,
+ lldb::offset_t base, lldb::offset_t size)
+ : ObjectFile(module_sp, &module_sp->GetFileSpec(), 0, 0, nullptr, 0) {
+ m_type = ObjectFile::eTypeObjectFile;
+ m_file_offset = base;
+ m_length = size;
+ m_uuid = uuid;
+ }
+
+private:
+ void Dump(Stream *s) override { *s << "PlaceholderObjectFile\n"; }
+ uint32_t GetDependentModules(FileSpecList &file_list) override { return 0; }
+ bool IsExecutable() const override { return false; }
+ bool IsStripped() override { return true; }
+ bool ParseHeader() override { return true; }
+ Type CalculateType() override { return m_type; }
+ Strata CalculateStrata() override { return eStrataUnknown; }
+ void CreateSections(SectionList &unified_section_list) override {}
+
+ uint32_t GetAddressByteSize() const override {
+ return GetModule()->GetArchitecture().GetAddressByteSize();
+ }
+
+ lldb::ByteOrder GetByteOrder() const override {
+ return GetModule()->GetArchitecture().GetByteOrder();
+ }
+
+ bool GetUUID(lldb_private::UUID *uuid) override {
+ *uuid = m_uuid;
+ return true;
+ }
+
+ bool GetArchitecture(ArchSpec &arch) override {
+ arch = GetModule()->GetArchitecture();
+ return true;
+ }
+
+ Symtab *GetSymtab() override {
+ if (!m_symtab_ap) {
+ m_symtab_ap = llvm::make_unique<Symtab>(this);
+ }
+ return m_symtab_ap.get();
+ }
+
+ ConstString GetPluginName() override {
+ return ConstString("placeholder-obj");
+ }
+
+ uint32_t GetPluginVersion() override { return 1; }
+
+private:
+ UUID m_uuid;
+};
+
+//------------------------------------------------------------------
/// A placeholder module used for minidumps, where the original
/// object files may not be available (so we can't parse the object
/// files to extract the set of sections/segments)
@@ -53,10 +120,20 @@
// Creates a synthetic module section covering the whole module image (and
// sets the section load address as well)
void CreateImageSection(const MinidumpModule *module, Target& target) {
+ // Create the placeholder object file
+ {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ lldbassert(!m_did_load_objfile.load());
+ m_objfile_sp = std::make_shared<PlaceholderObjectFile>(
+ shared_from_this(), m_uuid, module->base_of_image,
+ module->size_of_image);
+ m_did_load_objfile = true;
+ }
+
const ConstString section_name(".module_image");
lldb::SectionSP section_sp(new Section(
shared_from_this(), // Module to which this section belongs.
- nullptr, // ObjectFile
+ GetObjectFile(), // ObjectFile
0, // Section ID.
section_name, // Section name.
eSectionTypeContainer, // Section type.
@@ -73,7 +150,11 @@
section_sp, module->base_of_image);
}
- ObjectFile *GetObjectFile() override { return nullptr; }
+ ObjectFile *GetObjectFile() override {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ lldbassert(m_did_load_objfile);
+ return m_objfile_sp.get();
+ }
SectionList *GetSectionList() override {
return Module::GetUnifiedSectionList();
@@ -302,15 +383,22 @@
if (m_thread_list.size() > 0)
num_threads = m_thread_list.size();
- for (lldb::tid_t tid = 0; tid < num_threads; ++tid) {
+ for (lldb::tid_t t_index = 0; t_index < num_threads; ++t_index) {
llvm::ArrayRef<uint8_t> context;
+ const auto& thread = m_thread_list[t_index];
+ auto context_location = thread.thread_context;
+ if (m_active_exception != nullptr &&
+ m_active_exception->thread_id == thread.thread_id) {
+ // If the minidump contains an exception context, use it
+ context_location = m_active_exception->thread_context;
+ }
if (!m_is_wow64)
- context = m_minidump_parser.GetThreadContext(m_thread_list[tid]);
+ context = m_minidump_parser.GetThreadContext(context_location);
else
- context = m_minidump_parser.GetThreadContextWow64(m_thread_list[tid]);
+ context = m_minidump_parser.GetThreadContextWow64(thread);
lldb::ThreadSP thread_sp(
- new ThreadMinidump(*this, m_thread_list[tid], context));
+ new ThreadMinidump(*this, m_thread_list[t_index], context));
new_thread_list.AddThread(thread_sp);
}
return new_thread_list.GetSize(false) > 0;
@@ -347,6 +435,7 @@
auto file_spec = FileSpec(name.getValue(), GetArchitecture().GetTriple());
FileSystem::Instance().Resolve(file_spec);
ModuleSpec module_spec(file_spec, uuid);
+ module_spec.GetArchitecture() = GetArchitecture();
Status error;
lldb::ModuleSP module_sp = GetTarget().GetSharedModule(module_spec, &error);
if (!module_sp || error.Fail()) {
@@ -368,6 +457,9 @@
placeholder_module->CreateImageSection(module, GetTarget());
module_sp = placeholder_module;
GetTarget().GetImages().Append(module_sp);
+
+ if (GetTarget().GetPreloadSymbols())
+ module_sp->PreloadSymbols();
}
if (log) {
Index: source/Plugins/Process/minidump/MinidumpParser.h
===================================================================
--- source/Plugins/Process/minidump/MinidumpParser.h
+++ source/Plugins/Process/minidump/MinidumpParser.h
@@ -58,6 +58,9 @@
llvm::ArrayRef<MinidumpThread> GetThreads();
+ llvm::ArrayRef<uint8_t>
+ GetThreadContext(const MinidumpLocationDescriptor &location);
+
llvm::ArrayRef<uint8_t> GetThreadContext(const MinidumpThread &td);
llvm::ArrayRef<uint8_t> GetThreadContextWow64(const MinidumpThread &td);
Index: source/Plugins/Process/minidump/MinidumpParser.cpp
===================================================================
--- source/Plugins/Process/minidump/MinidumpParser.cpp
+++ source/Plugins/Process/minidump/MinidumpParser.cpp
@@ -106,11 +106,15 @@
}
llvm::ArrayRef<uint8_t>
-MinidumpParser::GetThreadContext(const MinidumpThread &td) {
- if (td.thread_context.rva + td.thread_context.data_size > GetData().size())
+MinidumpParser::GetThreadContext(const MinidumpLocationDescriptor &location) {
+ if (location.rva + location.data_size > GetData().size())
return {};
+ return GetData().slice(location.rva, location.data_size);
+}
- return GetData().slice(td.thread_context.rva, td.thread_context.data_size);
+llvm::ArrayRef<uint8_t>
+MinidumpParser::GetThreadContext(const MinidumpThread &td) {
+ return GetThreadContext(td.thread_context);
}
llvm::ArrayRef<uint8_t>
Index: lit/Minidump/Windows/Sigsegv/sigsegv.test
===================================================================
--- lit/Minidump/Windows/Sigsegv/sigsegv.test
+++ lit/Minidump/Windows/Sigsegv/sigsegv.test
@@ -0,0 +1,22 @@
+// RUN: cd %p/Inputs
+// RUN: env LLDB_USE_NATIVE_PDB_READER=1 \
+// RUN: %lldb -c sigsegv.dmp -s sigsegv.lldbinit | FileCheck %s
+
+CHECK: * thread #1, stop reason = Exception 0xc0000005 encountered at address 0x7ff7a13110d9
+CHECK: * frame #0: 0x00007ff7a13110d9 sigsegv.exe`crash at sigsegv.cpp:22
+
+CHECK: sigsegv.exe`crash:
+CHECK: 0x7ff7a13110b0 <+0>: movb %cl, 0x8(%rsp)
+CHECK: 0x7ff7a13110b4 <+4>: subq $0x28, %rsp
+CHECK: 0x7ff7a13110b8 <+8>: leaq 0x1f41(%rip), %rcx
+CHECK: 0x7ff7a13110bf <+15>: callq 0x7ff7a1311019
+CHECK: 0x7ff7a13110c4 <+20>: movzbl 0x30(%rsp), %eax
+CHECK: 0x7ff7a13110c9 <+25>: testl %eax, %eax
+CHECK: 0x7ff7a13110cb <+27>: je 0x7ff7a13110e4 ; <+52> at sigsegv.cpp:24
+CHECK: 0x7ff7a13110cd <+29>: leaq 0x1f3c(%rip), %rcx
+CHECK: 0x7ff7a13110d4 <+36>: callq 0x7ff7a1311019
+CHECK: -> 0x7ff7a13110d9 <+41>: movl $0x0, 0x0
+CHECK: 0x7ff7a13110e4 <+52>: leaq 0x1f45(%rip), %rcx
+CHECK: 0x7ff7a13110eb <+59>: callq 0x7ff7a1311019
+CHECK: 0x7ff7a13110f0 <+64>: addq $0x28, %rsp
+CHECK: 0x7ff7a13110f4 <+68>: retq
Index: lit/Minidump/Windows/Sigsegv/Inputs/sigsegv.lldbinit
===================================================================
--- lit/Minidump/Windows/Sigsegv/Inputs/sigsegv.lldbinit
+++ lit/Minidump/Windows/Sigsegv/Inputs/sigsegv.lldbinit
@@ -0,0 +1,2 @@
+bt all
+dis
Index: lit/Minidump/Windows/Sigsegv/Inputs/sigsegv.cpp
===================================================================
--- lit/Minidump/Windows/Sigsegv/Inputs/sigsegv.cpp
+++ lit/Minidump/Windows/Sigsegv/Inputs/sigsegv.cpp
@@ -0,0 +1,40 @@
+
+// nodefaultlib build: cl -Zi sigsegv.cpp /link /nodefaultlib
+
+#ifdef USE_CRT
+#include <stdio.h>
+#else
+int main();
+extern "C"
+{
+ int _fltused;
+ void mainCRTStartup() { main(); }
+ void printf(const char*, ...) {}
+}
+#endif
+
+void crash(bool crash_self)
+{
+ printf("Before...\n");
+ if(crash_self)
+ {
+ printf("Crashing in 3, 2, 1 ...\n");
+ *(volatile int*)nullptr = 0;
+ }
+ printf("After...\n");
+}
+
+int foo(int x, float y, const char* msg)
+{
+ bool flag = x > y;
+ if(flag)
+ printf("x = %d, y = %f, msg = %s\n", x, y, msg);
+ crash(flag);
+ return x << 1;
+}
+
+int main()
+{
+ foo(10, 3.14, "testing");
+}
+
_______________________________________________
lldb-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits