Skip to content

Commit 6c3d03c

Browse files
Implement DoReadMemory for Windows mini dumps.
Differential Revision: http://reviews.llvm.org/D12507 llvm-svn: 246558
1 parent c963a22 commit 6c3d03c

File tree

2 files changed

+93
-5
lines changed

2 files changed

+93
-5
lines changed

lldb/source/Plugins/Process/Windows/MiniDump/ProcessWinMiniDump.cpp

Lines changed: 76 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -227,19 +227,42 @@ ProcessWinMiniDump::IsAlive()
227227
return true;
228228
}
229229

230+
bool
231+
ProcessWinMiniDump::WarnBeforeDetach () const
232+
{
233+
// Since this is post-mortem debugging, there's no need to warn the user
234+
// that quitting the debugger will terminate the process.
235+
return false;
236+
}
237+
230238
size_t
231239
ProcessWinMiniDump::ReadMemory(lldb::addr_t addr, void *buf, size_t size, Error &error)
232240
{
233241
// Don't allow the caching that lldb_private::Process::ReadMemory does
234-
// since in core files we have it all cached our our core file anyway.
242+
// since we have it all cached our our dump file anyway.
235243
return DoReadMemory(addr, buf, size, error);
236244
}
237245

238246
size_t
239247
ProcessWinMiniDump::DoReadMemory(lldb::addr_t addr, void *buf, size_t size, Error &error)
240248
{
241-
// TODO
242-
return 0;
249+
// I don't have a sense of how frequently this is called or how many memory
250+
// ranges a mini dump typically has, so I'm not sure if searching for the
251+
// appropriate range linearly each time is stupid. Perhaps we should build
252+
// an index for faster lookups.
253+
Range range = {0};
254+
if (!FindMemoryRange(addr, &range))
255+
{
256+
return 0;
257+
}
258+
259+
// There's at least some overlap between the beginning of the desired range
260+
// (addr) and the current range. Figure out where the overlap begins and
261+
// how much overlap there is, then copy it to the destination buffer.
262+
const size_t offset = range.start - addr;
263+
const size_t overlap = std::min(size, range.size - offset);
264+
std::memcpy(buf, range.ptr + offset, overlap);
265+
return overlap;
243266
}
244267

245268
void
@@ -307,6 +330,54 @@ ProcessWinMiniDump::Data::~Data()
307330
}
308331
}
309332

333+
bool
334+
ProcessWinMiniDump::FindMemoryRange(lldb::addr_t addr, Range *range_out) const
335+
{
336+
size_t stream_size = 0;
337+
auto mem_list_stream = static_cast<const MINIDUMP_MEMORY_LIST *>(FindDumpStream(MemoryListStream, &stream_size));
338+
if (mem_list_stream)
339+
{
340+
for (ULONG32 i = 0; i < mem_list_stream->NumberOfMemoryRanges; ++i) {
341+
const MINIDUMP_MEMORY_DESCRIPTOR &mem_desc = mem_list_stream->MemoryRanges[i];
342+
const MINIDUMP_LOCATION_DESCRIPTOR &loc_desc = mem_desc.Memory;
343+
const lldb::addr_t range_start = mem_desc.StartOfMemoryRange;
344+
const size_t range_size = loc_desc.DataSize;
345+
if (range_start <= addr && addr < range_start + range_size)
346+
{
347+
range_out->start = range_start;
348+
range_out->size = range_size;
349+
range_out->ptr = reinterpret_cast<const uint8_t *>(m_data_up->m_base_addr) + loc_desc.Rva;
350+
return true;
351+
}
352+
}
353+
}
354+
355+
// Some mini dumps have a Memory64ListStream that captures all the heap
356+
// memory. We can't exactly use the same loop as above, because the mini
357+
// dump uses slightly different data structures to describe those.
358+
auto mem_list64_stream = static_cast<const MINIDUMP_MEMORY64_LIST *>(FindDumpStream(Memory64ListStream, &stream_size));
359+
if (mem_list64_stream)
360+
{
361+
size_t base_rva = mem_list64_stream->BaseRva;
362+
for (ULONG32 i = 0; i < mem_list64_stream->NumberOfMemoryRanges; ++i) {
363+
const MINIDUMP_MEMORY_DESCRIPTOR64 &mem_desc = mem_list64_stream->MemoryRanges[i];
364+
const lldb::addr_t range_start = mem_desc.StartOfMemoryRange;
365+
const size_t range_size = mem_desc.DataSize;
366+
if (range_start <= addr && addr < range_start + range_size)
367+
{
368+
range_out->start = range_start;
369+
range_out->size = range_size;
370+
range_out->ptr = reinterpret_cast<const uint8_t *>(m_data_up->m_base_addr) + base_rva;
371+
return true;
372+
}
373+
base_rva += range_size;
374+
}
375+
}
376+
377+
return false;
378+
}
379+
380+
310381
Error
311382
ProcessWinMiniDump::MapMiniDumpIntoMemory(const char *file)
312383
{
@@ -397,7 +468,8 @@ ProcessWinMiniDump::ReadModuleList() {
397468
}
398469

399470
void *
400-
ProcessWinMiniDump::FindDumpStream(unsigned stream_number, size_t *size_out) {
471+
ProcessWinMiniDump::FindDumpStream(unsigned stream_number, size_t *size_out) const
472+
{
401473
void *stream = nullptr;
402474
*size_out = 0;
403475

lldb/source/Plugins/Process/Windows/MiniDump/ProcessWinMiniDump.h

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,9 @@ class ProcessWinMiniDump : public lldb_private::Process
7070
bool
7171
IsAlive() override;
7272

73+
bool
74+
WarnBeforeDetach () const override;
75+
7376
size_t
7477
ReadMemory(lldb::addr_t addr, void *buf, size_t size, lldb_private::Error &error) override;
7578

@@ -91,6 +94,19 @@ class ProcessWinMiniDump : public lldb_private::Process
9194
lldb_private::ThreadList &new_thread_list) override;
9295

9396
private:
97+
// Describes a range of memory captured in the mini dump.
98+
struct Range {
99+
lldb::addr_t start; // virtual address of the beginning of the range
100+
size_t size; // size of the range in bytes
101+
const uint8_t *ptr; // absolute pointer to the first byte of the range
102+
};
103+
104+
// If the mini dump has a memory range that contains the desired address, it
105+
// returns true with the details of the range in *range_out. Otherwise, it
106+
// returns false.
107+
bool
108+
FindMemoryRange(lldb::addr_t addr, Range *range_out) const;
109+
94110
lldb_private::Error
95111
MapMiniDumpIntoMemory(const char *file);
96112

@@ -107,7 +123,7 @@ class ProcessWinMiniDump : public lldb_private::Process
107123
// checks. If there's a failure (e.g., if the requested stream doesn't exist),
108124
// the function returns nullptr and sets *size_out to 0.
109125
void *
110-
FindDumpStream(unsigned stream_number, size_t *size_out);
126+
FindDumpStream(unsigned stream_number, size_t *size_out) const;
111127

112128
// Isolate the data to keep Windows-specific types out of this header. Can't
113129
// use the typical pimpl idiom because the implementation of this class also

0 commit comments

Comments
 (0)