1 //===-- MinidumpTypesTest.cpp ---------------------------------------------===//
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
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"
36 using namespace lldb_private
;
37 using namespace minidump
;
39 class MinidumpParserTest
: public testing::Test
{
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
) {
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");
63 std::make_shared
<DataBufferHeap
>(data
.data(), data
.size());
64 auto expected_parser
= MinidumpParser::Create(std::move(data_buffer_sp
));
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
"(
81 Content: DEADBEEFBAADF00D
83 Content: DEADBEEFBAADF00D
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
"(
98 - Thread Id: 0x00003E81
100 Start of Memory Range: 0x00007FFCEB34A000
101 Content: C84D04BCE97F00
102 Context: 00000000000000
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
"(
124 Processor Arch: AMD64
126 Processor Revision: 16130
127 Number of Processors: 1
130 Vendor ID: GenuineIntel
131 Version Info: 0x00000000
132 Feature Info: 0x00000000
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
145 ASSERT_THAT_ERROR(SetUpFromYaml(R
"(
151 EXPECT_EQ(nullptr, parser
->GetMiscInfo());
154 TEST_F(MinidumpParserTest
, GetLinuxProcStatus
) {
155 ASSERT_THAT_ERROR(SetUpFromYaml(R
"(
159 Processor Arch: AMD64
161 Processor Revision: 16130
162 Number of Processors: 1
164 CSD Version: 'Linux 3.13.0-91-generic'
166 Vendor ID: GenuineIntel
167 Version Info: 0x00000000
168 Feature Info: 0x00000000
169 - Type: LinuxProcStatus
172 State: t (tracing stop)
178 Uid: 404696 404696 404696 404696
179 Gid: 5762 5762 5762 5762
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
"(
194 Processor Arch: AMD64
196 Processor Revision: 16130
197 Number of Processors: 1
199 CSD Version: 'Linux 3.13.0-91-generic'
201 Vendor ID: GenuineIntel
202 Version Info: 0x00000000
203 Feature Info: 0x00000000
204 - Type: LinuxProcStatus
207 State: t (tracing stop)
213 Uid: 404696 404696 404696 404696
214 Gid: 5762 5762 5762 5762
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
"(
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
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();
254 for (auto exception_stream
: exception_streams
) {
255 ASSERT_THAT_EXPECTED(exception_stream
, llvm::Succeeded());
256 ASSERT_EQ(16001UL, exception_stream
->ThreadId
);
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
"(
277 - Start of Memory Range: 0x00007FFCEB34A000
279 - Start of Memory Range: 0x0000000000401D46
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));
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
"(
303 - Start of Memory Range: 0x00007FFCEB34A000
305 - Start of Memory Range: 0x0000000000401D46
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
"(
345 - Type: MemoryInfoList
347 - Base Address: 0x0000000000000000
348 Allocation Protect: [ ]
349 Region Size: 0x0000000000010000
351 Protect: [ PAGE_NO_ACCESS ]
353 - Base Address: 0x0000000000010000
354 Allocation Protect: [ PAGE_READ_WRITE ]
355 Region Size: 0x0000000000021000
356 State: [ MEM_COMMIT ]
358 - Base Address: 0x0000000000040000
359 Allocation Protect: [ PAGE_EXECUTE_WRITE_COPY ]
360 Region Size: 0x0000000000001000
361 State: [ MEM_COMMIT ]
362 Protect: [ PAGE_READ_ONLY ]
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 ]
381 parser
->BuildMemoryRegions(),
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
)),
397 TEST_F(MinidumpParserTest
, GetMemoryRegionInfoFromMemoryList
) {
398 ASSERT_THAT_ERROR(SetUpFromYaml(R
"(
403 - Start of Memory Range: 0x0000000000001000
404 Content: '31313131313131313131313131313131'
405 - Start of Memory Range: 0x0000000000002000
406 Content: '3333333333333333333333333333333333333333333333333333333333333333'
411 // Test we can get memory regions from the MINIDUMP_MEMORY_LIST stream when
412 // we don't have a MemoryInfoListStream.
415 parser
->BuildMemoryRegions(),
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
)),
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.
431 parser
->BuildMemoryRegions(),
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
)),
441 TEST_F(MinidumpParserTest
, GetMemoryRegionInfoLinuxMaps
) {
442 ASSERT_THAT_ERROR(SetUpFromYaml(R
"(
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
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");
463 parser
->BuildMemoryRegions(),
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
)),
481 TEST_F(MinidumpParserTest
, GetMemoryRegionInfoLinuxMapsError
) {
482 ASSERT_THAT_ERROR(SetUpFromYaml(R
"(
487 400d9000-400db000 r?xp 00000000 b3:04 227
488 400fc000-400fd000 rwxp 00001000 b3:04 1096
492 // Test that when a /proc/maps region fails to parse
493 // we handle the error and continue with the rest.
495 parser
->BuildMemoryRegions(),
496 testing::Pair(testing::ElementsAre(MemoryRegionInfo(
497 {0x400fc000, 0x1000}, yes
, yes
, yes
, no
, yes
,
498 ConstString(nullptr), unknown
, 0, unknown
, unknown
)),
502 // Windows Minidump tests
503 TEST_F(MinidumpParserTest
, GetArchitectureWindows
) {
504 ASSERT_THAT_ERROR(SetUpFromYaml(R
"(
510 Processor Revision: 15876
511 Number of Processors: 32
517 CSD Version: Service Pack 1
520 Vendor ID: GenuineIntel
521 Version Info: 0x000306E4
522 Feature Info: 0xBFEBFBFF
523 AMD Extended Features: 0x771EEC80
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
"(
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
);
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
);
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
"(
579 - Thread Id: 0x00026804
581 Start of Memory Range: 0x00000000FF9DD000
583 Context: 0F0001000000000000000000000000000000000000000000000000007F03FFFF0000FFFFFFFFFFFF09DC62F72300000088E36CF72B00FFFF00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000063000000000000002B0000002B000000A88204085CD59DFF008077F7A3D49DFF01000000000000003CD59DFFA082040823000000820201002CD59DFF2B0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
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
"(
622 - Thread Id: 0x00003E81
624 Start of Memory Range: 0x00007FFCEB34A000
625 Content: C84D04BCE97F00
626 Context: 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000B0010000000000033000000000000000000000006020100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000010A234EBFC7F000010A234EBFC7F00000000000000000000F09C34EBFC7F0000C0A91ABCE97F00000000000000000000A0163FBCE97F00004602000000000000921C40000000000030A434EBFC7F000000000000000000000000000000000000C61D4000000000007F0300000000000000000000000000000000000000000000801F0000FFFF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FFFF00FFFFFFFFFFFFFF00FFFFFFFF25252525252525252525252525252525000000000000000000000000000000000000000000000000000000000000000000FFFF00FFFFFFFFFFFFFF00FFFFFFFF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FF00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
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
"(
701 - Base of Image: 0x0000000000002000
702 Size of Image: 0x00001000
703 Module Name: '/tmp/a'
705 - Base of Image: 0x0000000000001000
706 Size of Image: 0x00001000
707 Module Name: '/tmp/a'
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
"(
726 - Base of Image: 0x400d0000
727 Size of Image: 0x00002000
728 Module Name: '/usr/lib/libc.so'
730 - Base of Image: 0x400d3000
731 Size of Image: 0x00001000
732 Module Name: '/usr/lib/libc.so'
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
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
"(
766 - Base of Image: 0x400d0000
767 Size of Image: 0x00002000
768 Module Name: '/usr/lib/libc.so'
770 - Base of Image: 0x400d3000
771 Size of Image: 0x00001000
772 Module Name: '/usr/lib/libc.so'
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
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
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
"(
807 - Base of Image: 0x400d3000
808 Size of Image: 0x00002000
809 Module Name: '/usr/lib/libc.so'
811 - Base of Image: 0x400d0000
812 Size of Image: 0x00001000
813 Module Name: '/usr/lib/libc.so'
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
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
"(
848 - Base of Image: 0x400d0000
849 Size of Image: 0x00002000
850 Module Name: '/usr/lib/libc.so'
852 - Base of Image: 0x400d5000
853 Size of Image: 0x00001000
854 Module Name: '/usr/lib/libc.so'
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
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
"(
891 - Base of Image: 0x0000000000002000
892 Size of Image: 0x00001000
893 Module Name: '/tmp/a'
895 - Base of Image: 0x0000000000001000
896 Size of Image: 0x00001000
897 Module Name: '/tmp/b'
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"));