Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 28 additions & 6 deletions lldb/source/Plugins/Process/minidump/MinidumpParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,13 +108,21 @@ MinidumpParser::GetThreadContext(const minidump::Thread &td) {

llvm::ArrayRef<uint8_t>
MinidumpParser::GetThreadContextWow64(const minidump::Thread &td) {
Log *log = GetLog(LLDBLog::Process);
// On Windows, a 32-bit process can run on a 64-bit machine under WOW64. If
// the minidump was captured with a 64-bit debugger, then the CONTEXT we just
// grabbed from the mini_dump_thread is the one for the 64-bit "native"
// process rather than the 32-bit "guest" process we care about. In this
// case, we can get the 32-bit CONTEXT from the TEB (Thread Environment
// Block) of the 64-bit process.
auto teb_mem = GetMemory(td.EnvironmentBlock, sizeof(TEB64));
auto teb_mem_maybe = GetMemory(td.EnvironmentBlock, sizeof(TEB64));
if (!teb_mem_maybe) {
LLDB_LOG_ERROR(log, teb_mem_maybe.takeError(),
"Failed to read Thread Environment Block: {0}");
return {};
}

auto teb_mem = *teb_mem_maybe;
if (teb_mem.empty())
return {};

Expand All @@ -126,8 +134,16 @@ MinidumpParser::GetThreadContextWow64(const minidump::Thread &td) {
// Slot 1 of the thread-local storage in the 64-bit TEB points to a structure
// that includes the 32-bit CONTEXT (after a ULONG). See:
// https://msdn.microsoft.com/en-us/library/ms681670.aspx
auto context =
auto context_maybe =
GetMemory(wow64teb->tls_slots[1] + 4, sizeof(MinidumpContext_x86_32));
if (!context_maybe) {
LLDB_LOG_ERROR(log, context_maybe.takeError(),
"Failed to read WOW Thread Context: {0}");
return {};
}

auto context = *context_maybe;

if (context.size() < sizeof(MinidumpContext_x86_32))
return {};

Expand Down Expand Up @@ -478,11 +494,13 @@ void MinidumpParser::PopulateMemoryRanges() {
m_memory_ranges.Sort();
}

llvm::ArrayRef<uint8_t> MinidumpParser::GetMemory(lldb::addr_t addr,
size_t size) {
llvm::Expected<llvm::ArrayRef<uint8_t>>
MinidumpParser::GetMemory(lldb::addr_t addr, size_t size) {
std::optional<minidump::Range> range = FindMemoryRange(addr);
if (!range)
return {};
return llvm::createStringError(
llvm::inconvertibleErrorCode(),
"No memory range found for address (0x%" PRIx64 ")", addr);

// 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
Expand All @@ -491,7 +509,11 @@ llvm::ArrayRef<uint8_t> MinidumpParser::GetMemory(lldb::addr_t addr,
const size_t offset = addr - range->start;

if (addr < range->start || offset >= range->range_ref.size())
return {};
return llvm::createStringError(
llvm::inconvertibleErrorCode(),
"Address (0x%" PRIx64 ") is not in range [0x%" PRIx64 " - 0x%" PRIx64
")",
addr, range->start, range->start + range->range_ref.size());

const size_t overlap = std::min(size, range->range_ref.size() - offset);
return range->range_ref.slice(offset, overlap);
Expand Down
3 changes: 2 additions & 1 deletion lldb/source/Plugins/Process/minidump/MinidumpParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,8 @@ class MinidumpParser {

std::optional<Range> FindMemoryRange(lldb::addr_t addr);

llvm::ArrayRef<uint8_t> GetMemory(lldb::addr_t addr, size_t size);
llvm::Expected<llvm::ArrayRef<uint8_t>> GetMemory(lldb::addr_t addr,
size_t size);

/// Returns a list of memory regions and a flag indicating whether the list is
/// complete (includes all regions mapped into the process memory).
Expand Down
9 changes: 6 additions & 3 deletions lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -322,12 +322,15 @@ size_t ProcessMinidump::ReadMemory(lldb::addr_t addr, void *buf, size_t size,
size_t ProcessMinidump::DoReadMemory(lldb::addr_t addr, void *buf, size_t size,
Status &error) {

llvm::ArrayRef<uint8_t> mem = m_minidump_parser->GetMemory(addr, size);
if (mem.empty()) {
error = Status::FromErrorString("could not parse memory info");
llvm::Expected<llvm::ArrayRef<uint8_t>> mem_maybe =
m_minidump_parser->GetMemory(addr, size);
if (!mem_maybe) {
error = Status::FromError(mem_maybe.takeError());
return 0;
}

llvm::ArrayRef<uint8_t> mem = *mem_maybe;

std::memcpy(buf, mem.data(), mem.size());
return mem.size();
}
Expand Down
42 changes: 42 additions & 0 deletions lldb/test/Shell/Minidump/missing-memory-region.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Check that looking up a memory region not present in the Minidump fails
# even if it's in the /proc/<pid>/maps file.

# RUN: yaml2obj %s -o %t
# RUN: %lldb -c %t -o "memory read 0x5000" 2>&1 | FileCheck %s

# CHECK-LABEL: (lldb) memory read 0x5000
# CHECK-NEXT: error: No memory range found for address (0x5000)

--- !minidump
Streams:
- Type: SystemInfo
Processor Arch: AMD64
Processor Level: 6
Processor Revision: 15876
Number of Processors: 40
Platform ID: Linux
CSD Version: 'Linux 3.13.0-91-generic #138-Ubuntu SMP Fri Jun 24 17:00:34 UTC 2016 x86_64'
CPU:
Vendor ID: GenuineIntel
Version Info: 0x00000000
Feature Info: 0x00000000
- Type: LinuxProcStatus
Text: |
Name: test-yaml
Umask: 0002
State: t (tracing stop)
Pid: 8567
- Type: LinuxMaps
Text: |
0x1000-0x1100 r-xp 00000000 00:00 0
0x2000-0x2200 rw-p 00000000 00:00 0
0x4000-0x6000 rw-- 00000000 00:00 0
- Type: Memory64List
Memory Ranges:
- Start of Memory Range: 0x1000
Data Size: 0x100
Content : ''
- Start of Memory Range: 0x2000
Data Size: 0x200
Content : ''
...
23 changes: 13 additions & 10 deletions lldb/unittests/Process/minidump/MinidumpParserTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -308,16 +308,19 @@ TEST_F(MinidumpParserTest, GetMemory) {
)"),
llvm::Succeeded());

EXPECT_EQ((llvm::ArrayRef<uint8_t>{0x54}), parser->GetMemory(0x401d46, 1));
EXPECT_EQ((llvm::ArrayRef<uint8_t>{0x54, 0x21}),
parser->GetMemory(0x401d46, 4));

EXPECT_EQ((llvm::ArrayRef<uint8_t>{0xc8, 0x4d, 0x04, 0xbc, 0xe9}),
parser->GetMemory(0x7ffceb34a000, 5));
EXPECT_EQ((llvm::ArrayRef<uint8_t>{0xc8, 0x4d, 0x04}),
parser->GetMemory(0x7ffceb34a000, 3));

EXPECT_EQ(llvm::ArrayRef<uint8_t>(), parser->GetMemory(0x500000, 512));
EXPECT_THAT_EXPECTED(parser->GetMemory(0x401d46, 1),
llvm::HasValue(llvm::ArrayRef<uint8_t>{0x54}));
EXPECT_THAT_EXPECTED(parser->GetMemory(0x401d46, 4),
llvm::HasValue(llvm::ArrayRef<uint8_t>{0x54, 0x21}));
EXPECT_THAT_EXPECTED(
parser->GetMemory(0x7ffceb34a000, 5),
llvm::HasValue(llvm::ArrayRef<uint8_t>{0xc8, 0x4d, 0x04, 0xbc, 0xe9}));
EXPECT_THAT_EXPECTED(
parser->GetMemory(0x7ffceb34a000, 3),
llvm::HasValue(llvm::ArrayRef<uint8_t>{0xc8, 0x4d, 0x04}));
EXPECT_THAT_EXPECTED(
parser->GetMemory(0x500000, 512),
llvm::FailedWithMessage("No memory range found for address (0x500000)"));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: maybe we can also add a test for the "Address xxx is not in range xxx" error case?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure how plausible this'll be. That's mostly a safety check.

  const size_t offset = addr - range->start;

Ideally we'll never return an entry unless it's in the range. (Not sure if we even need the check anymore)

}

TEST_F(MinidumpParserTest, FindMemoryRangeWithFullMemoryMinidump) {
Expand Down
Loading