Skip to content

Commit a6fb3b3

Browse files
authored
[LLDB] Process minidump better error messages (#149206)
Prior, Process Minidump would return ``` Status::FromErrorString("could not parse memory info"); ``` For any unsuccessful memory read, with no differentiation between an error in LLDB and the data simply not being present. This lead to a lot of user confusion and overall pretty terrible user experience. To fix this I've refactored the APIs so we can pass an error back in an llvm expected. There were also no shell tests for memory read and process Minidump so I added one.
1 parent 011d38b commit a6fb3b3

File tree

5 files changed

+91
-20
lines changed

5 files changed

+91
-20
lines changed

lldb/source/Plugins/Process/minidump/MinidumpParser.cpp

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -108,13 +108,21 @@ MinidumpParser::GetThreadContext(const minidump::Thread &td) {
108108

109109
llvm::ArrayRef<uint8_t>
110110
MinidumpParser::GetThreadContextWow64(const minidump::Thread &td) {
111+
Log *log = GetLog(LLDBLog::Process);
111112
// On Windows, a 32-bit process can run on a 64-bit machine under WOW64. If
112113
// the minidump was captured with a 64-bit debugger, then the CONTEXT we just
113114
// grabbed from the mini_dump_thread is the one for the 64-bit "native"
114115
// process rather than the 32-bit "guest" process we care about. In this
115116
// case, we can get the 32-bit CONTEXT from the TEB (Thread Environment
116117
// Block) of the 64-bit process.
117-
auto teb_mem = GetMemory(td.EnvironmentBlock, sizeof(TEB64));
118+
auto teb_mem_maybe = GetMemory(td.EnvironmentBlock, sizeof(TEB64));
119+
if (!teb_mem_maybe) {
120+
LLDB_LOG_ERROR(log, teb_mem_maybe.takeError(),
121+
"Failed to read Thread Environment Block: {0}");
122+
return {};
123+
}
124+
125+
auto teb_mem = *teb_mem_maybe;
118126
if (teb_mem.empty())
119127
return {};
120128

@@ -126,8 +134,16 @@ MinidumpParser::GetThreadContextWow64(const minidump::Thread &td) {
126134
// Slot 1 of the thread-local storage in the 64-bit TEB points to a structure
127135
// that includes the 32-bit CONTEXT (after a ULONG). See:
128136
// https://msdn.microsoft.com/en-us/library/ms681670.aspx
129-
auto context =
137+
auto context_maybe =
130138
GetMemory(wow64teb->tls_slots[1] + 4, sizeof(MinidumpContext_x86_32));
139+
if (!context_maybe) {
140+
LLDB_LOG_ERROR(log, context_maybe.takeError(),
141+
"Failed to read WOW Thread Context: {0}");
142+
return {};
143+
}
144+
145+
auto context = *context_maybe;
146+
131147
if (context.size() < sizeof(MinidumpContext_x86_32))
132148
return {};
133149

@@ -478,11 +494,13 @@ void MinidumpParser::PopulateMemoryRanges() {
478494
m_memory_ranges.Sort();
479495
}
480496

481-
llvm::ArrayRef<uint8_t> MinidumpParser::GetMemory(lldb::addr_t addr,
482-
size_t size) {
497+
llvm::Expected<llvm::ArrayRef<uint8_t>>
498+
MinidumpParser::GetMemory(lldb::addr_t addr, size_t size) {
483499
std::optional<minidump::Range> range = FindMemoryRange(addr);
484500
if (!range)
485-
return {};
501+
return llvm::createStringError(
502+
llvm::inconvertibleErrorCode(),
503+
"No memory range found for address (0x%" PRIx64 ")", addr);
486504

487505
// There's at least some overlap between the beginning of the desired range
488506
// (addr) and the current range. Figure out where the overlap begins and
@@ -491,7 +509,11 @@ llvm::ArrayRef<uint8_t> MinidumpParser::GetMemory(lldb::addr_t addr,
491509
const size_t offset = addr - range->start;
492510

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

496518
const size_t overlap = std::min(size, range->range_ref.size() - offset);
497519
return range->range_ref.slice(offset, overlap);

lldb/source/Plugins/Process/minidump/MinidumpParser.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,8 @@ class MinidumpParser {
104104

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

107-
llvm::ArrayRef<uint8_t> GetMemory(lldb::addr_t addr, size_t size);
107+
llvm::Expected<llvm::ArrayRef<uint8_t>> GetMemory(lldb::addr_t addr,
108+
size_t size);
108109

109110
/// Returns a list of memory regions and a flag indicating whether the list is
110111
/// complete (includes all regions mapped into the process memory).

lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -322,12 +322,15 @@ size_t ProcessMinidump::ReadMemory(lldb::addr_t addr, void *buf, size_t size,
322322
size_t ProcessMinidump::DoReadMemory(lldb::addr_t addr, void *buf, size_t size,
323323
Status &error) {
324324

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

332+
llvm::ArrayRef<uint8_t> mem = *mem_maybe;
333+
331334
std::memcpy(buf, mem.data(), mem.size());
332335
return mem.size();
333336
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Check that looking up a memory region not present in the Minidump fails
2+
# even if it's in the /proc/<pid>/maps file.
3+
4+
# RUN: yaml2obj %s -o %t
5+
# RUN: %lldb -c %t -o "memory read 0x5000" 2>&1 | FileCheck %s
6+
7+
# CHECK-LABEL: (lldb) memory read 0x5000
8+
# CHECK-NEXT: error: No memory range found for address (0x5000)
9+
10+
--- !minidump
11+
Streams:
12+
- Type: SystemInfo
13+
Processor Arch: AMD64
14+
Processor Level: 6
15+
Processor Revision: 15876
16+
Number of Processors: 40
17+
Platform ID: Linux
18+
CSD Version: 'Linux 3.13.0-91-generic #138-Ubuntu SMP Fri Jun 24 17:00:34 UTC 2016 x86_64'
19+
CPU:
20+
Vendor ID: GenuineIntel
21+
Version Info: 0x00000000
22+
Feature Info: 0x00000000
23+
- Type: LinuxProcStatus
24+
Text: |
25+
Name: test-yaml
26+
Umask: 0002
27+
State: t (tracing stop)
28+
Pid: 8567
29+
- Type: LinuxMaps
30+
Text: |
31+
0x1000-0x1100 r-xp 00000000 00:00 0
32+
0x2000-0x2200 rw-p 00000000 00:00 0
33+
0x4000-0x6000 rw-- 00000000 00:00 0
34+
- Type: Memory64List
35+
Memory Ranges:
36+
- Start of Memory Range: 0x1000
37+
Data Size: 0x100
38+
Content : ''
39+
- Start of Memory Range: 0x2000
40+
Data Size: 0x200
41+
Content : ''
42+
...

lldb/unittests/Process/minidump/MinidumpParserTest.cpp

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -308,16 +308,19 @@ TEST_F(MinidumpParserTest, GetMemory) {
308308
)"),
309309
llvm::Succeeded());
310310

311-
EXPECT_EQ((llvm::ArrayRef<uint8_t>{0x54}), parser->GetMemory(0x401d46, 1));
312-
EXPECT_EQ((llvm::ArrayRef<uint8_t>{0x54, 0x21}),
313-
parser->GetMemory(0x401d46, 4));
314-
315-
EXPECT_EQ((llvm::ArrayRef<uint8_t>{0xc8, 0x4d, 0x04, 0xbc, 0xe9}),
316-
parser->GetMemory(0x7ffceb34a000, 5));
317-
EXPECT_EQ((llvm::ArrayRef<uint8_t>{0xc8, 0x4d, 0x04}),
318-
parser->GetMemory(0x7ffceb34a000, 3));
319-
320-
EXPECT_EQ(llvm::ArrayRef<uint8_t>(), parser->GetMemory(0x500000, 512));
311+
EXPECT_THAT_EXPECTED(parser->GetMemory(0x401d46, 1),
312+
llvm::HasValue(llvm::ArrayRef<uint8_t>{0x54}));
313+
EXPECT_THAT_EXPECTED(parser->GetMemory(0x401d46, 4),
314+
llvm::HasValue(llvm::ArrayRef<uint8_t>{0x54, 0x21}));
315+
EXPECT_THAT_EXPECTED(
316+
parser->GetMemory(0x7ffceb34a000, 5),
317+
llvm::HasValue(llvm::ArrayRef<uint8_t>{0xc8, 0x4d, 0x04, 0xbc, 0xe9}));
318+
EXPECT_THAT_EXPECTED(
319+
parser->GetMemory(0x7ffceb34a000, 3),
320+
llvm::HasValue(llvm::ArrayRef<uint8_t>{0xc8, 0x4d, 0x04}));
321+
EXPECT_THAT_EXPECTED(
322+
parser->GetMemory(0x500000, 512),
323+
llvm::FailedWithMessage("No memory range found for address (0x500000)"));
321324
}
322325

323326
TEST_F(MinidumpParserTest, FindMemoryRangeWithFullMemoryMinidump) {

0 commit comments

Comments
 (0)