xref: /llvm-project/lldb/unittests/Process/minidump/MinidumpParserTest.cpp (revision b1751faada35e3456b2a3f6b6c9559b5d74d559b)
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 
36 using namespace lldb_private;
37 using namespace minidump;
38 
39 class MinidumpParserTest : public testing::Test {
40 public:
41   SubsystemRAII<FileSystem> subsystems;
42 
43   void SetUpData(const char *minidump_filename) {
44     std::string filename = GetInputFilePath(minidump_filename);
45     auto BufferPtr = FileSystem::Instance().CreateDataBuffer(filename, -1, 0);
46     ASSERT_NE(BufferPtr, nullptr);
47     llvm::Expected<MinidumpParser> expected_parser =
48         MinidumpParser::Create(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, os, [](const llvm::Twine &Msg) {}))
59       return llvm::createStringError(llvm::inconvertibleErrorCode(),
60                                      "convertYAML() failed");
61 
62     auto data_buffer_sp =
63         std::make_shared<DataBufferHeap>(data.data(), data.size());
64     auto expected_parser = MinidumpParser::Create(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 
74 TEST_F(MinidumpParserTest, InvalidMinidump) {
75   std::string duplicate_streams;
76   llvm::raw_string_ostream os(duplicate_streams);
77   llvm::yaml::Input YIn(R"(
78 --- !minidump
79 Streams:
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       duplicate_streams.data(), duplicate_streams.size());
89   ASSERT_THAT_EXPECTED(MinidumpParser::Create(data_buffer_sp), llvm::Failed());
90 }
91 
92 TEST_F(MinidumpParserTest, GetThreadsAndGetThreadContext) {
93   ASSERT_THAT_ERROR(SetUpFromYaml(R"(
94 --- !minidump
95 Streams:
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(thread);
116   EXPECT_EQ(7u, context.size());
117 }
118 
119 TEST_F(MinidumpParserTest, GetArchitecture) {
120   ASSERT_THAT_ERROR(SetUpFromYaml(R"(
121 --- !minidump
122 Streams:
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 
142 TEST_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
147 Streams:
148 ...
149 )"),
150                     llvm::Succeeded());
151   EXPECT_EQ(nullptr, parser->GetMiscInfo());
152 }
153 
154 TEST_F(MinidumpParserTest, GetLinuxProcStatus) {
155   ASSERT_THAT_ERROR(SetUpFromYaml(R"(
156 --- !minidump
157 Streams:
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 
189 TEST_F(MinidumpParserTest, GetPid) {
190   ASSERT_THAT_ERROR(SetUpFromYaml(R"(
191 --- !minidump
192 Streams:
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 
223 TEST_F(MinidumpParserTest, GetFilteredModuleList) {
224   ASSERT_THAT_ERROR(SetUpFromYaml(R"(
225 --- !minidump
226 Streams:
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 
250 TEST_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 
263 void 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(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 
271 TEST_F(MinidumpParserTest, FindMemoryRange) {
272   ASSERT_THAT_ERROR(SetUpFromYaml(R"(
273 --- !minidump
274 Streams:
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 
297 TEST_F(MinidumpParserTest, GetMemory) {
298   ASSERT_THAT_ERROR(SetUpFromYaml(R"(
299 --- !minidump
300 Streams:
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 
323 TEST_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, 0x10000, 65536); // first range
330   check_mem_range_exists(*parser, 0x40000, 4096);
331   EXPECT_FALSE(parser->FindMemoryRange(0x40000 + 4096).has_value());
332   check_mem_range_exists(*parser, 0x77c12000, 8192);
333   check_mem_range_exists(*parser, 0x7ffe0000, 4096); // last range
334   EXPECT_FALSE(parser->FindMemoryRange(0x7ffe0000 + 4096).has_value());
335 }
336 
337 constexpr auto yes = MemoryRegionInfo::eYes;
338 constexpr auto no = MemoryRegionInfo::eNo;
339 constexpr auto unknown = MemoryRegionInfo::eDontKnow;
340 
341 TEST_F(MinidumpParserTest, GetMemoryRegionInfo) {
342   ASSERT_THAT_ERROR(SetUpFromYaml(R"(
343 --- !minidump
344 Streams:
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 
401 TEST_F(MinidumpParserTest, GetMemoryRegionInfoFromMemoryList) {
402   ASSERT_THAT_ERROR(SetUpFromYaml(R"(
403 --- !minidump
404 Streams:
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 
430 TEST_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 
447 TEST_F(MinidumpParserTest, GetMemoryRegionInfoLinuxMaps) {
448   ASSERT_THAT_ERROR(SetUpFromYaml(R"(
449 --- !minidump
450 Streams:
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 
491 TEST_F(MinidumpParserTest, GetMemoryRegionInfoLinuxMapsError) {
492   ASSERT_THAT_ERROR(SetUpFromYaml(R"(
493 --- !minidump
494 Streams:
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
513 TEST_F(MinidumpParserTest, GetArchitectureWindows) {
514   ASSERT_THAT_ERROR(SetUpFromYaml(R"(
515 --- !minidump
516 Streams:
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 
543 TEST_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
548 Streams:
549 ...
550 )"),
551                     llvm::Succeeded());
552   EXPECT_EQ(std::nullopt, parser->GetLinuxProcStatus());
553 }
554 
555 TEST_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 
564 TEST_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
572 TEST_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 
583 TEST_F(MinidumpParserTest, GetThreadContext_x86_32) {
584   ASSERT_THAT_ERROR(SetUpFromYaml(R"(
585 --- !minidump
586 Streams:
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(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 
626 TEST_F(MinidumpParserTest, GetThreadContext_x86_64) {
627   ASSERT_THAT_ERROR(SetUpFromYaml(R"(
628 --- !minidump
629 Streams:
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(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 
673 TEST_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(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 
705 TEST_F(MinidumpParserTest, MinidumpDuplicateModuleMinAddress) {
706   ASSERT_THAT_ERROR(SetUpFromYaml(R"(
707 --- !minidump
708 Streams:
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 
730 TEST_F(MinidumpParserTest, MinidumpDuplicateModuleMappedFirst) {
731   ASSERT_THAT_ERROR(SetUpFromYaml(R"(
732 --- !minidump
733 Streams:
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 
770 TEST_F(MinidumpParserTest, MinidumpDuplicateModuleMappedSecond) {
771   ASSERT_THAT_ERROR(SetUpFromYaml(R"(
772 --- !minidump
773 Streams:
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 
811 TEST_F(MinidumpParserTest, MinidumpDuplicateModuleMappedSecondHigh) {
812   ASSERT_THAT_ERROR(SetUpFromYaml(R"(
813 --- !minidump
814 Streams:
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 
852 TEST_F(MinidumpParserTest, MinidumpDuplicateModuleSeparateCode) {
853   ASSERT_THAT_ERROR(SetUpFromYaml(R"(
854 --- !minidump
855 Streams:
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 
895 TEST_F(MinidumpParserTest, MinidumpModuleOrder) {
896   ASSERT_THAT_ERROR(SetUpFromYaml(R"(
897 --- !minidump
898 Streams:
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