4C56543519D2297A002E9C44 /* SBThreadPlan.h in Headers */ = {isa = PBXBuildFile; fileRef = 4C56543419D2297A002E9C44 /* SBThreadPlan.h */; settings = {ATTRIBUTES = (Public, ); }; };
4C56543719D22B32002E9C44 /* SBThreadPlan.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C56543619D22B32002E9C44 /* SBThreadPlan.cpp */; };
4C6649A314EEE81000B0316F /* StreamCallback.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C6649A214EEE81000B0316F /* StreamCallback.cpp */; };
- 4C6966101DA47BCE004FAE72 /* ThreadMinidump.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C6966081DA47BB4004FAE72 /* ThreadMinidump.cpp */; };
- 4C6966111DA47BDB004FAE72 /* ProcessMinidump.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C69660A1DA47BB4004FAE72 /* ProcessMinidump.cpp */; };
4C88BC2A1BA3722B00AA0964 /* Expression.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C88BC291BA3722B00AA0964 /* Expression.cpp */; };
4C88BC2D1BA391B000AA0964 /* UserExpression.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4C0083331B9A5DE200D5CF24 /* UserExpression.cpp */; };
4CABA9E0134A8BCD00539BDD /* ValueObjectMemory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4CABA9DF134A8BCD00539BDD /* ValueObjectMemory.cpp */; };
AFCB2BBD1BF577F40018B553 /* PythonExceptionState.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AFCB2BBB1BF577F40018B553 /* PythonExceptionState.cpp */; };
AFCB2BBE1BF577F40018B553 /* PythonExceptionState.h in Headers */ = {isa = PBXBuildFile; fileRef = AFCB2BBC1BF577F40018B553 /* PythonExceptionState.h */; };
AFD65C811D9B5B2E00D93120 /* RegisterContextMinidump_x86_64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AFD65C7F1D9B5B2E00D93120 /* RegisterContextMinidump_x86_64.cpp */; };
+ AFD65C821D9B5B2E00D93120 /* RegisterContextMinidump_x86_64.h in Headers */ = {isa = PBXBuildFile; fileRef = AFD65C801D9B5B2E00D93120 /* RegisterContextMinidump_x86_64.h */; };
AFDCDBCB19DD0F42005EA55E /* SBExecutionContext.h in Headers */ = {isa = PBXBuildFile; fileRef = 940B02F419DC96CB00AD0F52 /* SBExecutionContext.h */; settings = {ATTRIBUTES = (Public, ); }; };
AFDFDFD119E34D3400EAE509 /* ConnectionFileDescriptorPosix.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AFDFDFD019E34D3400EAE509 /* ConnectionFileDescriptorPosix.cpp */; };
AFEC3362194A8ABA00FF05C6 /* StructuredData.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AFEC3361194A8ABA00FF05C6 /* StructuredData.cpp */; };
23E2E5201D903726006F38BB /* linux-x86_64.dmp */ = {isa = PBXFileReference; lastKnownFileType = file; path = "linux-x86_64.dmp"; sourceTree = "<group>"; };
23E2E52D1D90382B006F38BB /* BreakpointIDTest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BreakpointIDTest.cpp; sourceTree = "<group>"; };
23E2E52E1D90382B006F38BB /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = "<group>"; };
+ 23E2E5361D9048FB006F38BB /* CMakeLists.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = CMakeLists.txt; sourceTree = "<group>"; };
23E2E5371D9048FB006F38BB /* MinidumpParser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MinidumpParser.cpp; sourceTree = "<group>"; };
23E2E5381D9048FB006F38BB /* MinidumpParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MinidumpParser.h; sourceTree = "<group>"; };
23E2E5391D9048FB006F38BB /* MinidumpTypes.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MinidumpTypes.cpp; sourceTree = "<group>"; };
4C626533130F1B0A00C889F6 /* StreamTee.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StreamTee.h; path = include/lldb/Core/StreamTee.h; sourceTree = "<group>"; };
4C66499F14EEE7F100B0316F /* StreamCallback.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StreamCallback.h; path = include/lldb/Core/StreamCallback.h; sourceTree = "<group>"; };
4C6649A214EEE81000B0316F /* StreamCallback.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = StreamCallback.cpp; path = source/Core/StreamCallback.cpp; sourceTree = "<group>"; };
- 4C6966071DA47BB4004FAE72 /* ThreadMinidump.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ThreadMinidump.h; sourceTree = "<group>"; };
- 4C6966081DA47BB4004FAE72 /* ThreadMinidump.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ThreadMinidump.cpp; sourceTree = "<group>"; };
- 4C6966091DA47BB4004FAE72 /* ProcessMinidump.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ProcessMinidump.h; sourceTree = "<group>"; };
- 4C69660A1DA47BB4004FAE72 /* ProcessMinidump.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ProcessMinidump.cpp; sourceTree = "<group>"; };
4C73152119B7D71700F865A4 /* Iterable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Iterable.h; path = include/lldb/Utility/Iterable.h; sourceTree = "<group>"; };
4C7CF7E31295E10E00B4FBB5 /* ThreadPlanCallUserExpression.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ThreadPlanCallUserExpression.h; path = include/lldb/Target/ThreadPlanCallUserExpression.h; sourceTree = "<group>"; };
4C7CF7E51295E12B00B4FBB5 /* ThreadPlanCallUserExpression.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ThreadPlanCallUserExpression.cpp; path = source/Target/ThreadPlanCallUserExpression.cpp; sourceTree = "<group>"; };
23E2E5351D9048E7006F38BB /* minidump */ = {
isa = PBXGroup;
children = (
- 4C6966071DA47BB4004FAE72 /* ThreadMinidump.h */,
- 4C6966081DA47BB4004FAE72 /* ThreadMinidump.cpp */,
- 4C6966091DA47BB4004FAE72 /* ProcessMinidump.h */,
- 4C69660A1DA47BB4004FAE72 /* ProcessMinidump.cpp */,
AFD65C7F1D9B5B2E00D93120 /* RegisterContextMinidump_x86_64.cpp */,
AFD65C801D9B5B2E00D93120 /* RegisterContextMinidump_x86_64.h */,
+ 23E2E5361D9048FB006F38BB /* CMakeLists.txt */,
23E2E5371D9048FB006F38BB /* MinidumpParser.cpp */,
23E2E5381D9048FB006F38BB /* MinidumpParser.h */,
23E2E5391D9048FB006F38BB /* MinidumpTypes.cpp */,
4984BA181B979C08008658D4 /* ExpressionVariable.h in Headers */,
26C7C4841BFFEA7E009BD01F /* WindowsMiniDump.h in Headers */,
30B38A001CAAA6D7009524E3 /* ClangUtil.h in Headers */,
+ AFD65C821D9B5B2E00D93120 /* RegisterContextMinidump_x86_64.h in Headers */,
238F2BA11D2C835A001FF92A /* StructuredDataPlugin.h in Headers */,
AF415AE81D949E4400FCE0D4 /* x86AssemblyInspectionEngine.h in Headers */,
AF8AD62F1BEC28A400150209 /* PlatformAppleTVSimulator.h in Headers */,
268900CB13353E5F00698AC0 /* LogChannelDWARF.cpp in Sources */,
268900CC13353E5F00698AC0 /* SymbolFileDWARFDebugMap.cpp in Sources */,
268900CD13353E5F00698AC0 /* UniqueDWARFASTType.cpp in Sources */,
- 4C6966101DA47BCE004FAE72 /* ThreadMinidump.cpp in Sources */,
944372DC171F6B4300E57C32 /* RegisterContextDummy.cpp in Sources */,
4C88BC2D1BA391B000AA0964 /* UserExpression.cpp in Sources */,
49E4F66B1C9CAD16008487EA /* DiagnosticManager.cpp in Sources */,
23D0658F1D4A7BEE0008EDE6 /* RenderScriptExpressionOpts.cpp in Sources */,
945215DF17F639EE00521C0B /* ValueObjectPrinter.cpp in Sources */,
26EFB61B1BFE8D3E00544801 /* PlatformNetBSD.cpp in Sources */,
- 4C6966111DA47BDB004FAE72 /* ProcessMinidump.cpp in Sources */,
AFD65C811D9B5B2E00D93120 /* RegisterContextMinidump_x86_64.cpp in Sources */,
260CC64815D0440D002BF2E0 /* OptionValueArgs.cpp in Sources */,
260CC64915D0440D002BF2E0 /* OptionValueArray.cpp in Sources */,
+++ /dev/null
-LEVEL = ../../../make
-
-CXX_SOURCES := main.cpp
-
-include $(LEVEL)/Makefile.rules
-
+++ /dev/null
-"""
-Test basics of Minidump debugging.
-"""
-
-from __future__ import print_function
-from six import iteritems
-
-
-import lldb
-from lldbsuite.test.decorators import *
-from lldbsuite.test.lldbtest import *
-from lldbsuite.test import lldbutil
-
-
-class MiniDumpNewTestCase(TestBase):
-
- mydir = TestBase.compute_mydir(__file__)
-
- NO_DEBUG_INFO_TESTCASE = True
-
- @expectedFailureAll
- def test_process_info_in_minidump(self):
- """Test that lldb can read the process information from the Minidump."""
- # target create -c linux-x86_64.dmp
- self.dbg.CreateTarget(None)
- self.target = self.dbg.GetSelectedTarget()
- self.process = self.target.LoadCore("linux-x86_64.dmp")
- self.assertTrue(self.process, PROCESS_IS_VALID)
- self.assertEqual(self.process.GetNumThreads(), 1)
- self.assertEqual(self.process.GetProcessID(), 16001)
-
- @expectedFailureAll
- def test_thread_info_in_minidump(self):
- """Test that lldb can read the thread information from the Minidump."""
- # target create -c linux-x86_64.dmp
- self.dbg.CreateTarget(None)
- self.target = self.dbg.GetSelectedTarget()
- self.process = self.target.LoadCore("linux-x86_64.dmp")
- # This process crashed due to a segmentation fault in its
- # one and only thread.
- self.assertEqual(self.process.GetNumThreads(), 1)
- thread = self.process.GetThreadAtIndex(0)
- self.assertEqual(thread.GetStopReason(), lldb.eStopReasonSignal)
- stop_description = thread.GetStopDescription(256)
- self.assertTrue("SIGSEGV" in stop_description)
-
- @expectedFailureAll
- def test_stack_info_in_minidump(self):
- """Test that we can see a trivial stack in a breakpad-generated Minidump."""
- # target create linux-x86_64 -c linux-x86_64.dmp
- self.dbg.CreateTarget("linux-x86_64")
- self.target = self.dbg.GetSelectedTarget()
- self.process = self.target.LoadCore("linux-x86_64.dmp")
- self.assertEqual(self.process.GetNumThreads(), 1)
- thread = self.process.GetThreadAtIndex(0)
- # frame #0: a.out`crash()
- # frame #1: a.out`main()
- # frame #2: libc-2.19.so`__libc_start_main()
- # frame #3: a.out`_start
- self.assertEqual(thread.GetNumFrames(), 4)
- frame = thread.GetFrameAtIndex(0)
- self.assertTrue(frame.IsValid())
- pc = frame.GetPC()
- eip = frame.FindRegister("pc")
- self.assertTrue(eip.IsValid())
- self.assertEqual(pc, eip.GetValueAsUnsigned())
-
- @expectedFailureAll
- def test_snapshot_minidump(self):
- """Test that if we load a snapshot minidump file (meaning the process did not crash) there is no stop reason."""
- # target create -c linux-x86_64_not_crashed.dmp
- self.dbg.CreateTarget(None)
- self.target = self.dbg.GetSelectedTarget()
- self.process = self.target.LoadCore("linux-x86_64_not_crashed.dmp")
- self.assertEqual(self.process.GetNumThreads(), 1)
- thread = self.process.GetThreadAtIndex(0)
- self.assertEqual(thread.GetStopReason(), lldb.eStopReasonNone)
- stop_description = thread.GetStopDescription(256)
- self.assertEqual(stop_description, None)
-
- @expectedFailureAll
- def test_deeper_stack_in_minidump(self):
- """Test that we can examine a more interesting stack in a Minidump."""
- # Launch with the Minidump, and inspect the stack.
- # target create linux-x86_64_not_crashed -c linux-x86_64_not_crashed.dmp
- target = self.dbg.CreateTarget("linux-x86_64_not_crashed")
- process = target.LoadCore("linux-x86_64_not_crashed.dmp")
- thread = process.GetThreadAtIndex(0)
-
- expected_stack = {1: 'bar', 2: 'foo', 3: 'main'}
- self.assertGreaterEqual(thread.GetNumFrames(), len(expected_stack))
- for index, name in iteritems(expected_stack):
- frame = thread.GetFrameAtIndex(index)
- self.assertTrue(frame.IsValid())
- function_name = frame.GetFunctionName()
- self.assertTrue(name in function_name)
-
- @expectedFailureAll
- def test_local_variables_in_minidump(self):
- """Test that we can examine local variables in a Minidump."""
- # Launch with the Minidump, and inspect a local variable.
- # target create linux-x86_64_not_crashed -c linux-x86_64_not_crashed.dmp
- target = self.dbg.CreateTarget("linux-x86_64_not_crashed")
- process = target.LoadCore("linux-x86_64_not_crashed.dmp")
- thread = process.GetThreadAtIndex(0)
- frame = thread.GetFrameAtIndex(1)
- value = frame.EvaluateExpression('x')
- self.assertEqual(value.GetValueAsSigned(), 3)
+++ /dev/null
-// Example source from breakpad's linux tutorial
-// https://chromium.googlesource.com/breakpad/breakpad/+/master/docs/linux_starter_guide.md
-
-#include <stdio.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include "client/linux/handler/exception_handler.h"
-
-static bool dumpCallback(const google_breakpad::MinidumpDescriptor &descriptor,
- void *context, bool succeeded) {
- printf("Dump path: %s\n", descriptor.path());
- return succeeded;
-}
-
-void crash() {
- volatile int *a = (int *)(NULL);
- *a = 1;
-}
-
-int main(int argc, char *argv[]) {
- google_breakpad::MinidumpDescriptor descriptor("/tmp");
- google_breakpad::ExceptionHandler eh(descriptor, NULL, dumpCallback, NULL,
- true, -1);
- printf("pid: %d\n", getpid());
- crash();
- return 0;
-}
+++ /dev/null
-#include <stdio.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include "client/linux/handler/exception_handler.h"
-
-static bool dumpCallback(const google_breakpad::MinidumpDescriptor& descriptor,
-void* context, bool succeeded) {
- printf("Dump path: %s\n", descriptor.path());
- return succeeded;
-}
-
-int global = 42;
-
-int
-bar(int x, google_breakpad::ExceptionHandler &eh)
-{
- eh.WriteMinidump();
- int y = 4*x + global;
- return y;
-}
-
-int
-foo(int x, google_breakpad::ExceptionHandler &eh)
-{
- int y = 2*bar(3*x, eh);
- return y;
-}
-
-
-int main(int argc, char* argv[]) {
- google_breakpad::MinidumpDescriptor descriptor("/tmp");
- google_breakpad::ExceptionHandler eh(descriptor, NULL, dumpCallback, NULL, true, -1);
- foo(1, eh);
- return 0;
-}
#include "Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h"
#include "Plugins/Process/elf-core/ProcessElfCore.h"
#include "Plugins/Process/gdb-remote/ProcessGDBRemote.h"
-#include "Plugins/Process/minidump/ProcessMinidump.h"
#include "Plugins/ScriptInterpreter/None/ScriptInterpreterNone.h"
#include "Plugins/SymbolFile/DWARF/SymbolFileDWARF.h"
#include "Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h"
#if defined(_MSC_VER)
ProcessWinMiniDump::Initialize();
#endif
- minidump::ProcessMinidump::Initialize();
MemoryHistoryASan::Initialize();
AddressSanitizerRuntime::Initialize();
ThreadSanitizerRuntime::Initialize();
JITLoaderGDB::Terminate();
ProcessElfCore::Terminate();
-
#if defined(_MSC_VER)
ProcessWinMiniDump::Terminate();
#endif
- minidump::ProcessMinidump::Terminate();
MemoryHistoryASan::Terminate();
AddressSanitizerRuntime::Terminate();
ThreadSanitizerRuntime::Terminate();
MinidumpTypes.cpp
MinidumpParser.cpp
RegisterContextMinidump_x86_64.cpp
- ThreadMinidump.cpp
- ProcessMinidump.cpp
)
-//===-- MinidumpParser.cpp -------------------------------------*- C++ -*-===//
+//===-- MinidumpParser.cpp ---------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
-//===--------------------------------------------------------------------===//
+//===----------------------------------------------------------------------===//
// Project includes
#include "MinidumpParser.h"
}
llvm::ArrayRef<uint8_t> MinidumpParser::GetData() {
- return m_data_sp->GetData();
+ return llvm::ArrayRef<uint8_t>(m_data_sp->GetBytes(),
+ m_data_sp->GetByteSize());
}
llvm::ArrayRef<uint8_t>
return {};
// check if there is enough data
- if (iter->second.rva + iter->second.data_size > GetData().size())
+ if (iter->second.rva + iter->second.data_size > m_data_sp->GetByteSize())
return {};
- return GetData().slice(iter->second.rva, iter->second.data_size);
+ return llvm::ArrayRef<uint8_t>(m_data_sp->GetBytes() + iter->second.rva,
+ iter->second.data_size);
}
llvm::Optional<std::string> MinidumpParser::GetMinidumpString(uint32_t rva) {
- auto arr_ref = GetData();
+ auto arr_ref = m_data_sp->GetData();
if (rva > arr_ref.size())
return llvm::None;
arr_ref = arr_ref.drop_front(rva);
return MinidumpThread::ParseThreadList(data);
}
-llvm::ArrayRef<uint8_t>
-MinidumpParser::GetThreadContext(const MinidumpThread &td) {
- if (td.thread_context.rva + td.thread_context.data_size > GetData().size())
- return llvm::None;
-
- return GetData().slice(td.thread_context.rva, td.thread_context.data_size);
-}
-
const MinidumpSystemInfo *MinidumpParser::GetSystemInfo() {
llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::SystemInfo);
return MinidumpExceptionStream::Parse(data);
}
-
-llvm::Optional<Range> MinidumpParser::FindMemoryRange(lldb::addr_t addr) {
- llvm::ArrayRef<uint8_t> data = GetStream(MinidumpStreamType::MemoryList);
-
- if (data.size() == 0)
- return llvm::None;
-
- llvm::ArrayRef<MinidumpMemoryDescriptor> memory_list =
- MinidumpMemoryDescriptor::ParseMemoryList(data);
-
- if (memory_list.size() == 0)
- return llvm::None;
-
- for (auto memory_desc : memory_list) {
- const MinidumpLocationDescriptor &loc_desc = memory_desc.memory;
- const lldb::addr_t range_start = memory_desc.start_of_memory_range;
- const size_t range_size = loc_desc.data_size;
-
- if (loc_desc.rva + loc_desc.data_size > GetData().size())
- return llvm::None;
-
- if (range_start <= addr && addr < range_start + range_size) {
- return Range(range_start, GetData().slice(loc_desc.rva, range_size));
- }
- }
-
- // TODO parse Memory64List which is present in full-memory Minidumps
-
- return llvm::None;
-}
-//===-- MinidumpParser.h ---------------------------------------*- C++ -*-===//
+//===-- MinidumpParser.h -----------------------------------------*- C++
+//-*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
-//===--------------------------------------------------------------------===//
+//===----------------------------------------------------------------------===//
#ifndef liblldb_MinidumpParser_h_
#define liblldb_MinidumpParser_h_
#include "llvm/ADT/StringRef.h"
// C includes
+
// C++ includes
+#include <cstring>
+#include <unordered_map>
namespace lldb_private {
namespace minidump {
-// Describes a range of memory captured in the Minidump
-struct Range {
- lldb::addr_t start; // virtual address of the beginning of the range
- // range_ref - absolute pointer to the first byte of the range and size
- llvm::ArrayRef<uint8_t> range_ref;
-
- Range(lldb::addr_t start, llvm::ArrayRef<uint8_t> range_ref)
- : start(start), range_ref(range_ref) {}
-};
-
class MinidumpParser {
public:
static llvm::Optional<MinidumpParser>
llvm::ArrayRef<MinidumpThread> GetThreads();
- llvm::ArrayRef<uint8_t> GetThreadContext(const MinidumpThread &td);
-
const MinidumpSystemInfo *GetSystemInfo();
ArchSpec GetArchitecture();
const MinidumpExceptionStream *GetExceptionStream();
- llvm::Optional<Range> FindMemoryRange(lldb::addr_t addr);
-
private:
lldb::DataBufferSP m_data_sp;
const MinidumpHeader *m_header;
if (error.Fail() || *thread_count * sizeof(MinidumpThread) > data.size())
return {};
- return llvm::makeArrayRef(
+ return llvm::ArrayRef<MinidumpThread>(
reinterpret_cast<const MinidumpThread *>(data.data()), *thread_count);
}
if (error.Fail() || *modules_count * sizeof(MinidumpModule) > data.size())
return {};
- return llvm::makeArrayRef(
+ return llvm::ArrayRef<MinidumpModule>(
reinterpret_cast<const MinidumpModule *>(data.data()), *modules_count);
}
return exception_stream;
}
-
-llvm::ArrayRef<MinidumpMemoryDescriptor>
-MinidumpMemoryDescriptor::ParseMemoryList(llvm::ArrayRef<uint8_t> &data) {
- const llvm::support::ulittle32_t *mem_ranges_count;
- Error error = consumeObject(data, mem_ranges_count);
- if (error.Fail() ||
- *mem_ranges_count * sizeof(MinidumpMemoryDescriptor) > data.size())
- return {};
-
- return llvm::makeArrayRef(
- reinterpret_cast<const MinidumpMemoryDescriptor *>(data.data()),
- *mem_ranges_count);
-}
struct MinidumpMemoryDescriptor {
llvm::support::ulittle64_t start_of_memory_range;
MinidumpLocationDescriptor memory;
-
- static llvm::ArrayRef<MinidumpMemoryDescriptor>
- ParseMemoryList(llvm::ArrayRef<uint8_t> &data);
};
static_assert(sizeof(MinidumpMemoryDescriptor) == 16,
"sizeof MinidumpMemoryDescriptor is not correct!");
// Exception stuff
struct MinidumpException {
enum {
- ExceptonInfoMaxParams = 15,
- DumpRequested = 0xFFFFFFFF,
+ MaxParams = 15,
};
llvm::support::ulittle32_t exception_code;
llvm::support::ulittle64_t exception_address;
llvm::support::ulittle32_t number_parameters;
llvm::support::ulittle32_t unused_alignment;
- llvm::support::ulittle64_t exception_information[ExceptonInfoMaxParams];
+ llvm::support::ulittle64_t exception_information[MaxParams];
};
static_assert(sizeof(MinidumpException) == 152,
"sizeof MinidumpException is not correct!");
+++ /dev/null
-//===-- ProcessMinidump.cpp -------------------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-// Project includes
-#include "ProcessMinidump.h"
-#include "ThreadMinidump.h"
-
-// Other libraries and framework includes
-#include "lldb/Core/DataBufferHeap.h"
-#include "lldb/Core/Log.h"
-#include "lldb/Core/Module.h"
-#include "lldb/Core/ModuleSpec.h"
-#include "lldb/Core/PluginManager.h"
-#include "lldb/Core/Section.h"
-#include "lldb/Core/State.h"
-#include "lldb/Target/DynamicLoader.h"
-#include "lldb/Target/MemoryRegionInfo.h"
-#include "lldb/Target/Target.h"
-#include "lldb/Target/UnixSignals.h"
-#include "lldb/Utility/LLDBAssert.h"
-
-// C includes
-// C++ includes
-
-using namespace lldb_private;
-using namespace minidump;
-
-ConstString ProcessMinidump::GetPluginNameStatic() {
- static ConstString g_name("minidump");
- return g_name;
-}
-
-const char *ProcessMinidump::GetPluginDescriptionStatic() {
- return "Minidump plug-in.";
-}
-
-lldb::ProcessSP ProcessMinidump::CreateInstance(lldb::TargetSP target_sp,
- lldb::ListenerSP listener_sp,
- const FileSpec *crash_file) {
- if (!crash_file)
- return nullptr;
-
- lldb::ProcessSP process_sp;
- // Read enough data for the Minidump header
- const size_t header_size = sizeof(MinidumpHeader);
- lldb::DataBufferSP data_sp(crash_file->MemoryMapFileContents(0, header_size));
- // The memory map can fail
- if (!data_sp)
- return nullptr;
-
- // first, only try to parse the header, beacuse we need to be fast
- llvm::ArrayRef<uint8_t> header_data(data_sp->GetBytes(), header_size);
- const MinidumpHeader *header = MinidumpHeader::Parse(header_data);
-
- if (data_sp->GetByteSize() != header_size || header == nullptr)
- return nullptr;
-
- lldb::DataBufferSP all_data_sp(crash_file->MemoryMapFileContents());
- auto minidump_parser = MinidumpParser::Create(all_data_sp);
- // check if the parser object is valid
- // skip if the Minidump file is Windows generated, because we are still
- // work-in-progress
- if (!minidump_parser ||
- minidump_parser->GetArchitecture().GetTriple().getOS() ==
- llvm::Triple::OSType::Win32)
- return nullptr;
-
- return lldb::ProcessSP(new ProcessMinidump(
- target_sp, listener_sp, *crash_file, minidump_parser.getValue()));
-}
-
-// TODO leave it to be only "return true" ?
-bool ProcessMinidump::CanDebug(lldb::TargetSP target_sp,
- bool plugin_specified_by_name) {
- return true;
-}
-
-ProcessMinidump::ProcessMinidump(lldb::TargetSP target_sp,
- lldb::ListenerSP listener_sp,
- const FileSpec &core_file,
- MinidumpParser minidump_parser)
- : Process(target_sp, listener_sp), m_minidump_parser(minidump_parser),
- m_core_file(core_file) {}
-
-ProcessMinidump::~ProcessMinidump() {
- Clear();
- // We need to call finalize on the process before destroying ourselves
- // to make sure all of the broadcaster cleanup goes as planned. If we
- // destruct this class, then Process::~Process() might have problems
- // trying to fully destroy the broadcaster.
- Finalize();
-}
-
-void ProcessMinidump::Initialize() {
- static std::once_flag g_once_flag;
-
- std::call_once(g_once_flag, []() {
- PluginManager::RegisterPlugin(GetPluginNameStatic(),
- GetPluginDescriptionStatic(),
- ProcessMinidump::CreateInstance);
- });
-}
-
-void ProcessMinidump::Terminate() {
- PluginManager::UnregisterPlugin(ProcessMinidump::CreateInstance);
-}
-
-Error ProcessMinidump::DoLoadCore() {
- Error error;
-
- m_thread_list = m_minidump_parser.GetThreads();
- m_active_exception = m_minidump_parser.GetExceptionStream();
- GetTarget().SetArchitecture(GetArchitecture());
- ReadModuleList();
-
- llvm::Optional<lldb::pid_t> pid = m_minidump_parser.GetPid();
- if (!pid) {
- error.SetErrorString("failed to parse PID");
- return error;
- }
- SetID(pid.getValue());
-
- return error;
-}
-
-DynamicLoader *ProcessMinidump::GetDynamicLoader() {
- if (m_dyld_ap.get() == nullptr)
- m_dyld_ap.reset(DynamicLoader::FindPlugin(this, nullptr));
- return m_dyld_ap.get();
-}
-
-ConstString ProcessMinidump::GetPluginName() { return GetPluginNameStatic(); }
-
-uint32_t ProcessMinidump::GetPluginVersion() { return 1; }
-
-Error ProcessMinidump::DoDestroy() { return Error(); }
-
-void ProcessMinidump::RefreshStateAfterStop() {
- if (!m_active_exception)
- return;
-
- if (m_active_exception->exception_record.exception_code ==
- MinidumpException::DumpRequested) {
- return;
- }
-
- lldb::StopInfoSP stop_info;
- lldb::ThreadSP stop_thread;
-
- Process::m_thread_list.SetSelectedThreadByID(m_active_exception->thread_id);
- stop_thread = Process::m_thread_list.GetSelectedThread();
- ArchSpec arch = GetArchitecture();
-
- if (arch.GetTriple().getOS() == llvm::Triple::Linux) {
- stop_info = StopInfo::CreateStopReasonWithSignal(
- *stop_thread, m_active_exception->exception_record.exception_code);
- } else {
- std::string desc;
- llvm::raw_string_ostream desc_stream(desc);
- desc_stream << "Exception "
- << llvm::format_hex(
- m_active_exception->exception_record.exception_code, 8)
- << " encountered at address "
- << llvm::format_hex(
- m_active_exception->exception_record.exception_address,
- 8);
- stop_info = StopInfo::CreateStopReasonWithException(
- *stop_thread, desc_stream.str().c_str());
- }
-
- stop_thread->SetStopInfo(stop_info);
-}
-
-bool ProcessMinidump::IsAlive() { return true; }
-
-bool ProcessMinidump::WarnBeforeDetach() const { return false; }
-
-size_t ProcessMinidump::ReadMemory(lldb::addr_t addr, void *buf, size_t size,
- lldb_private::Error &error) {
- // Don't allow the caching that lldb_private::Process::ReadMemory does
- // since we have it all cached in our dump file anyway.
- return DoReadMemory(addr, buf, size, error);
-}
-
-size_t ProcessMinidump::DoReadMemory(lldb::addr_t addr, void *buf, size_t size,
- lldb_private::Error &error) {
- // I don't have a sense of how frequently this is called or how many memory
- // ranges a Minidump typically has, so I'm not sure if searching for the
- // appropriate range linearly each time is stupid. Perhaps we should build
- // an index for faster lookups.
- llvm::Optional<Range> range = m_minidump_parser.FindMemoryRange(addr);
- if (!range)
- return 0;
-
- // There's at least some overlap between the beginning of the desired range
- // (addr) and the current range. Figure out where the overlap begins and
- // how much overlap there is, then copy it to the destination buffer.
- lldbassert(range->start <= addr);
- const size_t offset = addr - range->start;
- lldbassert(offset < range->range_ref.size());
- const size_t overlap = std::min(size, range->range_ref.size() - offset);
- std::memcpy(buf, range->range_ref.data() + offset, overlap);
- return overlap;
-}
-
-ArchSpec ProcessMinidump::GetArchitecture() {
- return m_minidump_parser.GetArchitecture();
-}
-
-// TODO - parse the MemoryInfoListStream and implement this method
-Error ProcessMinidump::GetMemoryRegionInfo(
- lldb::addr_t load_addr, lldb_private::MemoryRegionInfo &range_info) {
- return {};
-}
-
-void ProcessMinidump::Clear() { Process::m_thread_list.Clear(); }
-
-bool ProcessMinidump::UpdateThreadList(
- lldb_private::ThreadList &old_thread_list,
- lldb_private::ThreadList &new_thread_list) {
- uint32_t num_threads = 0;
- if (m_thread_list.size() > 0)
- num_threads = m_thread_list.size();
-
- for (lldb::tid_t tid = 0; tid < num_threads; ++tid) {
- lldb::ThreadSP thread_sp(new ThreadMinidump(
- *this, m_thread_list[tid],
- m_minidump_parser.GetThreadContext(m_thread_list[tid])));
- new_thread_list.AddThread(thread_sp);
- }
- return new_thread_list.GetSize(false) > 0;
-}
-
-void ProcessMinidump::ReadModuleList() {
- llvm::ArrayRef<MinidumpModule> modules = m_minidump_parser.GetModuleList();
-
- for (auto module : modules) {
- llvm::Optional<std::string> name =
- m_minidump_parser.GetMinidumpString(module.module_name_rva);
-
- if (!name)
- continue;
-
- const auto file_spec = FileSpec(name.getValue(), true);
- ModuleSpec module_spec = file_spec;
- Error error;
- lldb::ModuleSP module_sp =
- this->GetTarget().GetSharedModule(module_spec, &error);
- if (!module_sp || error.Fail()) {
- continue;
- }
-
- bool load_addr_changed = false;
- module_sp->SetLoadAddress(this->GetTarget(), module.base_of_image, false,
- load_addr_changed);
- }
-}
+++ /dev/null
-//===-- ProcessMinidump.h ---------------------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef liblldb_ProcessMinidump_h_
-#define liblldb_ProcessMinidump_h_
-
-// Project includes
-#include "MinidumpParser.h"
-#include "MinidumpTypes.h"
-
-// Other libraries and framework includes
-#include "lldb/Core/ConstString.h"
-#include "lldb/Core/Error.h"
-#include "lldb/Target/Process.h"
-#include "lldb/Target/StopInfo.h"
-#include "lldb/Target/Target.h"
-
-#include "llvm/Support/Format.h"
-#include "llvm/Support/raw_ostream.h"
-
-// C Includes
-// C++ Includes
-
-namespace lldb_private {
-
-namespace minidump {
-
-class ProcessMinidump : public Process {
-public:
- static lldb::ProcessSP CreateInstance(lldb::TargetSP target_sp,
- lldb::ListenerSP listener_sp,
- const FileSpec *crash_file_path);
-
- static void Initialize();
-
- static void Terminate();
-
- static ConstString GetPluginNameStatic();
-
- static const char *GetPluginDescriptionStatic();
-
- ProcessMinidump(lldb::TargetSP target_sp, lldb::ListenerSP listener_sp,
- const lldb_private::FileSpec &core_file,
- MinidumpParser minidump_parser);
-
- ~ProcessMinidump() override;
-
- bool CanDebug(lldb::TargetSP target_sp,
- bool plugin_specified_by_name) override;
-
- Error DoLoadCore() override;
-
- DynamicLoader *GetDynamicLoader() override;
-
- ConstString GetPluginName() override;
-
- uint32_t GetPluginVersion() override;
-
- Error DoDestroy() override;
-
- void RefreshStateAfterStop() override;
-
- bool IsAlive() override;
-
- bool WarnBeforeDetach() const override;
-
- size_t ReadMemory(lldb::addr_t addr, void *buf, size_t size,
- Error &error) override;
-
- size_t DoReadMemory(lldb::addr_t addr, void *buf, size_t size,
- Error &error) override;
-
- ArchSpec GetArchitecture();
-
- Error GetMemoryRegionInfo(lldb::addr_t load_addr,
- MemoryRegionInfo &range_info) override;
-
- MinidumpParser m_minidump_parser;
-
-protected:
- void Clear();
-
- bool UpdateThreadList(ThreadList &old_thread_list,
- ThreadList &new_thread_list) override;
-
- void ReadModuleList();
-
-private:
- FileSpec m_core_file;
- llvm::ArrayRef<MinidumpThread> m_thread_list;
- const MinidumpExceptionStream *m_active_exception;
-};
-
-} // namespace minidump
-} // namespace lldb_private
-
-#endif // liblldb_ProcessMinidump_h_
+++ /dev/null
-//===-- ThreadMinidump.cpp --------------------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-// Project includes
-#include "ThreadMinidump.h"
-#include "ProcessMinidump.h"
-
-#include "RegisterContextMinidump_x86_64.h"
-
-// Other libraries and framework includes
-#include "Plugins/Process/Utility/RegisterContextLinux_x86_64.h"
-
-#include "Plugins/Process/elf-core/RegisterContextPOSIXCore_x86_64.h"
-
-#include "lldb/Core/DataExtractor.h"
-#include "lldb/Core/Log.h"
-#include "lldb/Target/RegisterContext.h"
-#include "lldb/Target/StopInfo.h"
-#include "lldb/Target/Target.h"
-#include "lldb/Target/Unwind.h"
-
-// C Includes
-// C++ Includes
-
-using namespace lldb;
-using namespace lldb_private;
-using namespace minidump;
-
-ThreadMinidump::ThreadMinidump(Process &process, const MinidumpThread &td,
- llvm::ArrayRef<uint8_t> gpregset_data)
- : Thread(process, td.thread_id), m_thread_reg_ctx_sp(),
- m_gpregset_data(gpregset_data) {}
-
-ThreadMinidump::~ThreadMinidump() {}
-
-void ThreadMinidump::RefreshStateAfterStop() {}
-
-void ThreadMinidump::ClearStackFrames() {}
-
-RegisterContextSP ThreadMinidump::GetRegisterContext() {
- if (!m_reg_context_sp) {
- m_reg_context_sp = CreateRegisterContextForFrame(nullptr);
- }
- return m_reg_context_sp;
-}
-
-RegisterContextSP
-ThreadMinidump::CreateRegisterContextForFrame(StackFrame *frame) {
- RegisterContextSP reg_ctx_sp;
- uint32_t concrete_frame_idx = 0;
- Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD));
-
- if (frame)
- concrete_frame_idx = frame->GetConcreteFrameIndex();
-
- if (concrete_frame_idx == 0) {
- if (m_thread_reg_ctx_sp)
- return m_thread_reg_ctx_sp;
-
- ProcessMinidump *process =
- static_cast<ProcessMinidump *>(GetProcess().get());
- ArchSpec arch = process->GetArchitecture();
- RegisterInfoInterface *reg_interface = nullptr;
-
- // TODO write other register contexts and add them here
- switch (arch.GetMachine()) {
- case llvm::Triple::x86_64: {
- reg_interface = new RegisterContextLinux_x86_64(arch);
- lldb::DataBufferSP buf =
- ConvertMinidumpContextToRegIface(m_gpregset_data, reg_interface);
- DataExtractor gpregs(buf, lldb::eByteOrderLittle, 8);
- DataExtractor fpregs;
- m_thread_reg_ctx_sp.reset(new RegisterContextCorePOSIX_x86_64(
- *this, reg_interface, gpregs, fpregs));
- break;
- }
- default:
- break;
- }
-
- if (!reg_interface) {
- if (log)
- log->Printf("elf-core::%s:: Architecture(%d) not supported",
- __FUNCTION__, arch.GetMachine());
- assert(false && "Architecture not supported");
- }
-
- reg_ctx_sp = m_thread_reg_ctx_sp;
- } else if (m_unwinder_ap) {
- reg_ctx_sp = m_unwinder_ap->CreateRegisterContextForFrame(frame);
- }
-
- return reg_ctx_sp;
-}
-
-bool ThreadMinidump::CalculateStopInfo() { return false; }
+++ /dev/null
-//===-- ThreadMinidump.h ---------------------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef liblldb_ThreadMinidump_h_
-#define liblldb_ThreadMinidump_h_
-
-// Project includes
-#include "MinidumpTypes.h"
-
-// Other libraries and framework includes
-#include "lldb/Target/Thread.h"
-
-// C Includes
-// C++ Includes
-
-namespace lldb_private {
-
-namespace minidump {
-
-class ThreadMinidump : public Thread {
-public:
- ThreadMinidump(Process &process, const MinidumpThread &td,
- llvm::ArrayRef<uint8_t> gpregset_data);
-
- ~ThreadMinidump() override;
-
- void RefreshStateAfterStop() override;
-
- lldb::RegisterContextSP GetRegisterContext() override;
-
- lldb::RegisterContextSP
- CreateRegisterContextForFrame(StackFrame *frame) override;
-
- void ClearStackFrames() override;
-
-protected:
- lldb::RegisterContextSP m_thread_reg_ctx_sp;
- llvm::ArrayRef<uint8_t> m_gpregset_data;
-
- bool CalculateStopInfo() override;
-};
-
-} // namespace minidump
-} // namespace lldb_private
-
-#endif // liblldb_ThreadMinidump_h_
std::unique_ptr<MinidumpParser> parser;
};
-TEST_F(MinidumpParserTest, GetThreadsAndGetThreadContext) {
+TEST_F(MinidumpParserTest, GetThreads) {
SetUpData("linux-x86_64.dmp");
llvm::ArrayRef<MinidumpThread> thread_list;
ASSERT_EQ(1UL, thread_list.size());
const MinidumpThread thread = thread_list[0];
- EXPECT_EQ(16001UL, thread.thread_id);
-
- llvm::ArrayRef<uint8_t> context = parser->GetThreadContext(thread);
- EXPECT_EQ(1232, context.size());
+ ASSERT_EQ(16001UL, thread.thread_id);
}
TEST_F(MinidumpParserTest, GetThreadsTruncatedFile) {
ASSERT_EQ(11UL, exception_stream->exception_record.exception_code);
}
-TEST_F(MinidumpParserTest, GetMemoryRange) {
- SetUpData("linux-x86_64.dmp");
- // There are two memory ranges in the file (size is in bytes, decimal):
- // 1) 0x7ffceb34a000 12288
- // 2) 0x401d46 256
- EXPECT_TRUE(parser->FindMemoryRange(0x7ffceb34a000).hasValue());
- EXPECT_TRUE(parser->FindMemoryRange(0x7ffceb34a000 + 12288 / 2).hasValue());
- EXPECT_TRUE(parser->FindMemoryRange(0x7ffceb34a000 + 12288 - 1).hasValue());
- EXPECT_FALSE(parser->FindMemoryRange(0x7ffceb34a000 + 12288).hasValue());
-
- EXPECT_TRUE(parser->FindMemoryRange(0x401d46).hasValue());
- EXPECT_TRUE(parser->FindMemoryRange(0x401d46 + 256 / 2).hasValue());
- EXPECT_TRUE(parser->FindMemoryRange(0x401d46 + 256 - 1).hasValue());
- EXPECT_FALSE(parser->FindMemoryRange(0x401d46 + 256).hasValue());
-
- EXPECT_FALSE(parser->FindMemoryRange(0x2a).hasValue());
-}
-
// Windows Minidump tests
// fizzbuzz_no_heap.dmp is copied from the WinMiniDump tests
TEST_F(MinidumpParserTest, GetArchitectureWindows) {
}
// Register stuff
+// TODO probably split register stuff tests into different file?
#define REG_VAL(x) *(reinterpret_cast<uint64_t *>(x))
TEST_F(MinidumpParserTest, ConvertRegisterContext) {