1//===-- MinidumpTypesTest.cpp ---------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "Plugins/Process/minidump/MinidumpParser.h"
10#include "Plugins/Process/minidump/MinidumpTypes.h"
11#include "Plugins/Process/minidump/RegisterContextMinidump_x86_32.h"
12#include "Plugins/Process/minidump/RegisterContextMinidump_x86_64.h"
13#include "TestingSupport/SubsystemRAII.h"
14#include "TestingSupport/TestUtilities.h"
15#include "lldb/Host/FileSystem.h"
16#include "lldb/Target/MemoryRegionInfo.h"
17#include "lldb/Utility/ArchSpec.h"
18#include "lldb/Utility/DataBufferHeap.h"
19#include "lldb/Utility/DataExtractor.h"
20#include "lldb/Utility/FileSpec.h"
21#include "llvm/ADT/ArrayRef.h"
22#include "llvm/ObjectYAML/yaml2obj.h"
23#include "llvm/Support/FileSystem.h"
24#include "llvm/Support/MemoryBuffer.h"
25#include "llvm/Support/Path.h"
26#include "llvm/Support/YAMLTraits.h"
27#include "llvm/Testing/Support/Error.h"
28#include "gtest/gtest.h"
29
30// C includes
31
32// C++ includes
33#include <memory>
34#include <optional>
35
36using namespace lldb_private;
37using namespace minidump;
38
39class MinidumpParserTest : public testing::Test {
40public:
41 SubsystemRAII<FileSystem> subsystems;
42
43 void SetUpData(const char *minidump_filename) {
44 std::string filename = GetInputFilePath(name: minidump_filename);
45 auto BufferPtr = FileSystem::Instance().CreateDataBuffer(path: filename, size: -1, offset: 0);
46 ASSERT_NE(BufferPtr, nullptr);
47 llvm::Expected<MinidumpParser> expected_parser =
48 MinidumpParser::Create(data_buf_sp: BufferPtr);
49 ASSERT_THAT_EXPECTED(expected_parser, llvm::Succeeded());
50 parser = std::move(*expected_parser);
51 ASSERT_GT(parser->GetData().size(), 0UL);
52 }
53
54 llvm::Error SetUpFromYaml(llvm::StringRef yaml) {
55 std::string data;
56 llvm::raw_string_ostream os(data);
57 llvm::yaml::Input YIn(yaml);
58 if (!llvm::yaml::convertYAML(YIn, Out&: os, ErrHandler: [](const llvm::Twine &Msg) {}))
59 return llvm::createStringError(EC: llvm::inconvertibleErrorCode(),
60 Msg: "convertYAML() failed");
61
62 os.flush();
63 auto data_buffer_sp =
64 std::make_shared<DataBufferHeap>(args: data.data(), args: data.size());
65 auto expected_parser = MinidumpParser::Create(data_buf_sp: std::move(data_buffer_sp));
66 if (!expected_parser)
67 return expected_parser.takeError();
68 parser = std::move(*expected_parser);
69 return llvm::Error::success();
70 }
71
72 std::optional<MinidumpParser> parser;
73};
74
75TEST_F(MinidumpParserTest, InvalidMinidump) {
76 std::string duplicate_streams;
77 llvm::raw_string_ostream os(duplicate_streams);
78 llvm::yaml::Input YIn(R"(
79--- !minidump
80Streams:
81 - Type: LinuxAuxv
82 Content: DEADBEEFBAADF00D
83 - Type: LinuxAuxv
84 Content: DEADBEEFBAADF00D
85 )");
86
87 ASSERT_TRUE(llvm::yaml::convertYAML(YIn, os, [](const llvm::Twine &Msg){}));
88 os.flush();
89 auto data_buffer_sp = std::make_shared<DataBufferHeap>(
90 args: duplicate_streams.data(), args: duplicate_streams.size());
91 ASSERT_THAT_EXPECTED(MinidumpParser::Create(data_buffer_sp), llvm::Failed());
92}
93
94TEST_F(MinidumpParserTest, GetThreadsAndGetThreadContext) {
95 ASSERT_THAT_ERROR(SetUpFromYaml(R"(
96--- !minidump
97Streams:
98 - Type: ThreadList
99 Threads:
100 - Thread Id: 0x00003E81
101 Stack:
102 Start of Memory Range: 0x00007FFCEB34A000
103 Content: C84D04BCE97F00
104 Context: 00000000000000
105...
106)"),
107 llvm::Succeeded());
108 llvm::ArrayRef<minidump::Thread> thread_list;
109
110 thread_list = parser->GetThreads();
111 ASSERT_EQ(1UL, thread_list.size());
112
113 const minidump::Thread &thread = thread_list[0];
114
115 EXPECT_EQ(0x3e81u, thread.ThreadId);
116
117 llvm::ArrayRef<uint8_t> context = parser->GetThreadContext(td: thread);
118 EXPECT_EQ(7u, context.size());
119}
120
121TEST_F(MinidumpParserTest, GetArchitecture) {
122 ASSERT_THAT_ERROR(SetUpFromYaml(R"(
123--- !minidump
124Streams:
125 - Type: SystemInfo
126 Processor Arch: AMD64
127 Processor Level: 6
128 Processor Revision: 16130
129 Number of Processors: 1
130 Platform ID: Linux
131 CPU:
132 Vendor ID: GenuineIntel
133 Version Info: 0x00000000
134 Feature Info: 0x00000000
135...
136)"),
137 llvm::Succeeded());
138 ASSERT_EQ(llvm::Triple::ArchType::x86_64,
139 parser->GetArchitecture().GetMachine());
140 ASSERT_EQ(llvm::Triple::OSType::Linux,
141 parser->GetArchitecture().GetTriple().getOS());
142}
143
144TEST_F(MinidumpParserTest, GetMiscInfo_no_stream) {
145 // Test that GetMiscInfo returns nullptr when the minidump does not contain
146 // this stream.
147 ASSERT_THAT_ERROR(SetUpFromYaml(R"(
148--- !minidump
149Streams:
150...
151)"),
152 llvm::Succeeded());
153 EXPECT_EQ(nullptr, parser->GetMiscInfo());
154}
155
156TEST_F(MinidumpParserTest, GetLinuxProcStatus) {
157 ASSERT_THAT_ERROR(SetUpFromYaml(R"(
158--- !minidump
159Streams:
160 - Type: SystemInfo
161 Processor Arch: AMD64
162 Processor Level: 6
163 Processor Revision: 16130
164 Number of Processors: 1
165 Platform ID: Linux
166 CSD Version: 'Linux 3.13.0-91-generic'
167 CPU:
168 Vendor ID: GenuineIntel
169 Version Info: 0x00000000
170 Feature Info: 0x00000000
171 - Type: LinuxProcStatus
172 Text: |
173 Name: a.out
174 State: t (tracing stop)
175 Tgid: 16001
176 Ngid: 0
177 Pid: 16001
178 PPid: 13243
179 TracerPid: 16002
180 Uid: 404696 404696 404696 404696
181 Gid: 5762 5762 5762 5762
182...
183)"),
184 llvm::Succeeded());
185 std::optional<LinuxProcStatus> proc_status = parser->GetLinuxProcStatus();
186 ASSERT_TRUE(proc_status.has_value());
187 lldb::pid_t pid = proc_status->GetPid();
188 ASSERT_EQ(16001UL, pid);
189}
190
191TEST_F(MinidumpParserTest, GetPid) {
192 ASSERT_THAT_ERROR(SetUpFromYaml(R"(
193--- !minidump
194Streams:
195 - Type: SystemInfo
196 Processor Arch: AMD64
197 Processor Level: 6
198 Processor Revision: 16130
199 Number of Processors: 1
200 Platform ID: Linux
201 CSD Version: 'Linux 3.13.0-91-generic'
202 CPU:
203 Vendor ID: GenuineIntel
204 Version Info: 0x00000000
205 Feature Info: 0x00000000
206 - Type: LinuxProcStatus
207 Text: |
208 Name: a.out
209 State: t (tracing stop)
210 Tgid: 16001
211 Ngid: 0
212 Pid: 16001
213 PPid: 13243
214 TracerPid: 16002
215 Uid: 404696 404696 404696 404696
216 Gid: 5762 5762 5762 5762
217...
218)"),
219 llvm::Succeeded());
220 std::optional<lldb::pid_t> pid = parser->GetPid();
221 ASSERT_TRUE(pid.has_value());
222 ASSERT_EQ(16001UL, *pid);
223}
224
225TEST_F(MinidumpParserTest, GetFilteredModuleList) {
226 ASSERT_THAT_ERROR(SetUpFromYaml(R"(
227--- !minidump
228Streams:
229 - Type: ModuleList
230 Modules:
231 - Base of Image: 0x0000000000400000
232 Size of Image: 0x00001000
233 Module Name: '/tmp/test/linux-x86_64_not_crashed'
234 CodeView Record: 4C4570426CCF3F60FFA7CC4B86AE8FF44DB2576A68983611
235 - Base of Image: 0x0000000000600000
236 Size of Image: 0x00002000
237 Module Name: '/tmp/test/linux-x86_64_not_crashed'
238 CodeView Record: 4C4570426CCF3F60FFA7CC4B86AE8FF44DB2576A68983611
239...
240)"),
241 llvm::Succeeded());
242 llvm::ArrayRef<minidump::Module> modules = parser->GetModuleList();
243 std::vector<const minidump::Module *> filtered_modules =
244 parser->GetFilteredModuleList();
245 EXPECT_EQ(2u, modules.size());
246 ASSERT_EQ(1u, filtered_modules.size());
247 const minidump::Module &M = *filtered_modules[0];
248 EXPECT_THAT_EXPECTED(parser->GetMinidumpFile().getString(M.ModuleNameRVA),
249 llvm::HasValue("/tmp/test/linux-x86_64_not_crashed"));
250}
251
252TEST_F(MinidumpParserTest, GetExceptionStream) {
253 SetUpData("linux-x86_64.dmp");
254 const llvm::minidump::ExceptionStream *exception_stream =
255 parser->GetExceptionStream();
256 ASSERT_NE(nullptr, exception_stream);
257 ASSERT_EQ(11UL, exception_stream->ExceptionRecord.ExceptionCode);
258}
259
260void check_mem_range_exists(MinidumpParser &parser, const uint64_t range_start,
261 const uint64_t range_size) {
262 std::optional<minidump::Range> range = parser.FindMemoryRange(addr: range_start);
263 ASSERT_TRUE(range.has_value()) << "There is no range containing this address";
264 EXPECT_EQ(range_start, range->start);
265 EXPECT_EQ(range_start + range_size, range->start + range->range_ref.size());
266}
267
268TEST_F(MinidumpParserTest, FindMemoryRange) {
269 ASSERT_THAT_ERROR(SetUpFromYaml(R"(
270--- !minidump
271Streams:
272 - Type: MemoryList
273 Memory Ranges:
274 - Start of Memory Range: 0x00007FFCEB34A000
275 Content: C84D04BCE9
276 - Start of Memory Range: 0x0000000000401D46
277 Content: 5421
278...
279)"),
280 llvm::Succeeded());
281 EXPECT_EQ(std::nullopt, parser->FindMemoryRange(0x00));
282 EXPECT_EQ(std::nullopt, parser->FindMemoryRange(0x2a));
283 EXPECT_EQ((minidump::Range{0x401d46, llvm::ArrayRef<uint8_t>{0x54, 0x21}}),
284 parser->FindMemoryRange(0x401d46));
285 EXPECT_EQ(std::nullopt, parser->FindMemoryRange(0x401d46 + 2));
286
287 EXPECT_EQ(
288 (minidump::Range{0x7ffceb34a000,
289 llvm::ArrayRef<uint8_t>{0xc8, 0x4d, 0x04, 0xbc, 0xe9}}),
290 parser->FindMemoryRange(0x7ffceb34a000 + 2));
291 EXPECT_EQ(std::nullopt, parser->FindMemoryRange(0x7ffceb34a000 + 5));
292}
293
294TEST_F(MinidumpParserTest, GetMemory) {
295 ASSERT_THAT_ERROR(SetUpFromYaml(R"(
296--- !minidump
297Streams:
298 - Type: MemoryList
299 Memory Ranges:
300 - Start of Memory Range: 0x00007FFCEB34A000
301 Content: C84D04BCE9
302 - Start of Memory Range: 0x0000000000401D46
303 Content: 5421
304...
305)"),
306 llvm::Succeeded());
307
308 EXPECT_EQ((llvm::ArrayRef<uint8_t>{0x54}), parser->GetMemory(0x401d46, 1));
309 EXPECT_EQ((llvm::ArrayRef<uint8_t>{0x54, 0x21}),
310 parser->GetMemory(0x401d46, 4));
311
312 EXPECT_EQ((llvm::ArrayRef<uint8_t>{0xc8, 0x4d, 0x04, 0xbc, 0xe9}),
313 parser->GetMemory(0x7ffceb34a000, 5));
314 EXPECT_EQ((llvm::ArrayRef<uint8_t>{0xc8, 0x4d, 0x04}),
315 parser->GetMemory(0x7ffceb34a000, 3));
316
317 EXPECT_EQ(llvm::ArrayRef<uint8_t>(), parser->GetMemory(0x500000, 512));
318}
319
320TEST_F(MinidumpParserTest, FindMemoryRangeWithFullMemoryMinidump) {
321 SetUpData("fizzbuzz_wow64.dmp");
322
323 // There are a lot of ranges in the file, just testing with some of them
324 EXPECT_FALSE(parser->FindMemoryRange(0x00).has_value());
325 EXPECT_FALSE(parser->FindMemoryRange(0x2a).has_value());
326 check_mem_range_exists(parser&: *parser, range_start: 0x10000, range_size: 65536); // first range
327 check_mem_range_exists(parser&: *parser, range_start: 0x40000, range_size: 4096);
328 EXPECT_FALSE(parser->FindMemoryRange(0x40000 + 4096).has_value());
329 check_mem_range_exists(parser&: *parser, range_start: 0x77c12000, range_size: 8192);
330 check_mem_range_exists(parser&: *parser, range_start: 0x7ffe0000, range_size: 4096); // last range
331 EXPECT_FALSE(parser->FindMemoryRange(0x7ffe0000 + 4096).has_value());
332}
333
334constexpr auto yes = MemoryRegionInfo::eYes;
335constexpr auto no = MemoryRegionInfo::eNo;
336constexpr auto unknown = MemoryRegionInfo::eDontKnow;
337
338TEST_F(MinidumpParserTest, GetMemoryRegionInfo) {
339 ASSERT_THAT_ERROR(SetUpFromYaml(R"(
340--- !minidump
341Streams:
342 - Type: MemoryInfoList
343 Memory Ranges:
344 - Base Address: 0x0000000000000000
345 Allocation Protect: [ ]
346 Region Size: 0x0000000000010000
347 State: [ MEM_FREE ]
348 Protect: [ PAGE_NO_ACCESS ]
349 Type: [ ]
350 - Base Address: 0x0000000000010000
351 Allocation Protect: [ PAGE_READ_WRITE ]
352 Region Size: 0x0000000000021000
353 State: [ MEM_COMMIT ]
354 Type: [ MEM_MAPPED ]
355 - Base Address: 0x0000000000040000
356 Allocation Protect: [ PAGE_EXECUTE_WRITE_COPY ]
357 Region Size: 0x0000000000001000
358 State: [ MEM_COMMIT ]
359 Protect: [ PAGE_READ_ONLY ]
360 Type: [ MEM_IMAGE ]
361 - Base Address: 0x000000007FFE0000
362 Allocation Protect: [ PAGE_READ_ONLY ]
363 Region Size: 0x0000000000001000
364 State: [ MEM_COMMIT ]
365 Type: [ MEM_PRIVATE ]
366 - Base Address: 0x000000007FFE1000
367 Allocation Base: 0x000000007FFE0000
368 Allocation Protect: [ PAGE_READ_ONLY ]
369 Region Size: 0x000000000000F000
370 State: [ MEM_RESERVE ]
371 Protect: [ PAGE_NO_ACCESS ]
372 Type: [ MEM_PRIVATE ]
373...
374)"),
375 llvm::Succeeded());
376
377 EXPECT_THAT(
378 parser->BuildMemoryRegions(),
379 testing::Pair(
380 testing::ElementsAre(
381 MemoryRegionInfo({0x0, 0x10000}, no, no, no, unknown, no, ConstString(),
382 unknown, 0, unknown, unknown),
383 MemoryRegionInfo({0x10000, 0x21000}, yes, yes, no, unknown, yes,
384 ConstString(), unknown, 0, unknown, unknown),
385 MemoryRegionInfo({0x40000, 0x1000}, yes, no, no, unknown, yes,
386 ConstString(), unknown, 0, unknown, unknown),
387 MemoryRegionInfo({0x7ffe0000, 0x1000}, yes, no, no, unknown, yes,
388 ConstString(), unknown, 0, unknown, unknown),
389 MemoryRegionInfo({0x7ffe1000, 0xf000}, no, no, no, unknown, yes,
390 ConstString(), unknown, 0, unknown, unknown)),
391 true));
392}
393
394TEST_F(MinidumpParserTest, GetMemoryRegionInfoFromMemoryList) {
395 ASSERT_THAT_ERROR(SetUpFromYaml(R"(
396--- !minidump
397Streams:
398 - Type: MemoryList
399 Memory Ranges:
400 - Start of Memory Range: 0x0000000000001000
401 Content: '31313131313131313131313131313131'
402 - Start of Memory Range: 0x0000000000002000
403 Content: '3333333333333333333333333333333333333333333333333333333333333333'
404...
405)"),
406 llvm::Succeeded());
407
408 // Test we can get memory regions from the MINIDUMP_MEMORY_LIST stream when
409 // we don't have a MemoryInfoListStream.
410
411 EXPECT_THAT(
412 parser->BuildMemoryRegions(),
413 testing::Pair(
414 testing::ElementsAre(
415 MemoryRegionInfo({0x1000, 0x10}, yes, unknown, unknown, unknown, yes,
416 ConstString(), unknown, 0, unknown, unknown),
417 MemoryRegionInfo({0x2000, 0x20}, yes, unknown, unknown, unknown, yes,
418 ConstString(), unknown, 0, unknown, unknown)),
419 false));
420}
421
422TEST_F(MinidumpParserTest, GetMemoryRegionInfoFromMemory64List) {
423 SetUpData("regions-memlist64.dmp");
424
425 // Test we can get memory regions from the MINIDUMP_MEMORY64_LIST stream when
426 // we don't have a MemoryInfoListStream.
427 EXPECT_THAT(
428 parser->BuildMemoryRegions(),
429 testing::Pair(
430 testing::ElementsAre(
431 MemoryRegionInfo({0x1000, 0x10}, yes, unknown, unknown, unknown, yes,
432 ConstString(), unknown, 0, unknown, unknown),
433 MemoryRegionInfo({0x2000, 0x20}, yes, unknown, unknown, unknown, yes,
434 ConstString(), unknown, 0, unknown, unknown)),
435 false));
436}
437
438TEST_F(MinidumpParserTest, GetMemoryRegionInfoLinuxMaps) {
439 ASSERT_THAT_ERROR(SetUpFromYaml(R"(
440--- !minidump
441Streams:
442 - Type: LinuxMaps
443 Text: |
444 400d9000-400db000 r-xp 00000000 b3:04 227 /system/bin/app_process
445 400db000-400dc000 r--p 00001000 b3:04 227 /system/bin/app_process
446 400dc000-400dd000 rw-p 00000000 00:00 0
447 400ec000-400ed000 r--p 00000000 00:00 0
448 400ee000-400ef000 rw-p 00010000 b3:04 300 /system/bin/linker
449 400fc000-400fd000 rwxp 00001000 b3:04 1096 /system/lib/liblog.so
450
451...
452)"),
453 llvm::Succeeded());
454 // Test we can get memory regions from the linux /proc/<pid>/maps stream when
455 // we don't have a MemoryInfoListStream.
456 ConstString app_process("/system/bin/app_process");
457 ConstString linker("/system/bin/linker");
458 ConstString liblog("/system/lib/liblog.so");
459 EXPECT_THAT(
460 parser->BuildMemoryRegions(),
461 testing::Pair(
462 testing::ElementsAre(
463 MemoryRegionInfo({0x400d9000, 0x2000}, yes, no, yes, no, yes,
464 app_process, unknown, 0, unknown, unknown),
465 MemoryRegionInfo({0x400db000, 0x1000}, yes, no, no, no, yes,
466 app_process, unknown, 0, unknown, unknown),
467 MemoryRegionInfo({0x400dc000, 0x1000}, yes, yes, no, no, yes,
468 ConstString(), unknown, 0, unknown, unknown),
469 MemoryRegionInfo({0x400ec000, 0x1000}, yes, no, no, no, yes,
470 ConstString(), unknown, 0, unknown, unknown),
471 MemoryRegionInfo({0x400ee000, 0x1000}, yes, yes, no, no, yes, linker,
472 unknown, 0, unknown, unknown),
473 MemoryRegionInfo({0x400fc000, 0x1000}, yes, yes, yes, no, yes, liblog,
474 unknown, 0, unknown, unknown)),
475 true));
476}
477
478TEST_F(MinidumpParserTest, GetMemoryRegionInfoLinuxMapsError) {
479 ASSERT_THAT_ERROR(SetUpFromYaml(R"(
480--- !minidump
481Streams:
482 - Type: LinuxMaps
483 Text: |
484 400d9000-400db000 r?xp 00000000 b3:04 227
485 400fc000-400fd000 rwxp 00001000 b3:04 1096
486...
487)"),
488 llvm::Succeeded());
489 // Test that when a /proc/maps region fails to parse
490 // we handle the error and continue with the rest.
491 EXPECT_THAT(
492 parser->BuildMemoryRegions(),
493 testing::Pair(testing::ElementsAre(MemoryRegionInfo(
494 {0x400fc000, 0x1000}, yes, yes, yes, no, yes,
495 ConstString(nullptr), unknown, 0, unknown, unknown)),
496 true));
497}
498
499// Windows Minidump tests
500TEST_F(MinidumpParserTest, GetArchitectureWindows) {
501 ASSERT_THAT_ERROR(SetUpFromYaml(R"(
502--- !minidump
503Streams:
504 - Type: SystemInfo
505 Processor Arch: X86
506 Processor Level: 6
507 Processor Revision: 15876
508 Number of Processors: 32
509 Product type: 1
510 Major Version: 6
511 Minor Version: 1
512 Build Number: 7601
513 Platform ID: Win32NT
514 CSD Version: Service Pack 1
515 Suite Mask: 0x0100
516 CPU:
517 Vendor ID: GenuineIntel
518 Version Info: 0x000306E4
519 Feature Info: 0xBFEBFBFF
520 AMD Extended Features: 0x771EEC80
521...
522)"),
523 llvm::Succeeded());
524 ASSERT_EQ(llvm::Triple::ArchType::x86,
525 parser->GetArchitecture().GetMachine());
526 ASSERT_EQ(llvm::Triple::OSType::Win32,
527 parser->GetArchitecture().GetTriple().getOS());
528}
529
530TEST_F(MinidumpParserTest, GetLinuxProcStatus_no_stream) {
531 // Test that GetLinuxProcStatus returns nullptr when the minidump does not
532 // contain this stream.
533 ASSERT_THAT_ERROR(SetUpFromYaml(R"(
534--- !minidump
535Streams:
536...
537)"),
538 llvm::Succeeded());
539 EXPECT_EQ(std::nullopt, parser->GetLinuxProcStatus());
540}
541
542TEST_F(MinidumpParserTest, GetMiscInfoWindows) {
543 SetUpData("fizzbuzz_no_heap.dmp");
544 const MinidumpMiscInfo *misc_info = parser->GetMiscInfo();
545 ASSERT_NE(nullptr, misc_info);
546 std::optional<lldb::pid_t> pid = misc_info->GetPid();
547 ASSERT_TRUE(pid.has_value());
548 ASSERT_EQ(4440UL, *pid);
549}
550
551TEST_F(MinidumpParserTest, GetPidWindows) {
552 SetUpData("fizzbuzz_no_heap.dmp");
553 std::optional<lldb::pid_t> pid = parser->GetPid();
554 ASSERT_TRUE(pid.has_value());
555 ASSERT_EQ(4440UL, *pid);
556}
557
558// wow64
559TEST_F(MinidumpParserTest, GetPidWow64) {
560 SetUpData("fizzbuzz_wow64.dmp");
561 std::optional<lldb::pid_t> pid = parser->GetPid();
562 ASSERT_TRUE(pid.has_value());
563 ASSERT_EQ(7836UL, *pid);
564}
565
566// Register tests
567#define REG_VAL32(x) *(reinterpret_cast<uint32_t *>(x))
568#define REG_VAL64(x) *(reinterpret_cast<uint64_t *>(x))
569
570TEST_F(MinidumpParserTest, GetThreadContext_x86_32) {
571 ASSERT_THAT_ERROR(SetUpFromYaml(R"(
572--- !minidump
573Streams:
574 - Type: ThreadList
575 Threads:
576 - Thread Id: 0x00026804
577 Stack:
578 Start of Memory Range: 0x00000000FF9DD000
579 Content: 68D39DFF
580 Context: 0F0001000000000000000000000000000000000000000000000000007F03FFFF0000FFFFFFFFFFFF09DC62F72300000088E36CF72B00FFFF00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000063000000000000002B0000002B000000A88204085CD59DFF008077F7A3D49DFF01000000000000003CD59DFFA082040823000000820201002CD59DFF2B0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
581)"),
582 llvm::Succeeded());
583
584 llvm::ArrayRef<minidump::Thread> thread_list = parser->GetThreads();
585 const minidump::Thread &thread = thread_list[0];
586 llvm::ArrayRef<uint8_t> registers(parser->GetThreadContext(td: thread));
587 const MinidumpContext_x86_32 *context;
588 EXPECT_TRUE(consumeObject(registers, context).Success());
589
590 EXPECT_EQ(MinidumpContext_x86_32_Flags(uint32_t(context->context_flags)),
591 MinidumpContext_x86_32_Flags::x86_32_Flag |
592 MinidumpContext_x86_32_Flags::Full |
593 MinidumpContext_x86_32_Flags::FloatingPoint);
594
595 EXPECT_EQ(0x00000000u, context->eax);
596 EXPECT_EQ(0xf7778000u, context->ebx);
597 EXPECT_EQ(0x00000001u, context->ecx);
598 EXPECT_EQ(0xff9dd4a3u, context->edx);
599 EXPECT_EQ(0x080482a8u, context->edi);
600 EXPECT_EQ(0xff9dd55cu, context->esi);
601 EXPECT_EQ(0xff9dd53cu, context->ebp);
602 EXPECT_EQ(0xff9dd52cu, context->esp);
603 EXPECT_EQ(0x080482a0u, context->eip);
604 EXPECT_EQ(0x00010282u, context->eflags);
605 EXPECT_EQ(0x0023u, context->cs);
606 EXPECT_EQ(0x0000u, context->fs);
607 EXPECT_EQ(0x0063u, context->gs);
608 EXPECT_EQ(0x002bu, context->ss);
609 EXPECT_EQ(0x002bu, context->ds);
610 EXPECT_EQ(0x002bu, context->es);
611}
612
613TEST_F(MinidumpParserTest, GetThreadContext_x86_64) {
614 ASSERT_THAT_ERROR(SetUpFromYaml(R"(
615--- !minidump
616Streams:
617 - Type: ThreadList
618 Threads:
619 - Thread Id: 0x00003E81
620 Stack:
621 Start of Memory Range: 0x00007FFCEB34A000
622 Content: C84D04BCE97F00
623 Context: 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000B0010000000000033000000000000000000000006020100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000010A234EBFC7F000010A234EBFC7F00000000000000000000F09C34EBFC7F0000C0A91ABCE97F00000000000000000000A0163FBCE97F00004602000000000000921C40000000000030A434EBFC7F000000000000000000000000000000000000C61D4000000000007F0300000000000000000000000000000000000000000000801F0000FFFF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FFFF00FFFFFFFFFFFFFF00FFFFFFFF25252525252525252525252525252525000000000000000000000000000000000000000000000000000000000000000000FFFF00FFFFFFFFFFFFFF00FFFFFFFF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FF00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
624...
625)"),
626 llvm::Succeeded());
627 llvm::ArrayRef<minidump::Thread> thread_list = parser->GetThreads();
628 const minidump::Thread &thread = thread_list[0];
629 llvm::ArrayRef<uint8_t> registers(parser->GetThreadContext(td: thread));
630 const MinidumpContext_x86_64 *context;
631 EXPECT_TRUE(consumeObject(registers, context).Success());
632
633 EXPECT_EQ(MinidumpContext_x86_64_Flags(uint32_t(context->context_flags)),
634 MinidumpContext_x86_64_Flags::x86_64_Flag |
635 MinidumpContext_x86_64_Flags::Control |
636 MinidumpContext_x86_64_Flags::FloatingPoint |
637 MinidumpContext_x86_64_Flags::Integer);
638 EXPECT_EQ(0x0000000000000000u, context->rax);
639 EXPECT_EQ(0x0000000000000000u, context->rbx);
640 EXPECT_EQ(0x0000000000000010u, context->rcx);
641 EXPECT_EQ(0x0000000000000000u, context->rdx);
642 EXPECT_EQ(0x00007ffceb349cf0u, context->rdi);
643 EXPECT_EQ(0x0000000000000000u, context->rsi);
644 EXPECT_EQ(0x00007ffceb34a210u, context->rbp);
645 EXPECT_EQ(0x00007ffceb34a210u, context->rsp);
646 EXPECT_EQ(0x00007fe9bc1aa9c0u, context->r8);
647 EXPECT_EQ(0x0000000000000000u, context->r9);
648 EXPECT_EQ(0x00007fe9bc3f16a0u, context->r10);
649 EXPECT_EQ(0x0000000000000246u, context->r11);
650 EXPECT_EQ(0x0000000000401c92u, context->r12);
651 EXPECT_EQ(0x00007ffceb34a430u, context->r13);
652 EXPECT_EQ(0x0000000000000000u, context->r14);
653 EXPECT_EQ(0x0000000000000000u, context->r15);
654 EXPECT_EQ(0x0000000000401dc6u, context->rip);
655 EXPECT_EQ(0x00010206u, context->eflags);
656 EXPECT_EQ(0x0033u, context->cs);
657 EXPECT_EQ(0x0000u, context->ss);
658}
659
660TEST_F(MinidumpParserTest, GetThreadContext_x86_32_wow64) {
661 SetUpData("fizzbuzz_wow64.dmp");
662 llvm::ArrayRef<minidump::Thread> thread_list = parser->GetThreads();
663 const minidump::Thread &thread = thread_list[0];
664 llvm::ArrayRef<uint8_t> registers(parser->GetThreadContextWow64(td: thread));
665 const MinidumpContext_x86_32 *context;
666 EXPECT_TRUE(consumeObject(registers, context).Success());
667
668 EXPECT_EQ(MinidumpContext_x86_32_Flags(uint32_t(context->context_flags)),
669 MinidumpContext_x86_32_Flags::x86_32_Flag |
670 MinidumpContext_x86_32_Flags::Full |
671 MinidumpContext_x86_32_Flags::FloatingPoint |
672 MinidumpContext_x86_32_Flags::ExtendedRegisters);
673
674 EXPECT_EQ(0x00000000u, context->eax);
675 EXPECT_EQ(0x0037f608u, context->ebx);
676 EXPECT_EQ(0x00e61578u, context->ecx);
677 EXPECT_EQ(0x00000008u, context->edx);
678 EXPECT_EQ(0x00000000u, context->edi);
679 EXPECT_EQ(0x00000002u, context->esi);
680 EXPECT_EQ(0x0037f654u, context->ebp);
681 EXPECT_EQ(0x0037f5b8u, context->esp);
682 EXPECT_EQ(0x77ce01fdu, context->eip);
683 EXPECT_EQ(0x00000246u, context->eflags);
684 EXPECT_EQ(0x0023u, context->cs);
685 EXPECT_EQ(0x0053u, context->fs);
686 EXPECT_EQ(0x002bu, context->gs);
687 EXPECT_EQ(0x002bu, context->ss);
688 EXPECT_EQ(0x002bu, context->ds);
689 EXPECT_EQ(0x002bu, context->es);
690}
691
692TEST_F(MinidumpParserTest, MinidumpDuplicateModuleMinAddress) {
693 ASSERT_THAT_ERROR(SetUpFromYaml(R"(
694--- !minidump
695Streams:
696 - Type: ModuleList
697 Modules:
698 - Base of Image: 0x0000000000002000
699 Size of Image: 0x00001000
700 Module Name: '/tmp/a'
701 CodeView Record: ''
702 - Base of Image: 0x0000000000001000
703 Size of Image: 0x00001000
704 Module Name: '/tmp/a'
705 CodeView Record: ''
706...
707)"),
708 llvm::Succeeded());
709 // If we have a module mentioned twice in the module list, the filtered
710 // module list should contain the instance with the lowest BaseOfImage.
711 std::vector<const minidump::Module *> filtered_modules =
712 parser->GetFilteredModuleList();
713 ASSERT_EQ(1u, filtered_modules.size());
714 EXPECT_EQ(0x0000000000001000u, filtered_modules[0]->BaseOfImage);
715}
716
717TEST_F(MinidumpParserTest, MinidumpDuplicateModuleMappedFirst) {
718 ASSERT_THAT_ERROR(SetUpFromYaml(R"(
719--- !minidump
720Streams:
721 - Type: ModuleList
722 Modules:
723 - Base of Image: 0x400d0000
724 Size of Image: 0x00002000
725 Module Name: '/usr/lib/libc.so'
726 CodeView Record: ''
727 - Base of Image: 0x400d3000
728 Size of Image: 0x00001000
729 Module Name: '/usr/lib/libc.so'
730 CodeView Record: ''
731 - Type: LinuxMaps
732 Text: |
733 400d0000-400d2000 r--p 00000000 b3:04 227 /usr/lib/libc.so
734 400d2000-400d3000 rw-p 00000000 00:00 0
735 400d3000-400d4000 r-xp 00010000 b3:04 227 /usr/lib/libc.so
736 400d4000-400d5000 rwxp 00001000 b3:04 227 /usr/lib/libc.so
737...
738)"),
739 llvm::Succeeded());
740 // If we have a module mentioned twice in the module list, and we have full
741 // linux maps for all of the memory regions, make sure we pick the one that
742 // has a consecutive region with a matching path that has executable
743 // permissions. If clients open an object file with mmap, breakpad can create
744 // multiple mappings for a library errnoneously and the lowest address isn't
745 // always the right address. In this case we check the consective memory
746 // regions whose path matches starting at the base of image address and make
747 // sure one of the regions is executable and prefer that one.
748 //
749 // This test will make sure that if the executable is second in the module
750 // list, that it will become the selected module in the filtered list.
751 std::vector<const minidump::Module *> filtered_modules =
752 parser->GetFilteredModuleList();
753 ASSERT_EQ(1u, filtered_modules.size());
754 EXPECT_EQ(0x400d3000u, filtered_modules[0]->BaseOfImage);
755}
756
757TEST_F(MinidumpParserTest, MinidumpDuplicateModuleMappedSecond) {
758 ASSERT_THAT_ERROR(SetUpFromYaml(R"(
759--- !minidump
760Streams:
761 - Type: ModuleList
762 Modules:
763 - Base of Image: 0x400d0000
764 Size of Image: 0x00002000
765 Module Name: '/usr/lib/libc.so'
766 CodeView Record: ''
767 - Base of Image: 0x400d3000
768 Size of Image: 0x00001000
769 Module Name: '/usr/lib/libc.so'
770 CodeView Record: ''
771 - Type: LinuxMaps
772 Text: |
773 400d0000-400d1000 r-xp 00010000 b3:04 227 /usr/lib/libc.so
774 400d1000-400d2000 rwxp 00001000 b3:04 227 /usr/lib/libc.so
775 400d2000-400d3000 rw-p 00000000 00:00 0
776 400d3000-400d5000 r--p 00000000 b3:04 227 /usr/lib/libc.so
777...
778)"),
779 llvm::Succeeded());
780 // If we have a module mentioned twice in the module list, and we have full
781 // linux maps for all of the memory regions, make sure we pick the one that
782 // has a consecutive region with a matching path that has executable
783 // permissions. If clients open an object file with mmap, breakpad can create
784 // multiple mappings for a library errnoneously and the lowest address isn't
785 // always the right address. In this case we check the consective memory
786 // regions whose path matches starting at the base of image address and make
787 // sure one of the regions is executable and prefer that one.
788 //
789 // This test will make sure that if the executable is first in the module
790 // list, that it will remain the correctly selected module in the filtered
791 // list.
792 std::vector<const minidump::Module *> filtered_modules =
793 parser->GetFilteredModuleList();
794 ASSERT_EQ(1u, filtered_modules.size());
795 EXPECT_EQ(0x400d0000u, filtered_modules[0]->BaseOfImage);
796}
797
798TEST_F(MinidumpParserTest, MinidumpDuplicateModuleMappedSecondHigh) {
799 ASSERT_THAT_ERROR(SetUpFromYaml(R"(
800--- !minidump
801Streams:
802 - Type: ModuleList
803 Modules:
804 - Base of Image: 0x400d3000
805 Size of Image: 0x00002000
806 Module Name: '/usr/lib/libc.so'
807 CodeView Record: ''
808 - Base of Image: 0x400d0000
809 Size of Image: 0x00001000
810 Module Name: '/usr/lib/libc.so'
811 CodeView Record: ''
812 - Type: LinuxMaps
813 Text: |
814 400d0000-400d2000 r--p 00000000 b3:04 227 /usr/lib/libc.so
815 400d2000-400d3000 rw-p 00000000 00:00 0
816 400d3000-400d4000 r-xp 00010000 b3:04 227 /usr/lib/libc.so
817 400d4000-400d5000 rwxp 00001000 b3:04 227 /usr/lib/libc.so
818...
819)"),
820 llvm::Succeeded());
821 // If we have a module mentioned twice in the module list, and we have full
822 // linux maps for all of the memory regions, make sure we pick the one that
823 // has a consecutive region with a matching path that has executable
824 // permissions. If clients open an object file with mmap, breakpad can create
825 // multiple mappings for a library errnoneously and the lowest address isn't
826 // always the right address. In this case we check the consective memory
827 // regions whose path matches starting at the base of image address and make
828 // sure one of the regions is executable and prefer that one.
829 //
830 // This test will make sure that if the executable is first in the module
831 // list, that it will remain the correctly selected module in the filtered
832 // list, even if the non-executable module was loaded at a lower base address.
833 std::vector<const minidump::Module *> filtered_modules =
834 parser->GetFilteredModuleList();
835 ASSERT_EQ(1u, filtered_modules.size());
836 EXPECT_EQ(0x400d3000u, filtered_modules[0]->BaseOfImage);
837}
838
839TEST_F(MinidumpParserTest, MinidumpDuplicateModuleSeparateCode) {
840 ASSERT_THAT_ERROR(SetUpFromYaml(R"(
841--- !minidump
842Streams:
843 - Type: ModuleList
844 Modules:
845 - Base of Image: 0x400d0000
846 Size of Image: 0x00002000
847 Module Name: '/usr/lib/libc.so'
848 CodeView Record: ''
849 - Base of Image: 0x400d5000
850 Size of Image: 0x00001000
851 Module Name: '/usr/lib/libc.so'
852 CodeView Record: ''
853 - Type: LinuxMaps
854 Text: |
855 400d0000-400d3000 r--p 00000000 b3:04 227 /usr/lib/libc.so
856 400d3000-400d5000 rw-p 00000000 00:00 0
857 400d5000-400d6000 r--p 00000000 b3:04 227 /usr/lib/libc.so
858 400d6000-400d7000 r-xp 00010000 b3:04 227 /usr/lib/libc.so
859 400d7000-400d8000 rwxp 00001000 b3:04 227 /usr/lib/libc.so
860...
861)"),
862 llvm::Succeeded());
863 // If we have a module mentioned twice in the module list, and we have full
864 // linux maps for all of the memory regions, make sure we pick the one that
865 // has a consecutive region with a matching path that has executable
866 // permissions. If clients open an object file with mmap, breakpad can create
867 // multiple mappings for a library errnoneously and the lowest address isn't
868 // always the right address. In this case we check the consective memory
869 // regions whose path matches starting at the base of image address and make
870 // sure one of the regions is executable and prefer that one.
871 //
872 // This test will make sure if binaries are compiled with "-z separate-code",
873 // where the first region for a binary won't be marked as executable, that
874 // it gets selected by detecting the second consecutive mapping at 0x400d7000
875 // when asked about the a module mamed "/usr/lib/libc.so" at 0x400d5000.
876 std::vector<const minidump::Module *> filtered_modules =
877 parser->GetFilteredModuleList();
878 ASSERT_EQ(1u, filtered_modules.size());
879 EXPECT_EQ(0x400d5000u, filtered_modules[0]->BaseOfImage);
880}
881
882TEST_F(MinidumpParserTest, MinidumpModuleOrder) {
883 ASSERT_THAT_ERROR(SetUpFromYaml(R"(
884--- !minidump
885Streams:
886 - Type: ModuleList
887 Modules:
888 - Base of Image: 0x0000000000002000
889 Size of Image: 0x00001000
890 Module Name: '/tmp/a'
891 CodeView Record: ''
892 - Base of Image: 0x0000000000001000
893 Size of Image: 0x00001000
894 Module Name: '/tmp/b'
895 CodeView Record: ''
896...
897)"),
898 llvm::Succeeded());
899 // Test module filtering does not affect the overall module order. Previous
900 // versions of the MinidumpParser::GetFilteredModuleList() function would sort
901 // all images by address and modify the order of the modules.
902 std::vector<const minidump::Module *> filtered_modules =
903 parser->GetFilteredModuleList();
904 ASSERT_EQ(2u, filtered_modules.size());
905 EXPECT_EQ(0x0000000000002000u, filtered_modules[0]->BaseOfImage);
906 EXPECT_THAT_EXPECTED(
907 parser->GetMinidumpFile().getString(filtered_modules[0]->ModuleNameRVA),
908 llvm::HasValue("/tmp/a"));
909 EXPECT_EQ(0x0000000000001000u, filtered_modules[1]->BaseOfImage);
910 EXPECT_THAT_EXPECTED(
911 parser->GetMinidumpFile().getString(filtered_modules[1]->ModuleNameRVA),
912 llvm::HasValue("/tmp/b"));
913}
914

source code of lldb/unittests/Process/minidump/MinidumpParserTest.cpp