Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
31 changes: 25 additions & 6 deletions lldb/source/Plugins/Process/minidump/MinidumpParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,13 @@ MinidumpParser::GetThreadContextWow64(const minidump::Thread &td) {
// 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) {
llvm::consumeError(teb_mem_maybe.takeError());
Copy link
Member

Choose a reason for hiding this comment

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

Should we use LLDB_LOG_ERROR here? Same question below.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I personally don't have a lot of context on if this should be an error (WOW even when I was at MSFT wasn't a common talking point). But I'm going to make the change

return {};
}

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

Expand All @@ -126,8 +132,15 @@ 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) {
llvm::consumeError(context_maybe.takeError());
return {};
}

auto context = *context_maybe;

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

Expand Down Expand Up @@ -478,11 +491,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 +506,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