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");
64 std::make_shared
<DataBufferHeap
>(data
.data(), data
.size());
65 auto expected_parser
= MinidumpParser::Create(std::move(data_buffer_sp
));
67 return expected_parser
.takeError();
68 parser
= std::move(*expected_parser
);
69 return llvm::Error::success();
72 std::optional
<MinidumpParser
> parser
;
75 TEST_F(MinidumpParserTest
, InvalidMinidump
) {
76 std::string duplicate_streams
;
77 llvm::raw_string_ostream
os(duplicate_streams
);
78 llvm::yaml::Input
YIn(R
"(
82 Content: DEADBEEFBAADF00D
84 Content: DEADBEEFBAADF00D
87 ASSERT_TRUE(llvm::yaml::convertYAML(YIn
, os
, [](const llvm::Twine
&Msg
){}));
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());
94 TEST_F(MinidumpParserTest
, GetThreadsAndGetThreadContext
) {
95 ASSERT_THAT_ERROR(SetUpFromYaml(R
"(
100 - Thread Id: 0x00003E81
102 Start of Memory Range: 0x00007FFCEB34A000
103 Content: C84D04BCE97F00
104 Context: 00000000000000
108 llvm::ArrayRef
<minidump::Thread
> thread_list
;
110 thread_list
= parser
->GetThreads();
111 ASSERT_EQ(1UL, thread_list
.size());
113 const minidump::Thread
&thread
= thread_list
[0];
115 EXPECT_EQ(0x3e81u
, thread
.ThreadId
);
117 llvm::ArrayRef
<uint8_t> context
= parser
->GetThreadContext(thread
);
118 EXPECT_EQ(7u, context
.size());
121 TEST_F(MinidumpParserTest
, GetArchitecture
) {
122 ASSERT_THAT_ERROR(SetUpFromYaml(R
"(
126 Processor Arch: AMD64
128 Processor Revision: 16130
129 Number of Processors: 1
132 Vendor ID: GenuineIntel
133 Version Info: 0x00000000
134 Feature Info: 0x00000000
138 ASSERT_EQ(llvm::Triple::ArchType::x86_64
,
139 parser
->GetArchitecture().GetMachine());
140 ASSERT_EQ(llvm::Triple::OSType::Linux
,
141 parser
->GetArchitecture().GetTriple().getOS());
144 TEST_F(MinidumpParserTest
, GetMiscInfo_no_stream
) {
145 // Test that GetMiscInfo returns nullptr when the minidump does not contain
147 ASSERT_THAT_ERROR(SetUpFromYaml(R
"(
153 EXPECT_EQ(nullptr, parser
->GetMiscInfo());
156 TEST_F(MinidumpParserTest
, GetLinuxProcStatus
) {
157 ASSERT_THAT_ERROR(SetUpFromYaml(R
"(
161 Processor Arch: AMD64
163 Processor Revision: 16130
164 Number of Processors: 1
166 CSD Version: 'Linux 3.13.0-91-generic'
168 Vendor ID: GenuineIntel
169 Version Info: 0x00000000
170 Feature Info: 0x00000000
171 - Type: LinuxProcStatus
174 State: t (tracing stop)
180 Uid: 404696 404696 404696 404696
181 Gid: 5762 5762 5762 5762
185 std::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
);
191 TEST_F(MinidumpParserTest
, GetPid
) {
192 ASSERT_THAT_ERROR(SetUpFromYaml(R
"(
196 Processor Arch: AMD64
198 Processor Revision: 16130
199 Number of Processors: 1
201 CSD Version: 'Linux 3.13.0-91-generic'
203 Vendor ID: GenuineIntel
204 Version Info: 0x00000000
205 Feature Info: 0x00000000
206 - Type: LinuxProcStatus
209 State: t (tracing stop)
215 Uid: 404696 404696 404696 404696
216 Gid: 5762 5762 5762 5762
220 std::optional
<lldb::pid_t
> pid
= parser
->GetPid();
221 ASSERT_TRUE(pid
.has_value());
222 ASSERT_EQ(16001UL, *pid
);
225 TEST_F(MinidumpParserTest
, GetFilteredModuleList
) {
226 ASSERT_THAT_ERROR(SetUpFromYaml(R
"(
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
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"));
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
);
260 void check_mem_range_exists(MinidumpParser
&parser
, const uint64_t range_start
,
261 const uint64_t range_size
) {
262 std::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());
268 TEST_F(MinidumpParserTest
, FindMemoryRange
) {
269 ASSERT_THAT_ERROR(SetUpFromYaml(R
"(
274 - Start of Memory Range: 0x00007FFCEB34A000
276 - Start of Memory Range: 0x0000000000401D46
281 EXPECT_EQ(std::nullopt
, parser
->FindMemoryRange(0x00));
282 EXPECT_EQ(std::nullopt
, parser
->FindMemoryRange(0x2a));
283 EXPECT_EQ((minidump::Range
{0x401d46, llvm::ArrayRef
<uint8_t>{0x54, 0x21}}),
284 parser
->FindMemoryRange(0x401d46));
285 EXPECT_EQ(std::nullopt
, parser
->FindMemoryRange(0x401d46 + 2));
288 (minidump::Range
{0x7ffceb34a000,
289 llvm::ArrayRef
<uint8_t>{0xc8, 0x4d, 0x04, 0xbc, 0xe9}}),
290 parser
->FindMemoryRange(0x7ffceb34a000 + 2));
291 EXPECT_EQ(std::nullopt
, parser
->FindMemoryRange(0x7ffceb34a000 + 5));
294 TEST_F(MinidumpParserTest
, GetMemory
) {
295 ASSERT_THAT_ERROR(SetUpFromYaml(R
"(
300 - Start of Memory Range: 0x00007FFCEB34A000
302 - Start of Memory Range: 0x0000000000401D46
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));
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));
317 EXPECT_EQ(llvm::ArrayRef
<uint8_t>(), parser
->GetMemory(0x500000, 512));
320 TEST_F(MinidumpParserTest
, FindMemoryRangeWithFullMemoryMinidump
) {
321 SetUpData("fizzbuzz_wow64.dmp");
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());
334 constexpr auto yes
= MemoryRegionInfo::eYes
;
335 constexpr auto no
= MemoryRegionInfo::eNo
;
336 constexpr auto unknown
= MemoryRegionInfo::eDontKnow
;
338 TEST_F(MinidumpParserTest
, GetMemoryRegionInfo
) {
339 ASSERT_THAT_ERROR(SetUpFromYaml(R
"(
342 - Type: MemoryInfoList
344 - Base Address: 0x0000000000000000
345 Allocation Protect: [ ]
346 Region Size: 0x0000000000010000
348 Protect: [ PAGE_NO_ACCESS ]
350 - Base Address: 0x0000000000010000
351 Allocation Protect: [ PAGE_READ_WRITE ]
352 Region Size: 0x0000000000021000
353 State: [ MEM_COMMIT ]
355 - Base Address: 0x0000000000040000
356 Allocation Protect: [ PAGE_EXECUTE_WRITE_COPY ]
357 Region Size: 0x0000000000001000
358 State: [ MEM_COMMIT ]
359 Protect: [ PAGE_READ_ONLY ]
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 ]
378 parser
->BuildMemoryRegions(),
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
)),
394 TEST_F(MinidumpParserTest
, GetMemoryRegionInfoFromMemoryList
) {
395 ASSERT_THAT_ERROR(SetUpFromYaml(R
"(
400 - Start of Memory Range: 0x0000000000001000
401 Content: '31313131313131313131313131313131'
402 - Start of Memory Range: 0x0000000000002000
403 Content: '3333333333333333333333333333333333333333333333333333333333333333'
408 // Test we can get memory regions from the MINIDUMP_MEMORY_LIST stream when
409 // we don't have a MemoryInfoListStream.
412 parser
->BuildMemoryRegions(),
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
)),
422 TEST_F(MinidumpParserTest
, GetMemoryRegionInfoFromMemory64List
) {
423 SetUpData("regions-memlist64.dmp");
425 // Test we can get memory regions from the MINIDUMP_MEMORY64_LIST stream when
426 // we don't have a MemoryInfoListStream.
428 parser
->BuildMemoryRegions(),
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
)),
438 TEST_F(MinidumpParserTest
, GetMemoryRegionInfoLinuxMaps
) {
439 ASSERT_THAT_ERROR(SetUpFromYaml(R
"(
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
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");
460 parser
->BuildMemoryRegions(),
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
)),
478 TEST_F(MinidumpParserTest
, GetMemoryRegionInfoLinuxMapsError
) {
479 ASSERT_THAT_ERROR(SetUpFromYaml(R
"(
484 400d9000-400db000 r?xp 00000000 b3:04 227
485 400fc000-400fd000 rwxp 00001000 b3:04 1096
489 // Test that when a /proc/maps region fails to parse
490 // we handle the error and continue with the rest.
492 parser
->BuildMemoryRegions(),
493 testing::Pair(testing::ElementsAre(MemoryRegionInfo(
494 {0x400fc000, 0x1000}, yes
, yes
, yes
, no
, yes
,
495 ConstString(nullptr), unknown
, 0, unknown
, unknown
)),
499 // Windows Minidump tests
500 TEST_F(MinidumpParserTest
, GetArchitectureWindows
) {
501 ASSERT_THAT_ERROR(SetUpFromYaml(R
"(
507 Processor Revision: 15876
508 Number of Processors: 32
514 CSD Version: Service Pack 1
517 Vendor ID: GenuineIntel
518 Version Info: 0x000306E4
519 Feature Info: 0xBFEBFBFF
520 AMD Extended Features: 0x771EEC80
524 ASSERT_EQ(llvm::Triple::ArchType::x86
,
525 parser
->GetArchitecture().GetMachine());
526 ASSERT_EQ(llvm::Triple::OSType::Win32
,
527 parser
->GetArchitecture().GetTriple().getOS());
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
"(
539 EXPECT_EQ(std::nullopt
, parser
->GetLinuxProcStatus());
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 std::optional
<lldb::pid_t
> pid
= misc_info
->GetPid();
547 ASSERT_TRUE(pid
.has_value());
548 ASSERT_EQ(4440UL, *pid
);
551 TEST_F(MinidumpParserTest
, GetPidWindows
) {
552 SetUpData("fizzbuzz_no_heap.dmp");
553 std::optional
<lldb::pid_t
> pid
= parser
->GetPid();
554 ASSERT_TRUE(pid
.has_value());
555 ASSERT_EQ(4440UL, *pid
);
559 TEST_F(MinidumpParserTest
, GetPidWow64
) {
560 SetUpData("fizzbuzz_wow64.dmp");
561 std::optional
<lldb::pid_t
> pid
= parser
->GetPid();
562 ASSERT_TRUE(pid
.has_value());
563 ASSERT_EQ(7836UL, *pid
);
567 #define REG_VAL32(x) *(reinterpret_cast<uint32_t *>(x))
568 #define REG_VAL64(x) *(reinterpret_cast<uint64_t *>(x))
570 TEST_F(MinidumpParserTest
, GetThreadContext_x86_32
) {
571 ASSERT_THAT_ERROR(SetUpFromYaml(R
"(
576 - Thread Id: 0x00026804
578 Start of Memory Range: 0x00000000FF9DD000
580 Context: 0F0001000000000000000000000000000000000000000000000000007F03FFFF0000FFFFFFFFFFFF09DC62F72300000088E36CF72B00FFFF00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000063000000000000002B0000002B000000A88204085CD59DFF008077F7A3D49DFF01000000000000003CD59DFFA082040823000000820201002CD59DFF2B0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
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());
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
);
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
);
613 TEST_F(MinidumpParserTest
, GetThreadContext_x86_64
) {
614 ASSERT_THAT_ERROR(SetUpFromYaml(R
"(
619 - Thread Id: 0x00003E81
621 Start of Memory Range: 0x00007FFCEB34A000
622 Content: C84D04BCE97F00
623 Context: 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000B0010000000000033000000000000000000000006020100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000010A234EBFC7F000010A234EBFC7F00000000000000000000F09C34EBFC7F0000C0A91ABCE97F00000000000000000000A0163FBCE97F00004602000000000000921C40000000000030A434EBFC7F000000000000000000000000000000000000C61D4000000000007F0300000000000000000000000000000000000000000000801F0000FFFF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FFFF00FFFFFFFFFFFFFF00FFFFFFFF25252525252525252525252525252525000000000000000000000000000000000000000000000000000000000000000000FFFF00FFFFFFFFFFFFFF00FFFFFFFF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FF00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
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());
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
);
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());
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
);
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
);
692 TEST_F(MinidumpParserTest
, MinidumpDuplicateModuleMinAddress
) {
693 ASSERT_THAT_ERROR(SetUpFromYaml(R
"(
698 - Base of Image: 0x0000000000002000
699 Size of Image: 0x00001000
700 Module Name: '/tmp/a'
702 - Base of Image: 0x0000000000001000
703 Size of Image: 0x00001000
704 Module Name: '/tmp/a'
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
);
717 TEST_F(MinidumpParserTest
, MinidumpDuplicateModuleMappedFirst
) {
718 ASSERT_THAT_ERROR(SetUpFromYaml(R
"(
723 - Base of Image: 0x400d0000
724 Size of Image: 0x00002000
725 Module Name: '/usr/lib/libc.so'
727 - Base of Image: 0x400d3000
728 Size of Image: 0x00001000
729 Module Name: '/usr/lib/libc.so'
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
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.
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
);
757 TEST_F(MinidumpParserTest
, MinidumpDuplicateModuleMappedSecond
) {
758 ASSERT_THAT_ERROR(SetUpFromYaml(R
"(
763 - Base of Image: 0x400d0000
764 Size of Image: 0x00002000
765 Module Name: '/usr/lib/libc.so'
767 - Base of Image: 0x400d3000
768 Size of Image: 0x00001000
769 Module Name: '/usr/lib/libc.so'
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
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.
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
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
);
798 TEST_F(MinidumpParserTest
, MinidumpDuplicateModuleMappedSecondHigh
) {
799 ASSERT_THAT_ERROR(SetUpFromYaml(R
"(
804 - Base of Image: 0x400d3000
805 Size of Image: 0x00002000
806 Module Name: '/usr/lib/libc.so'
808 - Base of Image: 0x400d0000
809 Size of Image: 0x00001000
810 Module Name: '/usr/lib/libc.so'
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
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.
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
);
839 TEST_F(MinidumpParserTest
, MinidumpDuplicateModuleSeparateCode
) {
840 ASSERT_THAT_ERROR(SetUpFromYaml(R
"(
845 - Base of Image: 0x400d0000
846 Size of Image: 0x00002000
847 Module Name: '/usr/lib/libc.so'
849 - Base of Image: 0x400d5000
850 Size of Image: 0x00001000
851 Module Name: '/usr/lib/libc.so'
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
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.
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
);
882 TEST_F(MinidumpParserTest
, MinidumpModuleOrder
) {
883 ASSERT_THAT_ERROR(SetUpFromYaml(R
"(
888 - Base of Image: 0x0000000000002000
889 Size of Image: 0x00001000
890 Module Name: '/tmp/a'
892 - Base of Image: 0x0000000000001000
893 Size of Image: 0x00001000
894 Module Name: '/tmp/b'
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"));