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

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

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