mirror of
https://github.com/chromium/crashpad.git
synced 2025-03-09 14:06:33 +00:00
win: Save contents of PEB to minidump to start making !peb work
This makes the basics of !peb work in windbg, however, pointed-to things are not yet retrieved. For full functionality, a variety of pointers in the PEB also needs to be walked and captured. e.g. Previously: 0:000> .ecxr eax=00000007 ebx=7e383000 ecx=c3f9a943 edx=00000000 esi=006d62d0 edi=003c9280 eip=00384828 esp=005bf634 ebp=005bf638 iopl=0 nv up ei pl zr na pe nc cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010246 crashy_program!crashpad::`anonymous namespace'::SomeCrashyFunction+0x28: 00384828 c7002a000000 mov dword ptr [eax],2Ah ds:002b:00000007=???????? 0:000> !peb PEB at 7e383000 error 1 InitTypeRead( nt!_PEB at 7e383000)... Now: 0:000> .ecxr eax=00000007 ebx=7f958000 ecx=02102f4d edx=00000000 esi=00e162d0 edi=01389280 eip=01344828 esp=00c2fb64 ebp=00c2fb68 iopl=0 nv up ei pl zr na pe nc cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010246 crashy_program!crashpad::`anonymous namespace'::SomeCrashyFunction+0x28: 01344828 c7002a000000 mov dword ptr [eax],2Ah ds:002b:00000007=???????? 0:000> !peb PEB at 7f958000 InheritedAddressSpace: No ReadImageFileExecOptions: No BeingDebugged: No ImageBaseAddress: 01340000 Ldr 77ec8b40 *** unable to read Ldr table at 77ec8b40 SubSystemData: 00000000 ProcessHeap: 00e10000 ProcessParameters: 00e114e0 CurrentDirectory: '< Name not readable >' WindowTitle: '< Name not readable >' ImageFile: '< Name not readable >' CommandLine: '< Name not readable >' DllPath: '< Name not readable >' Environment: 00000000 Unable to read Environment string. R=mark@chromium.org BUG=crashpad:46 Review URL: https://codereview.chromium.org/1364053002 .
This commit is contained in:
parent
5d026ea68b
commit
0758dbde9a
@ -93,6 +93,8 @@ void MinidumpFileWriter::InitializeFromSnapshot(
|
||||
auto crashpad_info = make_scoped_ptr(new MinidumpCrashpadInfoWriter());
|
||||
crashpad_info->InitializeFromSnapshot(process_snapshot);
|
||||
|
||||
memory_list->AddFromSnapshot(process_snapshot->ExtraMemory());
|
||||
|
||||
// Since the MinidumpCrashpadInfo stream is an extension, it’s safe to not add
|
||||
// it to the minidump file if it wouldn’t carry any useful information.
|
||||
if (crashpad_info->IsUseful()) {
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "minidump/test/minidump_writable_test_util.h"
|
||||
#include "snapshot/test/test_cpu_context.h"
|
||||
#include "snapshot/test/test_exception_snapshot.h"
|
||||
#include "snapshot/test/test_memory_snapshot.h"
|
||||
#include "snapshot/test/test_module_snapshot.h"
|
||||
#include "snapshot/test/test_process_snapshot.h"
|
||||
#include "snapshot/test/test_system_snapshot.h"
|
||||
@ -252,6 +253,14 @@ TEST(MinidumpFileWriter, InitializeFromSnapshot_Basic) {
|
||||
system_snapshot->SetOperatingSystem(SystemSnapshot::kOperatingSystemMacOSX);
|
||||
process_snapshot.SetSystem(system_snapshot.Pass());
|
||||
|
||||
auto peb_snapshot = make_scoped_ptr(new TestMemorySnapshot());
|
||||
const uint64_t kPebAddress = 0x07f90000;
|
||||
peb_snapshot->SetAddress(kPebAddress);
|
||||
const size_t kPebSize = 0x280;
|
||||
peb_snapshot->SetSize(kPebSize);
|
||||
peb_snapshot->SetValue('p');
|
||||
process_snapshot.AddExtraMemory(peb_snapshot.Pass());
|
||||
|
||||
MinidumpFileWriter minidump_file_writer;
|
||||
minidump_file_writer.InitializeFromSnapshot(&process_snapshot);
|
||||
|
||||
@ -283,6 +292,13 @@ TEST(MinidumpFileWriter, InitializeFromSnapshot_Basic) {
|
||||
EXPECT_EQ(kMinidumpStreamTypeMemoryList, directory[4].StreamType);
|
||||
EXPECT_TRUE(MinidumpWritableAtLocationDescriptor<MINIDUMP_MEMORY_LIST>(
|
||||
string_file.string(), directory[4].Location));
|
||||
|
||||
const MINIDUMP_MEMORY_LIST* memory_list =
|
||||
MinidumpWritableAtLocationDescriptor<MINIDUMP_MEMORY_LIST>(
|
||||
string_file.string(), directory[4].Location);
|
||||
EXPECT_EQ(1u, memory_list->NumberOfMemoryRanges);
|
||||
EXPECT_EQ(kPebAddress, memory_list->MemoryRanges[0].StartOfMemoryRange);
|
||||
EXPECT_EQ(kPebSize, memory_list->MemoryRanges[0].Memory.DataSize);
|
||||
}
|
||||
|
||||
TEST(MinidumpFileWriter, InitializeFromSnapshot_Exception) {
|
||||
|
@ -186,6 +186,11 @@ const ExceptionSnapshot* ProcessSnapshotMac::Exception() const {
|
||||
return exception_.get();
|
||||
}
|
||||
|
||||
std::vector<const MemorySnapshot*> ProcessSnapshotMac::ExtraMemory() const {
|
||||
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
||||
return std::vector<const MemorySnapshot*>();
|
||||
}
|
||||
|
||||
void ProcessSnapshotMac::InitializeThreads() {
|
||||
const std::vector<ProcessReader::Thread>& process_reader_threads =
|
||||
process_reader_.Threads();
|
||||
|
@ -126,6 +126,7 @@ class ProcessSnapshotMac final : public ProcessSnapshot {
|
||||
std::vector<const ThreadSnapshot*> Threads() const override;
|
||||
std::vector<const ModuleSnapshot*> Modules() const override;
|
||||
const ExceptionSnapshot* Exception() const override;
|
||||
std::vector<const MemorySnapshot*> ExtraMemory() const override;
|
||||
|
||||
private:
|
||||
// Initializes threads_ on behalf of Initialize().
|
||||
|
@ -177,6 +177,13 @@ const ExceptionSnapshot* ProcessSnapshotMinidump::Exception() const {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::vector<const MemorySnapshot*> ProcessSnapshotMinidump::ExtraMemory()
|
||||
const {
|
||||
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
||||
NOTREACHED(); // https://code.google.com/p/crashpad/issues/detail?id=10
|
||||
return std::vector<const MemorySnapshot*>();
|
||||
}
|
||||
|
||||
bool ProcessSnapshotMinidump::InitializeCrashpadInfo() {
|
||||
const auto& stream_it = stream_map_.find(kMinidumpStreamTypeCrashpadInfo);
|
||||
if (stream_it == stream_map_.end()) {
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "minidump/minidump_extensions.h"
|
||||
#include "snapshot/exception_snapshot.h"
|
||||
#include "snapshot/minidump/module_snapshot_minidump.h"
|
||||
#include "snapshot/memory_snapshot.h"
|
||||
#include "snapshot/module_snapshot.h"
|
||||
#include "snapshot/process_snapshot.h"
|
||||
#include "snapshot/system_snapshot.h"
|
||||
@ -68,6 +69,7 @@ class ProcessSnapshotMinidump final : public ProcessSnapshot {
|
||||
std::vector<const ThreadSnapshot*> Threads() const override;
|
||||
std::vector<const ModuleSnapshot*> Modules() const override;
|
||||
const ExceptionSnapshot* Exception() const override;
|
||||
std::vector<const MemorySnapshot*> ExtraMemory() const override;
|
||||
|
||||
private:
|
||||
// Initializes data carried in a MinidumpCrashpadInfo stream on behalf of
|
||||
|
@ -27,6 +27,7 @@
|
||||
namespace crashpad {
|
||||
|
||||
class ExceptionSnapshot;
|
||||
class MemorySnapshot;
|
||||
class ModuleSnapshot;
|
||||
class SystemSnapshot;
|
||||
class ThreadSnapshot;
|
||||
@ -160,6 +161,15 @@ class ProcessSnapshot {
|
||||
//! object that it was obtained from. If the snapshot is not a result of
|
||||
//! an exception, returns `nullptr`.
|
||||
virtual const ExceptionSnapshot* Exception() const = 0;
|
||||
|
||||
//! \brief Returns a vector of additional memory blocks that should be
|
||||
//! included in a minidump.
|
||||
//!
|
||||
//! \return An vector of MemorySnapshot objects that will be included in the
|
||||
//! crash dump. The caller does not take ownership of these objects, they
|
||||
//! are scoped to the lifetime of the ProcessSnapshot object that they
|
||||
//! were obtained from.
|
||||
virtual std::vector<const MemorySnapshot*> ExtraMemory() const = 0;
|
||||
};
|
||||
|
||||
} // namespace crashpad
|
||||
|
@ -32,7 +32,8 @@ TestProcessSnapshot::TestProcessSnapshot()
|
||||
system_(),
|
||||
threads_(),
|
||||
modules_(),
|
||||
exception_() {
|
||||
exception_(),
|
||||
extra_memory_() {
|
||||
}
|
||||
|
||||
TestProcessSnapshot::~TestProcessSnapshot() {
|
||||
@ -97,5 +98,12 @@ const ExceptionSnapshot* TestProcessSnapshot::Exception() const {
|
||||
return exception_.get();
|
||||
}
|
||||
|
||||
std::vector<const MemorySnapshot*> TestProcessSnapshot::ExtraMemory() const {
|
||||
std::vector<const MemorySnapshot*> extra_memory;
|
||||
for (const auto& em : extra_memory_)
|
||||
extra_memory.push_back(em);
|
||||
return extra_memory;
|
||||
}
|
||||
|
||||
} // namespace test
|
||||
} // namespace crashpad
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "base/basictypes.h"
|
||||
#include "base/memory/scoped_ptr.h"
|
||||
#include "snapshot/exception_snapshot.h"
|
||||
#include "snapshot/memory_snapshot.h"
|
||||
#include "snapshot/module_snapshot.h"
|
||||
#include "snapshot/process_snapshot.h"
|
||||
#include "snapshot/system_snapshot.h"
|
||||
@ -95,6 +96,14 @@ class TestProcessSnapshot final : public ProcessSnapshot {
|
||||
exception_ = exception.Pass();
|
||||
}
|
||||
|
||||
//! \brief Add a memory snapshot to be returned by ExtraMemory().
|
||||
//!
|
||||
//! \param[in] peb The memory snapshot that will be included in ExtraMemory().
|
||||
//! The TestProcessSnapshot object takes ownership of \a extra_memory.
|
||||
void AddExtraMemory(scoped_ptr<MemorySnapshot> extra_memory) {
|
||||
extra_memory_.push_back(extra_memory.release());
|
||||
}
|
||||
|
||||
// ProcessSnapshot:
|
||||
|
||||
pid_t ProcessID() const override;
|
||||
@ -110,6 +119,7 @@ class TestProcessSnapshot final : public ProcessSnapshot {
|
||||
std::vector<const ThreadSnapshot*> Threads() const override;
|
||||
std::vector<const ModuleSnapshot*> Modules() const override;
|
||||
const ExceptionSnapshot* Exception() const override;
|
||||
std::vector<const MemorySnapshot*> ExtraMemory() const override;
|
||||
|
||||
private:
|
||||
pid_t process_id_;
|
||||
@ -125,6 +135,7 @@ class TestProcessSnapshot final : public ProcessSnapshot {
|
||||
PointerVector<ThreadSnapshot> threads_;
|
||||
PointerVector<ModuleSnapshot> modules_;
|
||||
scoped_ptr<ExceptionSnapshot> exception_;
|
||||
PointerVector<MemorySnapshot> extra_memory_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(TestProcessSnapshot);
|
||||
};
|
||||
|
@ -275,6 +275,11 @@ const std::vector<ProcessInfo::Module>& ProcessReaderWin::Modules() {
|
||||
return modules_;
|
||||
}
|
||||
|
||||
const ProcessInfo& ProcessReaderWin::GetProcessInfo() const {
|
||||
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
||||
return process_info_;
|
||||
}
|
||||
|
||||
template <class Traits>
|
||||
void ProcessReaderWin::ReadThreadData(bool is_64_reading_32) {
|
||||
DCHECK(threads_.empty());
|
||||
|
@ -82,9 +82,6 @@ class ProcessReaderWin {
|
||||
//! \return `true` if the target task is a 64-bit process.
|
||||
bool Is64Bit() const { return process_info_.Is64Bit(); }
|
||||
|
||||
pid_t ProcessID() const { return process_info_.ProcessID(); }
|
||||
pid_t ParentProcessID() const { return process_info_.ParentProcessID(); }
|
||||
|
||||
bool ReadMemory(WinVMAddress at, WinVMSize num_bytes, void* into) const;
|
||||
|
||||
//! \brief Determines the target process' start time.
|
||||
@ -112,6 +109,9 @@ class ProcessReaderWin {
|
||||
//! `0`) corresponds to the main executable.
|
||||
const std::vector<ProcessInfo::Module>& Modules();
|
||||
|
||||
//! \return A ProcessInfo object for the process being read.
|
||||
const ProcessInfo& GetProcessInfo() const;
|
||||
|
||||
private:
|
||||
template <class Traits>
|
||||
void ReadThreadData(bool is_64_reading_32);
|
||||
|
@ -38,7 +38,7 @@ TEST(ProcessReaderWin, SelfBasic) {
|
||||
EXPECT_TRUE(process_reader.Is64Bit());
|
||||
#endif
|
||||
|
||||
EXPECT_EQ(GetCurrentProcessId(), process_reader.ProcessID());
|
||||
EXPECT_EQ(GetCurrentProcessId(), process_reader.GetProcessInfo().ProcessID());
|
||||
|
||||
const char kTestMemory[] = "Some test memory";
|
||||
char buffer[arraysize(kTestMemory)];
|
||||
|
@ -48,6 +48,10 @@ bool ProcessSnapshotWin::Initialize(HANDLE process,
|
||||
return false;
|
||||
|
||||
system_.Initialize(&process_reader_);
|
||||
WinVMAddress peb_address;
|
||||
WinVMSize peb_size;
|
||||
process_reader_.GetProcessInfo().Peb(&peb_address, &peb_size);
|
||||
peb_.Initialize(&process_reader_, peb_address, peb_size);
|
||||
|
||||
InitializeThreads();
|
||||
InitializeModules();
|
||||
@ -112,12 +116,12 @@ void ProcessSnapshotWin::GetCrashpadOptions(
|
||||
|
||||
pid_t ProcessSnapshotWin::ProcessID() const {
|
||||
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
||||
return process_reader_.ProcessID();
|
||||
return process_reader_.GetProcessInfo().ProcessID();
|
||||
}
|
||||
|
||||
pid_t ProcessSnapshotWin::ParentProcessID() const {
|
||||
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
||||
return process_reader_.ParentProcessID();
|
||||
return process_reader_.GetProcessInfo().ParentProcessID();
|
||||
}
|
||||
|
||||
void ProcessSnapshotWin::SnapshotTime(timeval* snapshot_time) const {
|
||||
@ -179,6 +183,13 @@ const ExceptionSnapshot* ProcessSnapshotWin::Exception() const {
|
||||
return exception_.get();
|
||||
}
|
||||
|
||||
std::vector<const MemorySnapshot*> ProcessSnapshotWin::ExtraMemory() const {
|
||||
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
||||
std::vector<const MemorySnapshot*> extra_memory;
|
||||
extra_memory.push_back(&peb_);
|
||||
return extra_memory;
|
||||
}
|
||||
|
||||
void ProcessSnapshotWin::InitializeThreads() {
|
||||
const std::vector<ProcessReaderWin::Thread>& process_reader_threads =
|
||||
process_reader_.Threads();
|
||||
|
@ -27,11 +27,13 @@
|
||||
#include "client/crashpad_info.h"
|
||||
#include "snapshot/crashpad_info_client_options.h"
|
||||
#include "snapshot/exception_snapshot.h"
|
||||
#include "snapshot/memory_snapshot.h"
|
||||
#include "snapshot/module_snapshot.h"
|
||||
#include "snapshot/process_snapshot.h"
|
||||
#include "snapshot/system_snapshot.h"
|
||||
#include "snapshot/thread_snapshot.h"
|
||||
#include "snapshot/win/exception_snapshot_win.h"
|
||||
#include "snapshot/win/memory_snapshot_win.h"
|
||||
#include "snapshot/win/module_snapshot_win.h"
|
||||
#include "snapshot/win/system_snapshot_win.h"
|
||||
#include "snapshot/win/thread_snapshot_win.h"
|
||||
@ -123,6 +125,7 @@ class ProcessSnapshotWin final : public ProcessSnapshot {
|
||||
std::vector<const ThreadSnapshot*> Threads() const override;
|
||||
std::vector<const ModuleSnapshot*> Modules() const override;
|
||||
const ExceptionSnapshot* Exception() const override;
|
||||
std::vector<const MemorySnapshot*> ExtraMemory() const override;
|
||||
|
||||
private:
|
||||
// Initializes threads_ on behalf of Initialize().
|
||||
@ -132,6 +135,7 @@ class ProcessSnapshotWin final : public ProcessSnapshot {
|
||||
void InitializeModules();
|
||||
|
||||
internal::SystemSnapshotWin system_;
|
||||
internal::MemorySnapshotWin peb_;
|
||||
PointerVector<internal::ThreadSnapshotWin> threads_;
|
||||
PointerVector<internal::ModuleSnapshotWin> modules_;
|
||||
scoped_ptr<internal::ExceptionSnapshotWin> exception_;
|
||||
|
@ -110,7 +110,8 @@ template <class Traits>
|
||||
bool GetProcessBasicInformation(HANDLE process,
|
||||
bool is_wow64,
|
||||
ProcessInfo* process_info,
|
||||
WinVMAddress* peb_address) {
|
||||
WinVMAddress* peb_address,
|
||||
WinVMSize* peb_size) {
|
||||
ULONG bytes_returned;
|
||||
process_types::PROCESS_BASIC_INFORMATION<Traits> process_basic_information;
|
||||
NTSTATUS status =
|
||||
@ -143,6 +144,7 @@ bool GetProcessBasicInformation(HANDLE process,
|
||||
// The address of this is found by a second call to NtQueryInformationProcess.
|
||||
if (!is_wow64) {
|
||||
*peb_address = process_basic_information.PebBaseAddress;
|
||||
*peb_size = sizeof(process_types::PEB<Traits>);
|
||||
} else {
|
||||
ULONG_PTR wow64_peb_address;
|
||||
status = crashpad::NtQueryInformationProcess(process,
|
||||
@ -159,6 +161,7 @@ bool GetProcessBasicInformation(HANDLE process,
|
||||
return false;
|
||||
}
|
||||
*peb_address = wow64_peb_address;
|
||||
*peb_size = sizeof(process_types::PEB<process_types::internal::Traits32>);
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -260,6 +263,8 @@ ProcessInfo::ProcessInfo()
|
||||
: process_id_(),
|
||||
inherited_from_process_id_(),
|
||||
command_line_(),
|
||||
peb_address_(0),
|
||||
peb_size_(0),
|
||||
modules_(),
|
||||
is_64_bit_(false),
|
||||
is_wow64_(false),
|
||||
@ -293,13 +298,12 @@ bool ProcessInfo::Initialize(HANDLE process) {
|
||||
}
|
||||
#endif
|
||||
|
||||
WinVMAddress peb_address;
|
||||
#if ARCH_CPU_64_BITS
|
||||
bool result = GetProcessBasicInformation<process_types::internal::Traits64>(
|
||||
process, is_wow64_, this, &peb_address);
|
||||
process, is_wow64_, this, &peb_address_, &peb_size_);
|
||||
#else
|
||||
bool result = GetProcessBasicInformation<process_types::internal::Traits32>(
|
||||
process, false, this, &peb_address);
|
||||
process, false, this, &peb_address_, &peb_size_);
|
||||
#endif // ARCH_CPU_64_BITS
|
||||
|
||||
if (!result) {
|
||||
@ -308,9 +312,9 @@ bool ProcessInfo::Initialize(HANDLE process) {
|
||||
}
|
||||
|
||||
result = is_64_bit_ ? ReadProcessData<process_types::internal::Traits64>(
|
||||
process, peb_address, this)
|
||||
process, peb_address_, this)
|
||||
: ReadProcessData<process_types::internal::Traits32>(
|
||||
process, peb_address, this);
|
||||
process, peb_address_, this);
|
||||
if (!result) {
|
||||
LOG(ERROR) << "ReadProcessData failed";
|
||||
return false;
|
||||
@ -346,6 +350,11 @@ bool ProcessInfo::CommandLine(std::wstring* command_line) const {
|
||||
return true;
|
||||
}
|
||||
|
||||
void ProcessInfo::Peb(WinVMAddress* peb_address, WinVMSize* peb_size) const {
|
||||
*peb_address = peb_address_;
|
||||
*peb_size = peb_size_;
|
||||
}
|
||||
|
||||
bool ProcessInfo::Modules(std::vector<Module>* modules) const {
|
||||
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
||||
*modules = modules_;
|
||||
|
@ -78,6 +78,13 @@ class ProcessInfo {
|
||||
//! Block.
|
||||
bool CommandLine(std::wstring* command_line) const;
|
||||
|
||||
//! \brief Gets the address and size of the process's Process Environment
|
||||
//! Block.
|
||||
//!
|
||||
//! \param[out] peb_address The address of the Process Environment Block.
|
||||
//! \param[out] peb_size The size of the Process Environment Block.
|
||||
void Peb(WinVMAddress* peb_address, WinVMSize* peb_size) const;
|
||||
|
||||
//! \brief Retrieves the modules loaded into the target process.
|
||||
//!
|
||||
//! The modules are enumerated in initialization order as detailed in the
|
||||
@ -90,7 +97,8 @@ class ProcessInfo {
|
||||
friend bool GetProcessBasicInformation(HANDLE process,
|
||||
bool is_wow64,
|
||||
ProcessInfo* process_info,
|
||||
WinVMAddress* peb_address);
|
||||
WinVMAddress* peb_address,
|
||||
WinVMSize* peb_size);
|
||||
template <class Traits>
|
||||
friend bool ReadProcessData(HANDLE process,
|
||||
WinVMAddress peb_address_vmaddr,
|
||||
@ -99,6 +107,8 @@ class ProcessInfo {
|
||||
pid_t process_id_;
|
||||
pid_t inherited_from_process_id_;
|
||||
std::wstring command_line_;
|
||||
WinVMAddress peb_address_;
|
||||
WinVMSize peb_size_;
|
||||
std::vector<Module> modules_;
|
||||
bool is_64_bit_;
|
||||
bool is_wow64_;
|
||||
|
Loading…
x
Reference in New Issue
Block a user