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/ADT/Optional.h"
23 #include "llvm/ObjectYAML/yaml2obj.h"
24 #include "llvm/Support/FileSystem.h"
25 #include "llvm/Support/MemoryBuffer.h"
26 #include "llvm/Support/Path.h"
27 #include "llvm/Support/YAMLTraits.h"
28 #include "llvm/Testing/Support/Error.h"
29 #include "gtest/gtest.h"
30 
31 // C includes
32 
33 // C++ includes
34 #include <memory>
35 
36 using namespace lldb_private;
37 using namespace minidump;
38 
39 class MinidumpParserTest : public testing::Test {
40 public:
41   SubsystemRAII<FileSystem> subsystems;
42 
SetUpData(const char * minidump_filename)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 
SetUpFromYaml(llvm::StringRef yaml)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     os.flush();
63     auto data_buffer_sp =
64         std::make_shared<DataBufferHeap>(data.data(), data.size());
65     auto expected_parser = MinidumpParser::Create(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   llvm::Optional<MinidumpParser> parser;
73 };
74 
TEST_F(MinidumpParserTest,InvalidMinidump)75 TEST_F(MinidumpParserTest, InvalidMinidump) {
76   std::string duplicate_streams;
77   llvm::raw_string_ostream os(duplicate_streams);
78   llvm::yaml::Input YIn(R"(
79 --- !minidump
80 Streams:
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       duplicate_streams.data(), duplicate_streams.size());
91   ASSERT_THAT_EXPECTED(MinidumpParser::Create(data_buffer_sp), llvm::Failed());
92 }
93 
TEST_F(MinidumpParserTest,GetThreadsAndGetThreadContext)94 TEST_F(MinidumpParserTest, GetThreadsAndGetThreadContext) {
95   ASSERT_THAT_ERROR(SetUpFromYaml(R"(
96 --- !minidump
97 Streams:
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(thread);
118   EXPECT_EQ(7u, context.size());
119 }
120 
TEST_F(MinidumpParserTest,GetArchitecture)121 TEST_F(MinidumpParserTest, GetArchitecture) {
122   ASSERT_THAT_ERROR(SetUpFromYaml(R"(
123 --- !minidump
124 Streams:
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 
TEST_F(MinidumpParserTest,GetMiscInfo_no_stream)144 TEST_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
149 Streams:
150 ...
151 )"),
152                     llvm::Succeeded());
153   EXPECT_EQ(nullptr, parser->GetMiscInfo());
154 }
155 
TEST_F(MinidumpParserTest,GetLinuxProcStatus)156 TEST_F(MinidumpParserTest, GetLinuxProcStatus) {
157   ASSERT_THAT_ERROR(SetUpFromYaml(R"(
158 --- !minidump
159 Streams:
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   llvm::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 
TEST_F(MinidumpParserTest,GetPid)191 TEST_F(MinidumpParserTest, GetPid) {
192   ASSERT_THAT_ERROR(SetUpFromYaml(R"(
193 --- !minidump
194 Streams:
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   llvm::Optional<lldb::pid_t> pid = parser->GetPid();
221   ASSERT_TRUE(pid.has_value());
222   ASSERT_EQ(16001UL, pid.value());
223 }
224 
TEST_F(MinidumpParserTest,GetFilteredModuleList)225 TEST_F(MinidumpParserTest, GetFilteredModuleList) {
226   ASSERT_THAT_ERROR(SetUpFromYaml(R"(
227 --- !minidump
228 Streams:
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 
TEST_F(MinidumpParserTest,GetExceptionStream)252 TEST_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 
check_mem_range_exists(MinidumpParser & parser,const uint64_t range_start,const uint64_t range_size)260 void check_mem_range_exists(MinidumpParser &parser, const uint64_t range_start,
261                             const uint64_t range_size) {
262   llvm::Optional<minidump::Range> range = parser.FindMemoryRange(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 
TEST_F(MinidumpParserTest,FindMemoryRange)268 TEST_F(MinidumpParserTest, FindMemoryRange) {
269   ASSERT_THAT_ERROR(SetUpFromYaml(R"(
270 --- !minidump
271 Streams:
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(llvm::None, parser->FindMemoryRange(0x00));
282   EXPECT_EQ(llvm::None, parser->FindMemoryRange(0x2a));
283   EXPECT_EQ((minidump::Range{0x401d46, llvm::ArrayRef<uint8_t>{0x54, 0x21}}),
284             parser->FindMemoryRange(0x401d46));
285   EXPECT_EQ(llvm::None, 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(llvm::None, parser->FindMemoryRange(0x7ffceb34a000 + 5));
292 }
293 
TEST_F(MinidumpParserTest,GetMemory)294 TEST_F(MinidumpParserTest, GetMemory) {
295   ASSERT_THAT_ERROR(SetUpFromYaml(R"(
296 --- !minidump
297 Streams:
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 
TEST_F(MinidumpParserTest,FindMemoryRangeWithFullMemoryMinidump)320 TEST_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, 0x10000, 65536); // first range
327   check_mem_range_exists(*parser, 0x40000, 4096);
328   EXPECT_FALSE(parser->FindMemoryRange(0x40000 + 4096).has_value());
329   check_mem_range_exists(*parser, 0x77c12000, 8192);
330   check_mem_range_exists(*parser, 0x7ffe0000, 4096); // last range
331   EXPECT_FALSE(parser->FindMemoryRange(0x7ffe0000 + 4096).has_value());
332 }
333 
334 constexpr auto yes = MemoryRegionInfo::eYes;
335 constexpr auto no = MemoryRegionInfo::eNo;
336 constexpr auto unknown = MemoryRegionInfo::eDontKnow;
337 
TEST_F(MinidumpParserTest,GetMemoryRegionInfo)338 TEST_F(MinidumpParserTest, GetMemoryRegionInfo) {
339   ASSERT_THAT_ERROR(SetUpFromYaml(R"(
340 --- !minidump
341 Streams:
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 
TEST_F(MinidumpParserTest,GetMemoryRegionInfoFromMemoryList)394 TEST_F(MinidumpParserTest, GetMemoryRegionInfoFromMemoryList) {
395   ASSERT_THAT_ERROR(SetUpFromYaml(R"(
396 --- !minidump
397 Streams:
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 
TEST_F(MinidumpParserTest,GetMemoryRegionInfoFromMemory64List)422 TEST_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 
TEST_F(MinidumpParserTest,GetMemoryRegionInfoLinuxMaps)438 TEST_F(MinidumpParserTest, GetMemoryRegionInfoLinuxMaps) {
439   ASSERT_THAT_ERROR(SetUpFromYaml(R"(
440 --- !minidump
441 Streams:
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 
TEST_F(MinidumpParserTest,GetMemoryRegionInfoLinuxMapsError)478 TEST_F(MinidumpParserTest, GetMemoryRegionInfoLinuxMapsError) {
479   ASSERT_THAT_ERROR(SetUpFromYaml(R"(
480 --- !minidump
481 Streams:
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
TEST_F(MinidumpParserTest,GetArchitectureWindows)500 TEST_F(MinidumpParserTest, GetArchitectureWindows) {
501   ASSERT_THAT_ERROR(SetUpFromYaml(R"(
502 --- !minidump
503 Streams:
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 
TEST_F(MinidumpParserTest,GetLinuxProcStatus_no_stream)530 TEST_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
535 Streams:
536 ...
537 )"),
538                     llvm::Succeeded());
539   EXPECT_EQ(llvm::None, parser->GetLinuxProcStatus());
540 }
541 
TEST_F(MinidumpParserTest,GetMiscInfoWindows)542 TEST_F(MinidumpParserTest, GetMiscInfoWindows) {
543   SetUpData("fizzbuzz_no_heap.dmp");
544   const MinidumpMiscInfo *misc_info = parser->GetMiscInfo();
545   ASSERT_NE(nullptr, misc_info);
546   llvm::Optional<lldb::pid_t> pid = misc_info->GetPid();
547   ASSERT_TRUE(pid.has_value());
548   ASSERT_EQ(4440UL, pid.value());
549 }
550 
TEST_F(MinidumpParserTest,GetPidWindows)551 TEST_F(MinidumpParserTest, GetPidWindows) {
552   SetUpData("fizzbuzz_no_heap.dmp");
553   llvm::Optional<lldb::pid_t> pid = parser->GetPid();
554   ASSERT_TRUE(pid.has_value());
555   ASSERT_EQ(4440UL, pid.value());
556 }
557 
558 // wow64
TEST_F(MinidumpParserTest,GetPidWow64)559 TEST_F(MinidumpParserTest, GetPidWow64) {
560   SetUpData("fizzbuzz_wow64.dmp");
561   llvm::Optional<lldb::pid_t> pid = parser->GetPid();
562   ASSERT_TRUE(pid.has_value());
563   ASSERT_EQ(7836UL, pid.value());
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 
TEST_F(MinidumpParserTest,GetThreadContext_x86_32)570 TEST_F(MinidumpParserTest, GetThreadContext_x86_32) {
571   ASSERT_THAT_ERROR(SetUpFromYaml(R"(
572 --- !minidump
573 Streams:
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(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 
TEST_F(MinidumpParserTest,GetThreadContext_x86_64)613 TEST_F(MinidumpParserTest, GetThreadContext_x86_64) {
614   ASSERT_THAT_ERROR(SetUpFromYaml(R"(
615 --- !minidump
616 Streams:
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(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 
TEST_F(MinidumpParserTest,GetThreadContext_x86_32_wow64)660 TEST_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(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 
TEST_F(MinidumpParserTest,MinidumpDuplicateModuleMinAddress)692 TEST_F(MinidumpParserTest, MinidumpDuplicateModuleMinAddress) {
693   ASSERT_THAT_ERROR(SetUpFromYaml(R"(
694 --- !minidump
695 Streams:
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 
TEST_F(MinidumpParserTest,MinidumpDuplicateModuleMappedFirst)717 TEST_F(MinidumpParserTest, MinidumpDuplicateModuleMappedFirst) {
718   ASSERT_THAT_ERROR(SetUpFromYaml(R"(
719 --- !minidump
720 Streams:
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 
TEST_F(MinidumpParserTest,MinidumpDuplicateModuleMappedSecond)757 TEST_F(MinidumpParserTest, MinidumpDuplicateModuleMappedSecond) {
758   ASSERT_THAT_ERROR(SetUpFromYaml(R"(
759 --- !minidump
760 Streams:
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 
TEST_F(MinidumpParserTest,MinidumpDuplicateModuleMappedSecondHigh)798 TEST_F(MinidumpParserTest, MinidumpDuplicateModuleMappedSecondHigh) {
799   ASSERT_THAT_ERROR(SetUpFromYaml(R"(
800 --- !minidump
801 Streams:
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 
TEST_F(MinidumpParserTest,MinidumpDuplicateModuleSeparateCode)839 TEST_F(MinidumpParserTest, MinidumpDuplicateModuleSeparateCode) {
840   ASSERT_THAT_ERROR(SetUpFromYaml(R"(
841 --- !minidump
842 Streams:
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 
TEST_F(MinidumpParserTest,MinidumpModuleOrder)882 TEST_F(MinidumpParserTest, MinidumpModuleOrder) {
883   ASSERT_THAT_ERROR(SetUpFromYaml(R"(
884 --- !minidump
885 Streams:
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