[NFC]Update -fsplit-machine-functions now aarch64 function splitting is supported...
[llvm-project.git] / lldb / unittests / Process / minidump / MinidumpParserTest.cpp
bloba6d015e79a7ef24d805881984731928634e4667a
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 //===----------------------------------------------------------------------===//
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"
30 // C includes
32 // C++ includes
33 #include <memory>
34 #include <optional>
36 using namespace lldb_private;
37 using namespace minidump;
39 class MinidumpParserTest : public testing::Test {
40 public:
41 SubsystemRAII<FileSystem> subsystems;
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);
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");
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();
71 std::optional<MinidumpParser> parser;
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 )");
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());
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
104 )"),
105 llvm::Succeeded());
106 llvm::ArrayRef<minidump::Thread> thread_list;
108 thread_list = parser->GetThreads();
109 ASSERT_EQ(1UL, thread_list.size());
111 const minidump::Thread &thread = thread_list[0];
113 EXPECT_EQ(0x3e81u, thread.ThreadId);
115 llvm::ArrayRef<uint8_t> context = parser->GetThreadContext(thread);
116 EXPECT_EQ(7u, context.size());
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
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());
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:
149 )"),
150 llvm::Succeeded());
151 EXPECT_EQ(nullptr, parser->GetMiscInfo());
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
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);
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
216 )"),
217 llvm::Succeeded());
218 std::optional<lldb::pid_t> pid = parser->GetPid();
219 ASSERT_TRUE(pid.has_value());
220 ASSERT_EQ(16001UL, *pid);
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
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"));
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++;
260 ASSERT_THAT(1UL, count);
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());
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
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));
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));
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
308 )"),
309 llvm::Succeeded());
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));
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));
320 EXPECT_EQ(llvm::ArrayRef<uint8_t>(), parser->GetMemory(0x500000, 512));
323 TEST_F(MinidumpParserTest, FindMemoryRangeWithFullMemoryMinidump) {
324 SetUpData("fizzbuzz_wow64.dmp");
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());
337 constexpr auto yes = MemoryRegionInfo::eYes;
338 constexpr auto no = MemoryRegionInfo::eNo;
339 constexpr auto unknown = MemoryRegionInfo::eDontKnow;
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 ]
377 )"),
378 llvm::Succeeded());
380 EXPECT_THAT(
381 parser->BuildMemoryRegions(),
382 testing::Pair(
383 testing::ElementsAre(
384 MemoryRegionInfo({0x0, 0x10000}, no, no, no, unknown, no, ConstString(),
385 unknown, 0, unknown, unknown),
386 MemoryRegionInfo({0x10000, 0x21000}, yes, yes, no, unknown, yes,
387 ConstString(), unknown, 0, unknown, unknown),
388 MemoryRegionInfo({0x40000, 0x1000}, yes, no, no, unknown, yes,
389 ConstString(), unknown, 0, unknown, unknown),
390 MemoryRegionInfo({0x7ffe0000, 0x1000}, yes, no, no, unknown, yes,
391 ConstString(), unknown, 0, unknown, unknown),
392 MemoryRegionInfo({0x7ffe1000, 0xf000}, no, no, no, unknown, yes,
393 ConstString(), unknown, 0, unknown, unknown)),
394 true));
397 TEST_F(MinidumpParserTest, GetMemoryRegionInfoFromMemoryList) {
398 ASSERT_THAT_ERROR(SetUpFromYaml(R"(
399 --- !minidump
400 Streams:
401 - Type: MemoryList
402 Memory Ranges:
403 - Start of Memory Range: 0x0000000000001000
404 Content: '31313131313131313131313131313131'
405 - Start of Memory Range: 0x0000000000002000
406 Content: '3333333333333333333333333333333333333333333333333333333333333333'
408 )"),
409 llvm::Succeeded());
411 // Test we can get memory regions from the MINIDUMP_MEMORY_LIST stream when
412 // we don't have a MemoryInfoListStream.
414 EXPECT_THAT(
415 parser->BuildMemoryRegions(),
416 testing::Pair(
417 testing::ElementsAre(
418 MemoryRegionInfo({0x1000, 0x10}, yes, unknown, unknown, unknown, yes,
419 ConstString(), unknown, 0, unknown, unknown),
420 MemoryRegionInfo({0x2000, 0x20}, yes, unknown, unknown, unknown, yes,
421 ConstString(), unknown, 0, unknown, unknown)),
422 false));
425 TEST_F(MinidumpParserTest, GetMemoryRegionInfoFromMemory64List) {
426 SetUpData("regions-memlist64.dmp");
428 // Test we can get memory regions from the MINIDUMP_MEMORY64_LIST stream when
429 // we don't have a MemoryInfoListStream.
430 EXPECT_THAT(
431 parser->BuildMemoryRegions(),
432 testing::Pair(
433 testing::ElementsAre(
434 MemoryRegionInfo({0x1000, 0x10}, yes, unknown, unknown, unknown, yes,
435 ConstString(), unknown, 0, unknown, unknown),
436 MemoryRegionInfo({0x2000, 0x20}, yes, unknown, unknown, unknown, yes,
437 ConstString(), unknown, 0, unknown, unknown)),
438 false));
441 TEST_F(MinidumpParserTest, GetMemoryRegionInfoLinuxMaps) {
442 ASSERT_THAT_ERROR(SetUpFromYaml(R"(
443 --- !minidump
444 Streams:
445 - Type: LinuxMaps
446 Text: |
447 400d9000-400db000 r-xp 00000000 b3:04 227 /system/bin/app_process
448 400db000-400dc000 r--p 00001000 b3:04 227 /system/bin/app_process
449 400dc000-400dd000 rw-p 00000000 00:00 0
450 400ec000-400ed000 r--p 00000000 00:00 0
451 400ee000-400ef000 rw-p 00010000 b3:04 300 /system/bin/linker
452 400fc000-400fd000 rwxp 00001000 b3:04 1096 /system/lib/liblog.so
455 )"),
456 llvm::Succeeded());
457 // Test we can get memory regions from the linux /proc/<pid>/maps stream when
458 // we don't have a MemoryInfoListStream.
459 ConstString app_process("/system/bin/app_process");
460 ConstString linker("/system/bin/linker");
461 ConstString liblog("/system/lib/liblog.so");
462 EXPECT_THAT(
463 parser->BuildMemoryRegions(),
464 testing::Pair(
465 testing::ElementsAre(
466 MemoryRegionInfo({0x400d9000, 0x2000}, yes, no, yes, no, yes,
467 app_process, unknown, 0, unknown, unknown),
468 MemoryRegionInfo({0x400db000, 0x1000}, yes, no, no, no, yes,
469 app_process, unknown, 0, unknown, unknown),
470 MemoryRegionInfo({0x400dc000, 0x1000}, yes, yes, no, no, yes,
471 ConstString(), unknown, 0, unknown, unknown),
472 MemoryRegionInfo({0x400ec000, 0x1000}, yes, no, no, no, yes,
473 ConstString(), unknown, 0, unknown, unknown),
474 MemoryRegionInfo({0x400ee000, 0x1000}, yes, yes, no, no, yes, linker,
475 unknown, 0, unknown, unknown),
476 MemoryRegionInfo({0x400fc000, 0x1000}, yes, yes, yes, no, yes, liblog,
477 unknown, 0, unknown, unknown)),
478 true));
481 TEST_F(MinidumpParserTest, GetMemoryRegionInfoLinuxMapsError) {
482 ASSERT_THAT_ERROR(SetUpFromYaml(R"(
483 --- !minidump
484 Streams:
485 - Type: LinuxMaps
486 Text: |
487 400d9000-400db000 r?xp 00000000 b3:04 227
488 400fc000-400fd000 rwxp 00001000 b3:04 1096
490 )"),
491 llvm::Succeeded());
492 // Test that when a /proc/maps region fails to parse
493 // we handle the error and continue with the rest.
494 EXPECT_THAT(
495 parser->BuildMemoryRegions(),
496 testing::Pair(testing::ElementsAre(MemoryRegionInfo(
497 {0x400fc000, 0x1000}, yes, yes, yes, no, yes,
498 ConstString(nullptr), unknown, 0, unknown, unknown)),
499 true));
502 // Windows Minidump tests
503 TEST_F(MinidumpParserTest, GetArchitectureWindows) {
504 ASSERT_THAT_ERROR(SetUpFromYaml(R"(
505 --- !minidump
506 Streams:
507 - Type: SystemInfo
508 Processor Arch: X86
509 Processor Level: 6
510 Processor Revision: 15876
511 Number of Processors: 32
512 Product type: 1
513 Major Version: 6
514 Minor Version: 1
515 Build Number: 7601
516 Platform ID: Win32NT
517 CSD Version: Service Pack 1
518 Suite Mask: 0x0100
519 CPU:
520 Vendor ID: GenuineIntel
521 Version Info: 0x000306E4
522 Feature Info: 0xBFEBFBFF
523 AMD Extended Features: 0x771EEC80
525 )"),
526 llvm::Succeeded());
527 ASSERT_EQ(llvm::Triple::ArchType::x86,
528 parser->GetArchitecture().GetMachine());
529 ASSERT_EQ(llvm::Triple::OSType::Win32,
530 parser->GetArchitecture().GetTriple().getOS());
533 TEST_F(MinidumpParserTest, GetLinuxProcStatus_no_stream) {
534 // Test that GetLinuxProcStatus returns nullptr when the minidump does not
535 // contain this stream.
536 ASSERT_THAT_ERROR(SetUpFromYaml(R"(
537 --- !minidump
538 Streams:
540 )"),
541 llvm::Succeeded());
542 EXPECT_EQ(std::nullopt, parser->GetLinuxProcStatus());
545 TEST_F(MinidumpParserTest, GetMiscInfoWindows) {
546 SetUpData("fizzbuzz_no_heap.dmp");
547 const MinidumpMiscInfo *misc_info = parser->GetMiscInfo();
548 ASSERT_NE(nullptr, misc_info);
549 std::optional<lldb::pid_t> pid = misc_info->GetPid();
550 ASSERT_TRUE(pid.has_value());
551 ASSERT_EQ(4440UL, *pid);
554 TEST_F(MinidumpParserTest, GetPidWindows) {
555 SetUpData("fizzbuzz_no_heap.dmp");
556 std::optional<lldb::pid_t> pid = parser->GetPid();
557 ASSERT_TRUE(pid.has_value());
558 ASSERT_EQ(4440UL, *pid);
561 // wow64
562 TEST_F(MinidumpParserTest, GetPidWow64) {
563 SetUpData("fizzbuzz_wow64.dmp");
564 std::optional<lldb::pid_t> pid = parser->GetPid();
565 ASSERT_TRUE(pid.has_value());
566 ASSERT_EQ(7836UL, *pid);
569 // Register tests
570 #define REG_VAL32(x) *(reinterpret_cast<uint32_t *>(x))
571 #define REG_VAL64(x) *(reinterpret_cast<uint64_t *>(x))
573 TEST_F(MinidumpParserTest, GetThreadContext_x86_32) {
574 ASSERT_THAT_ERROR(SetUpFromYaml(R"(
575 --- !minidump
576 Streams:
577 - Type: ThreadList
578 Threads:
579 - Thread Id: 0x00026804
580 Stack:
581 Start of Memory Range: 0x00000000FF9DD000
582 Content: 68D39DFF
583 Context: 0F0001000000000000000000000000000000000000000000000000007F03FFFF0000FFFFFFFFFFFF09DC62F72300000088E36CF72B00FFFF00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000063000000000000002B0000002B000000A88204085CD59DFF008077F7A3D49DFF01000000000000003CD59DFFA082040823000000820201002CD59DFF2B0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
584 )"),
585 llvm::Succeeded());
587 llvm::ArrayRef<minidump::Thread> thread_list = parser->GetThreads();
588 const minidump::Thread &thread = thread_list[0];
589 llvm::ArrayRef<uint8_t> registers(parser->GetThreadContext(thread));
590 const MinidumpContext_x86_32 *context;
591 EXPECT_TRUE(consumeObject(registers, context).Success());
593 EXPECT_EQ(MinidumpContext_x86_32_Flags(uint32_t(context->context_flags)),
594 MinidumpContext_x86_32_Flags::x86_32_Flag |
595 MinidumpContext_x86_32_Flags::Full |
596 MinidumpContext_x86_32_Flags::FloatingPoint);
598 EXPECT_EQ(0x00000000u, context->eax);
599 EXPECT_EQ(0xf7778000u, context->ebx);
600 EXPECT_EQ(0x00000001u, context->ecx);
601 EXPECT_EQ(0xff9dd4a3u, context->edx);
602 EXPECT_EQ(0x080482a8u, context->edi);
603 EXPECT_EQ(0xff9dd55cu, context->esi);
604 EXPECT_EQ(0xff9dd53cu, context->ebp);
605 EXPECT_EQ(0xff9dd52cu, context->esp);
606 EXPECT_EQ(0x080482a0u, context->eip);
607 EXPECT_EQ(0x00010282u, context->eflags);
608 EXPECT_EQ(0x0023u, context->cs);
609 EXPECT_EQ(0x0000u, context->fs);
610 EXPECT_EQ(0x0063u, context->gs);
611 EXPECT_EQ(0x002bu, context->ss);
612 EXPECT_EQ(0x002bu, context->ds);
613 EXPECT_EQ(0x002bu, context->es);
616 TEST_F(MinidumpParserTest, GetThreadContext_x86_64) {
617 ASSERT_THAT_ERROR(SetUpFromYaml(R"(
618 --- !minidump
619 Streams:
620 - Type: ThreadList
621 Threads:
622 - Thread Id: 0x00003E81
623 Stack:
624 Start of Memory Range: 0x00007FFCEB34A000
625 Content: C84D04BCE97F00
626 Context: 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000B0010000000000033000000000000000000000006020100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000010A234EBFC7F000010A234EBFC7F00000000000000000000F09C34EBFC7F0000C0A91ABCE97F00000000000000000000A0163FBCE97F00004602000000000000921C40000000000030A434EBFC7F000000000000000000000000000000000000C61D4000000000007F0300000000000000000000000000000000000000000000801F0000FFFF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FFFF00FFFFFFFFFFFFFF00FFFFFFFF25252525252525252525252525252525000000000000000000000000000000000000000000000000000000000000000000FFFF00FFFFFFFFFFFFFF00FFFFFFFF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FF00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
628 )"),
629 llvm::Succeeded());
630 llvm::ArrayRef<minidump::Thread> thread_list = parser->GetThreads();
631 const minidump::Thread &thread = thread_list[0];
632 llvm::ArrayRef<uint8_t> registers(parser->GetThreadContext(thread));
633 const MinidumpContext_x86_64 *context;
634 EXPECT_TRUE(consumeObject(registers, context).Success());
636 EXPECT_EQ(MinidumpContext_x86_64_Flags(uint32_t(context->context_flags)),
637 MinidumpContext_x86_64_Flags::x86_64_Flag |
638 MinidumpContext_x86_64_Flags::Control |
639 MinidumpContext_x86_64_Flags::FloatingPoint |
640 MinidumpContext_x86_64_Flags::Integer);
641 EXPECT_EQ(0x0000000000000000u, context->rax);
642 EXPECT_EQ(0x0000000000000000u, context->rbx);
643 EXPECT_EQ(0x0000000000000010u, context->rcx);
644 EXPECT_EQ(0x0000000000000000u, context->rdx);
645 EXPECT_EQ(0x00007ffceb349cf0u, context->rdi);
646 EXPECT_EQ(0x0000000000000000u, context->rsi);
647 EXPECT_EQ(0x00007ffceb34a210u, context->rbp);
648 EXPECT_EQ(0x00007ffceb34a210u, context->rsp);
649 EXPECT_EQ(0x00007fe9bc1aa9c0u, context->r8);
650 EXPECT_EQ(0x0000000000000000u, context->r9);
651 EXPECT_EQ(0x00007fe9bc3f16a0u, context->r10);
652 EXPECT_EQ(0x0000000000000246u, context->r11);
653 EXPECT_EQ(0x0000000000401c92u, context->r12);
654 EXPECT_EQ(0x00007ffceb34a430u, context->r13);
655 EXPECT_EQ(0x0000000000000000u, context->r14);
656 EXPECT_EQ(0x0000000000000000u, context->r15);
657 EXPECT_EQ(0x0000000000401dc6u, context->rip);
658 EXPECT_EQ(0x00010206u, context->eflags);
659 EXPECT_EQ(0x0033u, context->cs);
660 EXPECT_EQ(0x0000u, context->ss);
663 TEST_F(MinidumpParserTest, GetThreadContext_x86_32_wow64) {
664 SetUpData("fizzbuzz_wow64.dmp");
665 llvm::ArrayRef<minidump::Thread> thread_list = parser->GetThreads();
666 const minidump::Thread &thread = thread_list[0];
667 llvm::ArrayRef<uint8_t> registers(parser->GetThreadContextWow64(thread));
668 const MinidumpContext_x86_32 *context;
669 EXPECT_TRUE(consumeObject(registers, context).Success());
671 EXPECT_EQ(MinidumpContext_x86_32_Flags(uint32_t(context->context_flags)),
672 MinidumpContext_x86_32_Flags::x86_32_Flag |
673 MinidumpContext_x86_32_Flags::Full |
674 MinidumpContext_x86_32_Flags::FloatingPoint |
675 MinidumpContext_x86_32_Flags::ExtendedRegisters);
677 EXPECT_EQ(0x00000000u, context->eax);
678 EXPECT_EQ(0x0037f608u, context->ebx);
679 EXPECT_EQ(0x00e61578u, context->ecx);
680 EXPECT_EQ(0x00000008u, context->edx);
681 EXPECT_EQ(0x00000000u, context->edi);
682 EXPECT_EQ(0x00000002u, context->esi);
683 EXPECT_EQ(0x0037f654u, context->ebp);
684 EXPECT_EQ(0x0037f5b8u, context->esp);
685 EXPECT_EQ(0x77ce01fdu, context->eip);
686 EXPECT_EQ(0x00000246u, context->eflags);
687 EXPECT_EQ(0x0023u, context->cs);
688 EXPECT_EQ(0x0053u, context->fs);
689 EXPECT_EQ(0x002bu, context->gs);
690 EXPECT_EQ(0x002bu, context->ss);
691 EXPECT_EQ(0x002bu, context->ds);
692 EXPECT_EQ(0x002bu, context->es);
695 TEST_F(MinidumpParserTest, MinidumpDuplicateModuleMinAddress) {
696 ASSERT_THAT_ERROR(SetUpFromYaml(R"(
697 --- !minidump
698 Streams:
699 - Type: ModuleList
700 Modules:
701 - Base of Image: 0x0000000000002000
702 Size of Image: 0x00001000
703 Module Name: '/tmp/a'
704 CodeView Record: ''
705 - Base of Image: 0x0000000000001000
706 Size of Image: 0x00001000
707 Module Name: '/tmp/a'
708 CodeView Record: ''
710 )"),
711 llvm::Succeeded());
712 // If we have a module mentioned twice in the module list, the filtered
713 // module list should contain the instance with the lowest BaseOfImage.
714 std::vector<const minidump::Module *> filtered_modules =
715 parser->GetFilteredModuleList();
716 ASSERT_EQ(1u, filtered_modules.size());
717 EXPECT_EQ(0x0000000000001000u, filtered_modules[0]->BaseOfImage);
720 TEST_F(MinidumpParserTest, MinidumpDuplicateModuleMappedFirst) {
721 ASSERT_THAT_ERROR(SetUpFromYaml(R"(
722 --- !minidump
723 Streams:
724 - Type: ModuleList
725 Modules:
726 - Base of Image: 0x400d0000
727 Size of Image: 0x00002000
728 Module Name: '/usr/lib/libc.so'
729 CodeView Record: ''
730 - Base of Image: 0x400d3000
731 Size of Image: 0x00001000
732 Module Name: '/usr/lib/libc.so'
733 CodeView Record: ''
734 - Type: LinuxMaps
735 Text: |
736 400d0000-400d2000 r--p 00000000 b3:04 227 /usr/lib/libc.so
737 400d2000-400d3000 rw-p 00000000 00:00 0
738 400d3000-400d4000 r-xp 00010000 b3:04 227 /usr/lib/libc.so
739 400d4000-400d5000 rwxp 00001000 b3:04 227 /usr/lib/libc.so
741 )"),
742 llvm::Succeeded());
743 // If we have a module mentioned twice in the module list, and we have full
744 // linux maps for all of the memory regions, make sure we pick the one that
745 // has a consecutive region with a matching path that has executable
746 // permissions. If clients open an object file with mmap, breakpad can create
747 // multiple mappings for a library errnoneously and the lowest address isn't
748 // always the right address. In this case we check the consective memory
749 // regions whose path matches starting at the base of image address and make
750 // sure one of the regions is executable and prefer that one.
752 // This test will make sure that if the executable is second in the module
753 // list, that it will become the selected module in the filtered list.
754 std::vector<const minidump::Module *> filtered_modules =
755 parser->GetFilteredModuleList();
756 ASSERT_EQ(1u, filtered_modules.size());
757 EXPECT_EQ(0x400d3000u, filtered_modules[0]->BaseOfImage);
760 TEST_F(MinidumpParserTest, MinidumpDuplicateModuleMappedSecond) {
761 ASSERT_THAT_ERROR(SetUpFromYaml(R"(
762 --- !minidump
763 Streams:
764 - Type: ModuleList
765 Modules:
766 - Base of Image: 0x400d0000
767 Size of Image: 0x00002000
768 Module Name: '/usr/lib/libc.so'
769 CodeView Record: ''
770 - Base of Image: 0x400d3000
771 Size of Image: 0x00001000
772 Module Name: '/usr/lib/libc.so'
773 CodeView Record: ''
774 - Type: LinuxMaps
775 Text: |
776 400d0000-400d1000 r-xp 00010000 b3:04 227 /usr/lib/libc.so
777 400d1000-400d2000 rwxp 00001000 b3:04 227 /usr/lib/libc.so
778 400d2000-400d3000 rw-p 00000000 00:00 0
779 400d3000-400d5000 r--p 00000000 b3:04 227 /usr/lib/libc.so
781 )"),
782 llvm::Succeeded());
783 // If we have a module mentioned twice in the module list, and we have full
784 // linux maps for all of the memory regions, make sure we pick the one that
785 // has a consecutive region with a matching path that has executable
786 // permissions. If clients open an object file with mmap, breakpad can create
787 // multiple mappings for a library errnoneously and the lowest address isn't
788 // always the right address. In this case we check the consective memory
789 // regions whose path matches starting at the base of image address and make
790 // sure one of the regions is executable and prefer that one.
792 // This test will make sure that if the executable is first in the module
793 // list, that it will remain the correctly selected module in the filtered
794 // list.
795 std::vector<const minidump::Module *> filtered_modules =
796 parser->GetFilteredModuleList();
797 ASSERT_EQ(1u, filtered_modules.size());
798 EXPECT_EQ(0x400d0000u, filtered_modules[0]->BaseOfImage);
801 TEST_F(MinidumpParserTest, MinidumpDuplicateModuleMappedSecondHigh) {
802 ASSERT_THAT_ERROR(SetUpFromYaml(R"(
803 --- !minidump
804 Streams:
805 - Type: ModuleList
806 Modules:
807 - Base of Image: 0x400d3000
808 Size of Image: 0x00002000
809 Module Name: '/usr/lib/libc.so'
810 CodeView Record: ''
811 - Base of Image: 0x400d0000
812 Size of Image: 0x00001000
813 Module Name: '/usr/lib/libc.so'
814 CodeView Record: ''
815 - Type: LinuxMaps
816 Text: |
817 400d0000-400d2000 r--p 00000000 b3:04 227 /usr/lib/libc.so
818 400d2000-400d3000 rw-p 00000000 00:00 0
819 400d3000-400d4000 r-xp 00010000 b3:04 227 /usr/lib/libc.so
820 400d4000-400d5000 rwxp 00001000 b3:04 227 /usr/lib/libc.so
822 )"),
823 llvm::Succeeded());
824 // If we have a module mentioned twice in the module list, and we have full
825 // linux maps for all of the memory regions, make sure we pick the one that
826 // has a consecutive region with a matching path that has executable
827 // permissions. If clients open an object file with mmap, breakpad can create
828 // multiple mappings for a library errnoneously and the lowest address isn't
829 // always the right address. In this case we check the consective memory
830 // regions whose path matches starting at the base of image address and make
831 // sure one of the regions is executable and prefer that one.
833 // This test will make sure that if the executable is first in the module
834 // list, that it will remain the correctly selected module in the filtered
835 // list, even if the non-executable module was loaded at a lower base address.
836 std::vector<const minidump::Module *> filtered_modules =
837 parser->GetFilteredModuleList();
838 ASSERT_EQ(1u, filtered_modules.size());
839 EXPECT_EQ(0x400d3000u, filtered_modules[0]->BaseOfImage);
842 TEST_F(MinidumpParserTest, MinidumpDuplicateModuleSeparateCode) {
843 ASSERT_THAT_ERROR(SetUpFromYaml(R"(
844 --- !minidump
845 Streams:
846 - Type: ModuleList
847 Modules:
848 - Base of Image: 0x400d0000
849 Size of Image: 0x00002000
850 Module Name: '/usr/lib/libc.so'
851 CodeView Record: ''
852 - Base of Image: 0x400d5000
853 Size of Image: 0x00001000
854 Module Name: '/usr/lib/libc.so'
855 CodeView Record: ''
856 - Type: LinuxMaps
857 Text: |
858 400d0000-400d3000 r--p 00000000 b3:04 227 /usr/lib/libc.so
859 400d3000-400d5000 rw-p 00000000 00:00 0
860 400d5000-400d6000 r--p 00000000 b3:04 227 /usr/lib/libc.so
861 400d6000-400d7000 r-xp 00010000 b3:04 227 /usr/lib/libc.so
862 400d7000-400d8000 rwxp 00001000 b3:04 227 /usr/lib/libc.so
864 )"),
865 llvm::Succeeded());
866 // If we have a module mentioned twice in the module list, and we have full
867 // linux maps for all of the memory regions, make sure we pick the one that
868 // has a consecutive region with a matching path that has executable
869 // permissions. If clients open an object file with mmap, breakpad can create
870 // multiple mappings for a library errnoneously and the lowest address isn't
871 // always the right address. In this case we check the consective memory
872 // regions whose path matches starting at the base of image address and make
873 // sure one of the regions is executable and prefer that one.
875 // This test will make sure if binaries are compiled with "-z separate-code",
876 // where the first region for a binary won't be marked as executable, that
877 // it gets selected by detecting the second consecutive mapping at 0x400d7000
878 // when asked about the a module mamed "/usr/lib/libc.so" at 0x400d5000.
879 std::vector<const minidump::Module *> filtered_modules =
880 parser->GetFilteredModuleList();
881 ASSERT_EQ(1u, filtered_modules.size());
882 EXPECT_EQ(0x400d5000u, filtered_modules[0]->BaseOfImage);
885 TEST_F(MinidumpParserTest, MinidumpModuleOrder) {
886 ASSERT_THAT_ERROR(SetUpFromYaml(R"(
887 --- !minidump
888 Streams:
889 - Type: ModuleList
890 Modules:
891 - Base of Image: 0x0000000000002000
892 Size of Image: 0x00001000
893 Module Name: '/tmp/a'
894 CodeView Record: ''
895 - Base of Image: 0x0000000000001000
896 Size of Image: 0x00001000
897 Module Name: '/tmp/b'
898 CodeView Record: ''
900 )"),
901 llvm::Succeeded());
902 // Test module filtering does not affect the overall module order. Previous
903 // versions of the MinidumpParser::GetFilteredModuleList() function would sort
904 // all images by address and modify the order of the modules.
905 std::vector<const minidump::Module *> filtered_modules =
906 parser->GetFilteredModuleList();
907 ASSERT_EQ(2u, filtered_modules.size());
908 EXPECT_EQ(0x0000000000002000u, filtered_modules[0]->BaseOfImage);
909 EXPECT_THAT_EXPECTED(
910 parser->GetMinidumpFile().getString(filtered_modules[0]->ModuleNameRVA),
911 llvm::HasValue("/tmp/a"));
912 EXPECT_EQ(0x0000000000001000u, filtered_modules[1]->BaseOfImage);
913 EXPECT_THAT_EXPECTED(
914 parser->GetMinidumpFile().getString(filtered_modules[1]->ModuleNameRVA),
915 llvm::HasValue("/tmp/b"));