1 | //===-- MinidumpTypesTest.cpp ---------------------------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "Plugins/Process/minidump/MinidumpParser.h" |
10 | #include "Plugins/Process/minidump/MinidumpTypes.h" |
11 | #include "Plugins/Process/minidump/RegisterContextMinidump_x86_32.h" |
12 | #include "Plugins/Process/minidump/RegisterContextMinidump_x86_64.h" |
13 | #include "TestingSupport/SubsystemRAII.h" |
14 | #include "TestingSupport/TestUtilities.h" |
15 | #include "lldb/Host/FileSystem.h" |
16 | #include "lldb/Target/MemoryRegionInfo.h" |
17 | #include "lldb/Utility/ArchSpec.h" |
18 | #include "lldb/Utility/DataBufferHeap.h" |
19 | #include "lldb/Utility/DataExtractor.h" |
20 | #include "lldb/Utility/FileSpec.h" |
21 | #include "llvm/ADT/ArrayRef.h" |
22 | #include "llvm/ObjectYAML/yaml2obj.h" |
23 | #include "llvm/Support/FileSystem.h" |
24 | #include "llvm/Support/MemoryBuffer.h" |
25 | #include "llvm/Support/Path.h" |
26 | #include "llvm/Support/YAMLTraits.h" |
27 | #include "llvm/Testing/Support/Error.h" |
28 | #include "gtest/gtest.h" |
29 | |
30 | // C includes |
31 | |
32 | // C++ includes |
33 | #include <memory> |
34 | #include <optional> |
35 | |
36 | using namespace lldb_private; |
37 | using namespace minidump; |
38 | |
39 | class MinidumpParserTest : public testing::Test { |
40 | public: |
41 | SubsystemRAII<FileSystem> subsystems; |
42 | |
43 | void SetUpData(const char *minidump_filename) { |
44 | std::string filename = GetInputFilePath(name: minidump_filename); |
45 | auto BufferPtr = FileSystem::Instance().CreateDataBuffer(path: filename, size: -1, offset: 0); |
46 | ASSERT_NE(BufferPtr, nullptr); |
47 | llvm::Expected<MinidumpParser> expected_parser = |
48 | MinidumpParser::Create(data_buf_sp: BufferPtr); |
49 | ASSERT_THAT_EXPECTED(expected_parser, llvm::Succeeded()); |
50 | parser = std::move(*expected_parser); |
51 | ASSERT_GT(parser->GetData().size(), 0UL); |
52 | } |
53 | |
54 | llvm::Error SetUpFromYaml(llvm::StringRef yaml) { |
55 | std::string data; |
56 | llvm::raw_string_ostream os(data); |
57 | llvm::yaml::Input YIn(yaml); |
58 | if (!llvm::yaml::convertYAML(YIn, Out&: os, ErrHandler: [](const llvm::Twine &Msg) {})) |
59 | return llvm::createStringError(EC: llvm::inconvertibleErrorCode(), |
60 | Msg: "convertYAML() failed" ); |
61 | |
62 | os.flush(); |
63 | auto data_buffer_sp = |
64 | std::make_shared<DataBufferHeap>(args: data.data(), args: data.size()); |
65 | auto expected_parser = MinidumpParser::Create(data_buf_sp: std::move(data_buffer_sp)); |
66 | if (!expected_parser) |
67 | return expected_parser.takeError(); |
68 | parser = std::move(*expected_parser); |
69 | return llvm::Error::success(); |
70 | } |
71 | |
72 | std::optional<MinidumpParser> parser; |
73 | }; |
74 | |
75 | TEST_F(MinidumpParserTest, InvalidMinidump) { |
76 | std::string duplicate_streams; |
77 | llvm::raw_string_ostream os(duplicate_streams); |
78 | llvm::yaml::Input YIn(R"( |
79 | --- !minidump |
80 | Streams: |
81 | - Type: LinuxAuxv |
82 | Content: DEADBEEFBAADF00D |
83 | - Type: LinuxAuxv |
84 | Content: DEADBEEFBAADF00D |
85 | )" ); |
86 | |
87 | ASSERT_TRUE(llvm::yaml::convertYAML(YIn, os, [](const llvm::Twine &Msg){})); |
88 | os.flush(); |
89 | auto data_buffer_sp = std::make_shared<DataBufferHeap>( |
90 | args: duplicate_streams.data(), args: duplicate_streams.size()); |
91 | ASSERT_THAT_EXPECTED(MinidumpParser::Create(data_buffer_sp), llvm::Failed()); |
92 | } |
93 | |
94 | TEST_F(MinidumpParserTest, GetThreadsAndGetThreadContext) { |
95 | ASSERT_THAT_ERROR(SetUpFromYaml(R"( |
96 | --- !minidump |
97 | Streams: |
98 | - Type: ThreadList |
99 | Threads: |
100 | - Thread Id: 0x00003E81 |
101 | Stack: |
102 | Start of Memory Range: 0x00007FFCEB34A000 |
103 | Content: C84D04BCE97F00 |
104 | Context: 00000000000000 |
105 | ... |
106 | )" ), |
107 | llvm::Succeeded()); |
108 | llvm::ArrayRef<minidump::Thread> thread_list; |
109 | |
110 | thread_list = parser->GetThreads(); |
111 | ASSERT_EQ(1UL, thread_list.size()); |
112 | |
113 | const minidump::Thread &thread = thread_list[0]; |
114 | |
115 | EXPECT_EQ(0x3e81u, thread.ThreadId); |
116 | |
117 | llvm::ArrayRef<uint8_t> context = parser->GetThreadContext(td: thread); |
118 | EXPECT_EQ(7u, context.size()); |
119 | } |
120 | |
121 | TEST_F(MinidumpParserTest, GetArchitecture) { |
122 | ASSERT_THAT_ERROR(SetUpFromYaml(R"( |
123 | --- !minidump |
124 | Streams: |
125 | - Type: SystemInfo |
126 | Processor Arch: AMD64 |
127 | Processor Level: 6 |
128 | Processor Revision: 16130 |
129 | Number of Processors: 1 |
130 | Platform ID: Linux |
131 | CPU: |
132 | Vendor ID: GenuineIntel |
133 | Version Info: 0x00000000 |
134 | Feature Info: 0x00000000 |
135 | ... |
136 | )" ), |
137 | llvm::Succeeded()); |
138 | ASSERT_EQ(llvm::Triple::ArchType::x86_64, |
139 | parser->GetArchitecture().GetMachine()); |
140 | ASSERT_EQ(llvm::Triple::OSType::Linux, |
141 | parser->GetArchitecture().GetTriple().getOS()); |
142 | } |
143 | |
144 | TEST_F(MinidumpParserTest, GetMiscInfo_no_stream) { |
145 | // Test that GetMiscInfo returns nullptr when the minidump does not contain |
146 | // this stream. |
147 | ASSERT_THAT_ERROR(SetUpFromYaml(R"( |
148 | --- !minidump |
149 | Streams: |
150 | ... |
151 | )" ), |
152 | llvm::Succeeded()); |
153 | EXPECT_EQ(nullptr, parser->GetMiscInfo()); |
154 | } |
155 | |
156 | TEST_F(MinidumpParserTest, GetLinuxProcStatus) { |
157 | ASSERT_THAT_ERROR(SetUpFromYaml(R"( |
158 | --- !minidump |
159 | Streams: |
160 | - Type: SystemInfo |
161 | Processor Arch: AMD64 |
162 | Processor Level: 6 |
163 | Processor Revision: 16130 |
164 | Number of Processors: 1 |
165 | Platform ID: Linux |
166 | CSD Version: 'Linux 3.13.0-91-generic' |
167 | CPU: |
168 | Vendor ID: GenuineIntel |
169 | Version Info: 0x00000000 |
170 | Feature Info: 0x00000000 |
171 | - Type: LinuxProcStatus |
172 | Text: | |
173 | Name: a.out |
174 | State: t (tracing stop) |
175 | Tgid: 16001 |
176 | Ngid: 0 |
177 | Pid: 16001 |
178 | PPid: 13243 |
179 | TracerPid: 16002 |
180 | Uid: 404696 404696 404696 404696 |
181 | Gid: 5762 5762 5762 5762 |
182 | ... |
183 | )" ), |
184 | llvm::Succeeded()); |
185 | 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); |
189 | } |
190 | |
191 | TEST_F(MinidumpParserTest, GetPid) { |
192 | ASSERT_THAT_ERROR(SetUpFromYaml(R"( |
193 | --- !minidump |
194 | Streams: |
195 | - Type: SystemInfo |
196 | Processor Arch: AMD64 |
197 | Processor Level: 6 |
198 | Processor Revision: 16130 |
199 | Number of Processors: 1 |
200 | Platform ID: Linux |
201 | CSD Version: 'Linux 3.13.0-91-generic' |
202 | CPU: |
203 | Vendor ID: GenuineIntel |
204 | Version Info: 0x00000000 |
205 | Feature Info: 0x00000000 |
206 | - Type: LinuxProcStatus |
207 | Text: | |
208 | Name: a.out |
209 | State: t (tracing stop) |
210 | Tgid: 16001 |
211 | Ngid: 0 |
212 | Pid: 16001 |
213 | PPid: 13243 |
214 | TracerPid: 16002 |
215 | Uid: 404696 404696 404696 404696 |
216 | Gid: 5762 5762 5762 5762 |
217 | ... |
218 | )" ), |
219 | llvm::Succeeded()); |
220 | std::optional<lldb::pid_t> pid = parser->GetPid(); |
221 | ASSERT_TRUE(pid.has_value()); |
222 | ASSERT_EQ(16001UL, *pid); |
223 | } |
224 | |
225 | TEST_F(MinidumpParserTest, GetFilteredModuleList) { |
226 | ASSERT_THAT_ERROR(SetUpFromYaml(R"( |
227 | --- !minidump |
228 | Streams: |
229 | - Type: ModuleList |
230 | Modules: |
231 | - Base of Image: 0x0000000000400000 |
232 | Size of Image: 0x00001000 |
233 | Module Name: '/tmp/test/linux-x86_64_not_crashed' |
234 | CodeView Record: 4C4570426CCF3F60FFA7CC4B86AE8FF44DB2576A68983611 |
235 | - Base of Image: 0x0000000000600000 |
236 | Size of Image: 0x00002000 |
237 | Module Name: '/tmp/test/linux-x86_64_not_crashed' |
238 | CodeView Record: 4C4570426CCF3F60FFA7CC4B86AE8FF44DB2576A68983611 |
239 | ... |
240 | )" ), |
241 | llvm::Succeeded()); |
242 | llvm::ArrayRef<minidump::Module> modules = parser->GetModuleList(); |
243 | std::vector<const minidump::Module *> filtered_modules = |
244 | parser->GetFilteredModuleList(); |
245 | EXPECT_EQ(2u, modules.size()); |
246 | ASSERT_EQ(1u, filtered_modules.size()); |
247 | const minidump::Module &M = *filtered_modules[0]; |
248 | EXPECT_THAT_EXPECTED(parser->GetMinidumpFile().getString(M.ModuleNameRVA), |
249 | llvm::HasValue("/tmp/test/linux-x86_64_not_crashed" )); |
250 | } |
251 | |
252 | TEST_F(MinidumpParserTest, GetExceptionStream) { |
253 | SetUpData("linux-x86_64.dmp" ); |
254 | const llvm::minidump::ExceptionStream *exception_stream = |
255 | parser->GetExceptionStream(); |
256 | ASSERT_NE(nullptr, exception_stream); |
257 | ASSERT_EQ(11UL, exception_stream->ExceptionRecord.ExceptionCode); |
258 | } |
259 | |
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(addr: range_start); |
263 | ASSERT_TRUE(range.has_value()) << "There is no range containing this address" ; |
264 | EXPECT_EQ(range_start, range->start); |
265 | EXPECT_EQ(range_start + range_size, range->start + range->range_ref.size()); |
266 | } |
267 | |
268 | TEST_F(MinidumpParserTest, FindMemoryRange) { |
269 | ASSERT_THAT_ERROR(SetUpFromYaml(R"( |
270 | --- !minidump |
271 | Streams: |
272 | - Type: MemoryList |
273 | Memory Ranges: |
274 | - Start of Memory Range: 0x00007FFCEB34A000 |
275 | Content: C84D04BCE9 |
276 | - Start of Memory Range: 0x0000000000401D46 |
277 | Content: 5421 |
278 | ... |
279 | )" ), |
280 | llvm::Succeeded()); |
281 | EXPECT_EQ(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)); |
286 | |
287 | EXPECT_EQ( |
288 | (minidump::Range{0x7ffceb34a000, |
289 | llvm::ArrayRef<uint8_t>{0xc8, 0x4d, 0x04, 0xbc, 0xe9}}), |
290 | parser->FindMemoryRange(0x7ffceb34a000 + 2)); |
291 | EXPECT_EQ(std::nullopt, parser->FindMemoryRange(0x7ffceb34a000 + 5)); |
292 | } |
293 | |
294 | TEST_F(MinidumpParserTest, GetMemory) { |
295 | ASSERT_THAT_ERROR(SetUpFromYaml(R"( |
296 | --- !minidump |
297 | Streams: |
298 | - Type: MemoryList |
299 | Memory Ranges: |
300 | - Start of Memory Range: 0x00007FFCEB34A000 |
301 | Content: C84D04BCE9 |
302 | - Start of Memory Range: 0x0000000000401D46 |
303 | Content: 5421 |
304 | ... |
305 | )" ), |
306 | llvm::Succeeded()); |
307 | |
308 | EXPECT_EQ((llvm::ArrayRef<uint8_t>{0x54}), parser->GetMemory(0x401d46, 1)); |
309 | EXPECT_EQ((llvm::ArrayRef<uint8_t>{0x54, 0x21}), |
310 | parser->GetMemory(0x401d46, 4)); |
311 | |
312 | EXPECT_EQ((llvm::ArrayRef<uint8_t>{0xc8, 0x4d, 0x04, 0xbc, 0xe9}), |
313 | parser->GetMemory(0x7ffceb34a000, 5)); |
314 | EXPECT_EQ((llvm::ArrayRef<uint8_t>{0xc8, 0x4d, 0x04}), |
315 | parser->GetMemory(0x7ffceb34a000, 3)); |
316 | |
317 | EXPECT_EQ(llvm::ArrayRef<uint8_t>(), parser->GetMemory(0x500000, 512)); |
318 | } |
319 | |
320 | TEST_F(MinidumpParserTest, FindMemoryRangeWithFullMemoryMinidump) { |
321 | SetUpData("fizzbuzz_wow64.dmp" ); |
322 | |
323 | // There are a lot of ranges in the file, just testing with some of them |
324 | EXPECT_FALSE(parser->FindMemoryRange(0x00).has_value()); |
325 | EXPECT_FALSE(parser->FindMemoryRange(0x2a).has_value()); |
326 | check_mem_range_exists(parser&: *parser, range_start: 0x10000, range_size: 65536); // first range |
327 | check_mem_range_exists(parser&: *parser, range_start: 0x40000, range_size: 4096); |
328 | EXPECT_FALSE(parser->FindMemoryRange(0x40000 + 4096).has_value()); |
329 | check_mem_range_exists(parser&: *parser, range_start: 0x77c12000, range_size: 8192); |
330 | check_mem_range_exists(parser&: *parser, range_start: 0x7ffe0000, range_size: 4096); // last range |
331 | EXPECT_FALSE(parser->FindMemoryRange(0x7ffe0000 + 4096).has_value()); |
332 | } |
333 | |
334 | constexpr auto yes = MemoryRegionInfo::eYes; |
335 | constexpr auto no = MemoryRegionInfo::eNo; |
336 | constexpr auto unknown = MemoryRegionInfo::eDontKnow; |
337 | |
338 | TEST_F(MinidumpParserTest, GetMemoryRegionInfo) { |
339 | ASSERT_THAT_ERROR(SetUpFromYaml(R"( |
340 | --- !minidump |
341 | Streams: |
342 | - Type: MemoryInfoList |
343 | Memory Ranges: |
344 | - Base Address: 0x0000000000000000 |
345 | Allocation Protect: [ ] |
346 | Region Size: 0x0000000000010000 |
347 | State: [ MEM_FREE ] |
348 | Protect: [ PAGE_NO_ACCESS ] |
349 | Type: [ ] |
350 | - Base Address: 0x0000000000010000 |
351 | Allocation Protect: [ PAGE_READ_WRITE ] |
352 | Region Size: 0x0000000000021000 |
353 | State: [ MEM_COMMIT ] |
354 | Type: [ MEM_MAPPED ] |
355 | - Base Address: 0x0000000000040000 |
356 | Allocation Protect: [ PAGE_EXECUTE_WRITE_COPY ] |
357 | Region Size: 0x0000000000001000 |
358 | State: [ MEM_COMMIT ] |
359 | Protect: [ PAGE_READ_ONLY ] |
360 | Type: [ MEM_IMAGE ] |
361 | - Base Address: 0x000000007FFE0000 |
362 | Allocation Protect: [ PAGE_READ_ONLY ] |
363 | Region Size: 0x0000000000001000 |
364 | State: [ MEM_COMMIT ] |
365 | Type: [ MEM_PRIVATE ] |
366 | - Base Address: 0x000000007FFE1000 |
367 | Allocation Base: 0x000000007FFE0000 |
368 | Allocation Protect: [ PAGE_READ_ONLY ] |
369 | Region Size: 0x000000000000F000 |
370 | State: [ MEM_RESERVE ] |
371 | Protect: [ PAGE_NO_ACCESS ] |
372 | Type: [ MEM_PRIVATE ] |
373 | ... |
374 | )" ), |
375 | llvm::Succeeded()); |
376 | |
377 | EXPECT_THAT( |
378 | parser->BuildMemoryRegions(), |
379 | testing::Pair( |
380 | testing::ElementsAre( |
381 | MemoryRegionInfo({0x0, 0x10000}, no, no, no, unknown, no, ConstString(), |
382 | unknown, 0, unknown, unknown), |
383 | MemoryRegionInfo({0x10000, 0x21000}, yes, yes, no, unknown, yes, |
384 | ConstString(), unknown, 0, unknown, unknown), |
385 | MemoryRegionInfo({0x40000, 0x1000}, yes, no, no, unknown, yes, |
386 | ConstString(), unknown, 0, unknown, unknown), |
387 | MemoryRegionInfo({0x7ffe0000, 0x1000}, yes, no, no, unknown, yes, |
388 | ConstString(), unknown, 0, unknown, unknown), |
389 | MemoryRegionInfo({0x7ffe1000, 0xf000}, no, no, no, unknown, yes, |
390 | ConstString(), unknown, 0, unknown, unknown)), |
391 | true)); |
392 | } |
393 | |
394 | TEST_F(MinidumpParserTest, GetMemoryRegionInfoFromMemoryList) { |
395 | ASSERT_THAT_ERROR(SetUpFromYaml(R"( |
396 | --- !minidump |
397 | Streams: |
398 | - Type: MemoryList |
399 | Memory Ranges: |
400 | - Start of Memory Range: 0x0000000000001000 |
401 | Content: '31313131313131313131313131313131' |
402 | - Start of Memory Range: 0x0000000000002000 |
403 | Content: '3333333333333333333333333333333333333333333333333333333333333333' |
404 | ... |
405 | )" ), |
406 | llvm::Succeeded()); |
407 | |
408 | // Test we can get memory regions from the MINIDUMP_MEMORY_LIST stream when |
409 | // we don't have a MemoryInfoListStream. |
410 | |
411 | EXPECT_THAT( |
412 | parser->BuildMemoryRegions(), |
413 | testing::Pair( |
414 | testing::ElementsAre( |
415 | MemoryRegionInfo({0x1000, 0x10}, yes, unknown, unknown, unknown, yes, |
416 | ConstString(), unknown, 0, unknown, unknown), |
417 | MemoryRegionInfo({0x2000, 0x20}, yes, unknown, unknown, unknown, yes, |
418 | ConstString(), unknown, 0, unknown, unknown)), |
419 | false)); |
420 | } |
421 | |
422 | TEST_F(MinidumpParserTest, GetMemoryRegionInfoFromMemory64List) { |
423 | SetUpData("regions-memlist64.dmp" ); |
424 | |
425 | // Test we can get memory regions from the MINIDUMP_MEMORY64_LIST stream when |
426 | // we don't have a MemoryInfoListStream. |
427 | EXPECT_THAT( |
428 | parser->BuildMemoryRegions(), |
429 | testing::Pair( |
430 | testing::ElementsAre( |
431 | MemoryRegionInfo({0x1000, 0x10}, yes, unknown, unknown, unknown, yes, |
432 | ConstString(), unknown, 0, unknown, unknown), |
433 | MemoryRegionInfo({0x2000, 0x20}, yes, unknown, unknown, unknown, yes, |
434 | ConstString(), unknown, 0, unknown, unknown)), |
435 | false)); |
436 | } |
437 | |
438 | TEST_F(MinidumpParserTest, GetMemoryRegionInfoLinuxMaps) { |
439 | ASSERT_THAT_ERROR(SetUpFromYaml(R"( |
440 | --- !minidump |
441 | Streams: |
442 | - Type: LinuxMaps |
443 | Text: | |
444 | 400d9000-400db000 r-xp 00000000 b3:04 227 /system/bin/app_process |
445 | 400db000-400dc000 r--p 00001000 b3:04 227 /system/bin/app_process |
446 | 400dc000-400dd000 rw-p 00000000 00:00 0 |
447 | 400ec000-400ed000 r--p 00000000 00:00 0 |
448 | 400ee000-400ef000 rw-p 00010000 b3:04 300 /system/bin/linker |
449 | 400fc000-400fd000 rwxp 00001000 b3:04 1096 /system/lib/liblog.so |
450 | |
451 | ... |
452 | )" ), |
453 | llvm::Succeeded()); |
454 | // Test we can get memory regions from the linux /proc/<pid>/maps stream when |
455 | // we don't have a MemoryInfoListStream. |
456 | ConstString app_process("/system/bin/app_process" ); |
457 | ConstString linker("/system/bin/linker" ); |
458 | ConstString liblog("/system/lib/liblog.so" ); |
459 | EXPECT_THAT( |
460 | parser->BuildMemoryRegions(), |
461 | testing::Pair( |
462 | testing::ElementsAre( |
463 | MemoryRegionInfo({0x400d9000, 0x2000}, yes, no, yes, no, yes, |
464 | app_process, unknown, 0, unknown, unknown), |
465 | MemoryRegionInfo({0x400db000, 0x1000}, yes, no, no, no, yes, |
466 | app_process, unknown, 0, unknown, unknown), |
467 | MemoryRegionInfo({0x400dc000, 0x1000}, yes, yes, no, no, yes, |
468 | ConstString(), unknown, 0, unknown, unknown), |
469 | MemoryRegionInfo({0x400ec000, 0x1000}, yes, no, no, no, yes, |
470 | ConstString(), unknown, 0, unknown, unknown), |
471 | MemoryRegionInfo({0x400ee000, 0x1000}, yes, yes, no, no, yes, linker, |
472 | unknown, 0, unknown, unknown), |
473 | MemoryRegionInfo({0x400fc000, 0x1000}, yes, yes, yes, no, yes, liblog, |
474 | unknown, 0, unknown, unknown)), |
475 | true)); |
476 | } |
477 | |
478 | TEST_F(MinidumpParserTest, GetMemoryRegionInfoLinuxMapsError) { |
479 | ASSERT_THAT_ERROR(SetUpFromYaml(R"( |
480 | --- !minidump |
481 | Streams: |
482 | - Type: LinuxMaps |
483 | Text: | |
484 | 400d9000-400db000 r?xp 00000000 b3:04 227 |
485 | 400fc000-400fd000 rwxp 00001000 b3:04 1096 |
486 | ... |
487 | )" ), |
488 | llvm::Succeeded()); |
489 | // Test that when a /proc/maps region fails to parse |
490 | // we handle the error and continue with the rest. |
491 | EXPECT_THAT( |
492 | parser->BuildMemoryRegions(), |
493 | testing::Pair(testing::ElementsAre(MemoryRegionInfo( |
494 | {0x400fc000, 0x1000}, yes, yes, yes, no, yes, |
495 | ConstString(nullptr), unknown, 0, unknown, unknown)), |
496 | true)); |
497 | } |
498 | |
499 | // Windows Minidump tests |
500 | TEST_F(MinidumpParserTest, GetArchitectureWindows) { |
501 | ASSERT_THAT_ERROR(SetUpFromYaml(R"( |
502 | --- !minidump |
503 | Streams: |
504 | - Type: SystemInfo |
505 | Processor Arch: X86 |
506 | Processor Level: 6 |
507 | Processor Revision: 15876 |
508 | Number of Processors: 32 |
509 | Product type: 1 |
510 | Major Version: 6 |
511 | Minor Version: 1 |
512 | Build Number: 7601 |
513 | Platform ID: Win32NT |
514 | CSD Version: Service Pack 1 |
515 | Suite Mask: 0x0100 |
516 | CPU: |
517 | Vendor ID: GenuineIntel |
518 | Version Info: 0x000306E4 |
519 | Feature Info: 0xBFEBFBFF |
520 | AMD Extended Features: 0x771EEC80 |
521 | ... |
522 | )" ), |
523 | llvm::Succeeded()); |
524 | ASSERT_EQ(llvm::Triple::ArchType::x86, |
525 | parser->GetArchitecture().GetMachine()); |
526 | ASSERT_EQ(llvm::Triple::OSType::Win32, |
527 | parser->GetArchitecture().GetTriple().getOS()); |
528 | } |
529 | |
530 | TEST_F(MinidumpParserTest, GetLinuxProcStatus_no_stream) { |
531 | // Test that GetLinuxProcStatus returns nullptr when the minidump does not |
532 | // contain this stream. |
533 | ASSERT_THAT_ERROR(SetUpFromYaml(R"( |
534 | --- !minidump |
535 | Streams: |
536 | ... |
537 | )" ), |
538 | llvm::Succeeded()); |
539 | EXPECT_EQ(std::nullopt, parser->GetLinuxProcStatus()); |
540 | } |
541 | |
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); |
549 | } |
550 | |
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); |
556 | } |
557 | |
558 | // wow64 |
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); |
564 | } |
565 | |
566 | // Register tests |
567 | #define REG_VAL32(x) *(reinterpret_cast<uint32_t *>(x)) |
568 | #define REG_VAL64(x) *(reinterpret_cast<uint64_t *>(x)) |
569 | |
570 | TEST_F(MinidumpParserTest, GetThreadContext_x86_32) { |
571 | ASSERT_THAT_ERROR(SetUpFromYaml(R"( |
572 | --- !minidump |
573 | Streams: |
574 | - Type: ThreadList |
575 | Threads: |
576 | - Thread Id: 0x00026804 |
577 | Stack: |
578 | Start of Memory Range: 0x00000000FF9DD000 |
579 | Content: 68D39DFF |
580 | Context: 0F0001000000000000000000000000000000000000000000000000007F03FFFF0000FFFFFFFFFFFF09DC62F72300000088E36CF72B00FFFF00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000063000000000000002B0000002B000000A88204085CD59DFF008077F7A3D49DFF01000000000000003CD59DFFA082040823000000820201002CD59DFF2B0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 |
581 | )" ), |
582 | llvm::Succeeded()); |
583 | |
584 | llvm::ArrayRef<minidump::Thread> thread_list = parser->GetThreads(); |
585 | const minidump::Thread &thread = thread_list[0]; |
586 | llvm::ArrayRef<uint8_t> registers(parser->GetThreadContext(td: thread)); |
587 | const MinidumpContext_x86_32 *context; |
588 | EXPECT_TRUE(consumeObject(registers, context).Success()); |
589 | |
590 | EXPECT_EQ(MinidumpContext_x86_32_Flags(uint32_t(context->context_flags)), |
591 | MinidumpContext_x86_32_Flags::x86_32_Flag | |
592 | MinidumpContext_x86_32_Flags::Full | |
593 | MinidumpContext_x86_32_Flags::FloatingPoint); |
594 | |
595 | EXPECT_EQ(0x00000000u, context->eax); |
596 | EXPECT_EQ(0xf7778000u, context->ebx); |
597 | EXPECT_EQ(0x00000001u, context->ecx); |
598 | EXPECT_EQ(0xff9dd4a3u, context->edx); |
599 | EXPECT_EQ(0x080482a8u, context->edi); |
600 | EXPECT_EQ(0xff9dd55cu, context->esi); |
601 | EXPECT_EQ(0xff9dd53cu, context->ebp); |
602 | EXPECT_EQ(0xff9dd52cu, context->esp); |
603 | EXPECT_EQ(0x080482a0u, context->eip); |
604 | EXPECT_EQ(0x00010282u, context->eflags); |
605 | EXPECT_EQ(0x0023u, context->cs); |
606 | EXPECT_EQ(0x0000u, context->fs); |
607 | EXPECT_EQ(0x0063u, context->gs); |
608 | EXPECT_EQ(0x002bu, context->ss); |
609 | EXPECT_EQ(0x002bu, context->ds); |
610 | EXPECT_EQ(0x002bu, context->es); |
611 | } |
612 | |
613 | TEST_F(MinidumpParserTest, GetThreadContext_x86_64) { |
614 | ASSERT_THAT_ERROR(SetUpFromYaml(R"( |
615 | --- !minidump |
616 | Streams: |
617 | - Type: ThreadList |
618 | Threads: |
619 | - Thread Id: 0x00003E81 |
620 | Stack: |
621 | Start of Memory Range: 0x00007FFCEB34A000 |
622 | Content: C84D04BCE97F00 |
623 | Context: 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000B0010000000000033000000000000000000000006020100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000010A234EBFC7F000010A234EBFC7F00000000000000000000F09C34EBFC7F0000C0A91ABCE97F00000000000000000000A0163FBCE97F00004602000000000000921C40000000000030A434EBFC7F000000000000000000000000000000000000C61D4000000000007F0300000000000000000000000000000000000000000000801F0000FFFF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FFFF00FFFFFFFFFFFFFF00FFFFFFFF25252525252525252525252525252525000000000000000000000000000000000000000000000000000000000000000000FFFF00FFFFFFFFFFFFFF00FFFFFFFF0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000FF00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 |
624 | ... |
625 | )" ), |
626 | llvm::Succeeded()); |
627 | llvm::ArrayRef<minidump::Thread> thread_list = parser->GetThreads(); |
628 | const minidump::Thread &thread = thread_list[0]; |
629 | llvm::ArrayRef<uint8_t> registers(parser->GetThreadContext(td: thread)); |
630 | const MinidumpContext_x86_64 *context; |
631 | EXPECT_TRUE(consumeObject(registers, context).Success()); |
632 | |
633 | EXPECT_EQ(MinidumpContext_x86_64_Flags(uint32_t(context->context_flags)), |
634 | MinidumpContext_x86_64_Flags::x86_64_Flag | |
635 | MinidumpContext_x86_64_Flags::Control | |
636 | MinidumpContext_x86_64_Flags::FloatingPoint | |
637 | MinidumpContext_x86_64_Flags::Integer); |
638 | EXPECT_EQ(0x0000000000000000u, context->rax); |
639 | EXPECT_EQ(0x0000000000000000u, context->rbx); |
640 | EXPECT_EQ(0x0000000000000010u, context->rcx); |
641 | EXPECT_EQ(0x0000000000000000u, context->rdx); |
642 | EXPECT_EQ(0x00007ffceb349cf0u, context->rdi); |
643 | EXPECT_EQ(0x0000000000000000u, context->rsi); |
644 | EXPECT_EQ(0x00007ffceb34a210u, context->rbp); |
645 | EXPECT_EQ(0x00007ffceb34a210u, context->rsp); |
646 | EXPECT_EQ(0x00007fe9bc1aa9c0u, context->r8); |
647 | EXPECT_EQ(0x0000000000000000u, context->r9); |
648 | EXPECT_EQ(0x00007fe9bc3f16a0u, context->r10); |
649 | EXPECT_EQ(0x0000000000000246u, context->r11); |
650 | EXPECT_EQ(0x0000000000401c92u, context->r12); |
651 | EXPECT_EQ(0x00007ffceb34a430u, context->r13); |
652 | EXPECT_EQ(0x0000000000000000u, context->r14); |
653 | EXPECT_EQ(0x0000000000000000u, context->r15); |
654 | EXPECT_EQ(0x0000000000401dc6u, context->rip); |
655 | EXPECT_EQ(0x00010206u, context->eflags); |
656 | EXPECT_EQ(0x0033u, context->cs); |
657 | EXPECT_EQ(0x0000u, context->ss); |
658 | } |
659 | |
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(td: thread)); |
665 | const MinidumpContext_x86_32 *context; |
666 | EXPECT_TRUE(consumeObject(registers, context).Success()); |
667 | |
668 | EXPECT_EQ(MinidumpContext_x86_32_Flags(uint32_t(context->context_flags)), |
669 | MinidumpContext_x86_32_Flags::x86_32_Flag | |
670 | MinidumpContext_x86_32_Flags::Full | |
671 | MinidumpContext_x86_32_Flags::FloatingPoint | |
672 | MinidumpContext_x86_32_Flags::ExtendedRegisters); |
673 | |
674 | EXPECT_EQ(0x00000000u, context->eax); |
675 | EXPECT_EQ(0x0037f608u, context->ebx); |
676 | EXPECT_EQ(0x00e61578u, context->ecx); |
677 | EXPECT_EQ(0x00000008u, context->edx); |
678 | EXPECT_EQ(0x00000000u, context->edi); |
679 | EXPECT_EQ(0x00000002u, context->esi); |
680 | EXPECT_EQ(0x0037f654u, context->ebp); |
681 | EXPECT_EQ(0x0037f5b8u, context->esp); |
682 | EXPECT_EQ(0x77ce01fdu, context->eip); |
683 | EXPECT_EQ(0x00000246u, context->eflags); |
684 | EXPECT_EQ(0x0023u, context->cs); |
685 | EXPECT_EQ(0x0053u, context->fs); |
686 | EXPECT_EQ(0x002bu, context->gs); |
687 | EXPECT_EQ(0x002bu, context->ss); |
688 | EXPECT_EQ(0x002bu, context->ds); |
689 | EXPECT_EQ(0x002bu, context->es); |
690 | } |
691 | |
692 | TEST_F(MinidumpParserTest, MinidumpDuplicateModuleMinAddress) { |
693 | ASSERT_THAT_ERROR(SetUpFromYaml(R"( |
694 | --- !minidump |
695 | Streams: |
696 | - Type: ModuleList |
697 | Modules: |
698 | - Base of Image: 0x0000000000002000 |
699 | Size of Image: 0x00001000 |
700 | Module Name: '/tmp/a' |
701 | CodeView Record: '' |
702 | - Base of Image: 0x0000000000001000 |
703 | Size of Image: 0x00001000 |
704 | Module Name: '/tmp/a' |
705 | CodeView Record: '' |
706 | ... |
707 | )" ), |
708 | llvm::Succeeded()); |
709 | // If we have a module mentioned twice in the module list, the filtered |
710 | // module list should contain the instance with the lowest BaseOfImage. |
711 | std::vector<const minidump::Module *> filtered_modules = |
712 | parser->GetFilteredModuleList(); |
713 | ASSERT_EQ(1u, filtered_modules.size()); |
714 | EXPECT_EQ(0x0000000000001000u, filtered_modules[0]->BaseOfImage); |
715 | } |
716 | |
717 | TEST_F(MinidumpParserTest, MinidumpDuplicateModuleMappedFirst) { |
718 | ASSERT_THAT_ERROR(SetUpFromYaml(R"( |
719 | --- !minidump |
720 | Streams: |
721 | - Type: ModuleList |
722 | Modules: |
723 | - Base of Image: 0x400d0000 |
724 | Size of Image: 0x00002000 |
725 | Module Name: '/usr/lib/libc.so' |
726 | CodeView Record: '' |
727 | - Base of Image: 0x400d3000 |
728 | Size of Image: 0x00001000 |
729 | Module Name: '/usr/lib/libc.so' |
730 | CodeView Record: '' |
731 | - Type: LinuxMaps |
732 | Text: | |
733 | 400d0000-400d2000 r--p 00000000 b3:04 227 /usr/lib/libc.so |
734 | 400d2000-400d3000 rw-p 00000000 00:00 0 |
735 | 400d3000-400d4000 r-xp 00010000 b3:04 227 /usr/lib/libc.so |
736 | 400d4000-400d5000 rwxp 00001000 b3:04 227 /usr/lib/libc.so |
737 | ... |
738 | )" ), |
739 | llvm::Succeeded()); |
740 | // If we have a module mentioned twice in the module list, and we have full |
741 | // linux maps for all of the memory regions, make sure we pick the one that |
742 | // has a consecutive region with a matching path that has executable |
743 | // permissions. If clients open an object file with mmap, breakpad can create |
744 | // multiple mappings for a library errnoneously and the lowest address isn't |
745 | // always the right address. In this case we check the consective memory |
746 | // regions whose path matches starting at the base of image address and make |
747 | // sure one of the regions is executable and prefer that one. |
748 | // |
749 | // This test will make sure that if the executable is second in the module |
750 | // list, that it will become the selected module in the filtered list. |
751 | std::vector<const minidump::Module *> filtered_modules = |
752 | parser->GetFilteredModuleList(); |
753 | ASSERT_EQ(1u, filtered_modules.size()); |
754 | EXPECT_EQ(0x400d3000u, filtered_modules[0]->BaseOfImage); |
755 | } |
756 | |
757 | TEST_F(MinidumpParserTest, MinidumpDuplicateModuleMappedSecond) { |
758 | ASSERT_THAT_ERROR(SetUpFromYaml(R"( |
759 | --- !minidump |
760 | Streams: |
761 | - Type: ModuleList |
762 | Modules: |
763 | - Base of Image: 0x400d0000 |
764 | Size of Image: 0x00002000 |
765 | Module Name: '/usr/lib/libc.so' |
766 | CodeView Record: '' |
767 | - Base of Image: 0x400d3000 |
768 | Size of Image: 0x00001000 |
769 | Module Name: '/usr/lib/libc.so' |
770 | CodeView Record: '' |
771 | - Type: LinuxMaps |
772 | Text: | |
773 | 400d0000-400d1000 r-xp 00010000 b3:04 227 /usr/lib/libc.so |
774 | 400d1000-400d2000 rwxp 00001000 b3:04 227 /usr/lib/libc.so |
775 | 400d2000-400d3000 rw-p 00000000 00:00 0 |
776 | 400d3000-400d5000 r--p 00000000 b3:04 227 /usr/lib/libc.so |
777 | ... |
778 | )" ), |
779 | llvm::Succeeded()); |
780 | // If we have a module mentioned twice in the module list, and we have full |
781 | // linux maps for all of the memory regions, make sure we pick the one that |
782 | // has a consecutive region with a matching path that has executable |
783 | // permissions. If clients open an object file with mmap, breakpad can create |
784 | // multiple mappings for a library errnoneously and the lowest address isn't |
785 | // always the right address. In this case we check the consective memory |
786 | // regions whose path matches starting at the base of image address and make |
787 | // sure one of the regions is executable and prefer that one. |
788 | // |
789 | // This test will make sure that if the executable is first in the module |
790 | // list, that it will remain the correctly selected module in the filtered |
791 | // list. |
792 | std::vector<const minidump::Module *> filtered_modules = |
793 | parser->GetFilteredModuleList(); |
794 | ASSERT_EQ(1u, filtered_modules.size()); |
795 | EXPECT_EQ(0x400d0000u, filtered_modules[0]->BaseOfImage); |
796 | } |
797 | |
798 | TEST_F(MinidumpParserTest, MinidumpDuplicateModuleMappedSecondHigh) { |
799 | ASSERT_THAT_ERROR(SetUpFromYaml(R"( |
800 | --- !minidump |
801 | Streams: |
802 | - Type: ModuleList |
803 | Modules: |
804 | - Base of Image: 0x400d3000 |
805 | Size of Image: 0x00002000 |
806 | Module Name: '/usr/lib/libc.so' |
807 | CodeView Record: '' |
808 | - Base of Image: 0x400d0000 |
809 | Size of Image: 0x00001000 |
810 | Module Name: '/usr/lib/libc.so' |
811 | CodeView Record: '' |
812 | - Type: LinuxMaps |
813 | Text: | |
814 | 400d0000-400d2000 r--p 00000000 b3:04 227 /usr/lib/libc.so |
815 | 400d2000-400d3000 rw-p 00000000 00:00 0 |
816 | 400d3000-400d4000 r-xp 00010000 b3:04 227 /usr/lib/libc.so |
817 | 400d4000-400d5000 rwxp 00001000 b3:04 227 /usr/lib/libc.so |
818 | ... |
819 | )" ), |
820 | llvm::Succeeded()); |
821 | // If we have a module mentioned twice in the module list, and we have full |
822 | // linux maps for all of the memory regions, make sure we pick the one that |
823 | // has a consecutive region with a matching path that has executable |
824 | // permissions. If clients open an object file with mmap, breakpad can create |
825 | // multiple mappings for a library errnoneously and the lowest address isn't |
826 | // always the right address. In this case we check the consective memory |
827 | // regions whose path matches starting at the base of image address and make |
828 | // sure one of the regions is executable and prefer that one. |
829 | // |
830 | // This test will make sure that if the executable is first in the module |
831 | // list, that it will remain the correctly selected module in the filtered |
832 | // list, even if the non-executable module was loaded at a lower base address. |
833 | std::vector<const minidump::Module *> filtered_modules = |
834 | parser->GetFilteredModuleList(); |
835 | ASSERT_EQ(1u, filtered_modules.size()); |
836 | EXPECT_EQ(0x400d3000u, filtered_modules[0]->BaseOfImage); |
837 | } |
838 | |
839 | TEST_F(MinidumpParserTest, MinidumpDuplicateModuleSeparateCode) { |
840 | ASSERT_THAT_ERROR(SetUpFromYaml(R"( |
841 | --- !minidump |
842 | Streams: |
843 | - Type: ModuleList |
844 | Modules: |
845 | - Base of Image: 0x400d0000 |
846 | Size of Image: 0x00002000 |
847 | Module Name: '/usr/lib/libc.so' |
848 | CodeView Record: '' |
849 | - Base of Image: 0x400d5000 |
850 | Size of Image: 0x00001000 |
851 | Module Name: '/usr/lib/libc.so' |
852 | CodeView Record: '' |
853 | - Type: LinuxMaps |
854 | Text: | |
855 | 400d0000-400d3000 r--p 00000000 b3:04 227 /usr/lib/libc.so |
856 | 400d3000-400d5000 rw-p 00000000 00:00 0 |
857 | 400d5000-400d6000 r--p 00000000 b3:04 227 /usr/lib/libc.so |
858 | 400d6000-400d7000 r-xp 00010000 b3:04 227 /usr/lib/libc.so |
859 | 400d7000-400d8000 rwxp 00001000 b3:04 227 /usr/lib/libc.so |
860 | ... |
861 | )" ), |
862 | llvm::Succeeded()); |
863 | // If we have a module mentioned twice in the module list, and we have full |
864 | // linux maps for all of the memory regions, make sure we pick the one that |
865 | // has a consecutive region with a matching path that has executable |
866 | // permissions. If clients open an object file with mmap, breakpad can create |
867 | // multiple mappings for a library errnoneously and the lowest address isn't |
868 | // always the right address. In this case we check the consective memory |
869 | // regions whose path matches starting at the base of image address and make |
870 | // sure one of the regions is executable and prefer that one. |
871 | // |
872 | // This test will make sure if binaries are compiled with "-z separate-code", |
873 | // where the first region for a binary won't be marked as executable, that |
874 | // it gets selected by detecting the second consecutive mapping at 0x400d7000 |
875 | // when asked about the a module mamed "/usr/lib/libc.so" at 0x400d5000. |
876 | std::vector<const minidump::Module *> filtered_modules = |
877 | parser->GetFilteredModuleList(); |
878 | ASSERT_EQ(1u, filtered_modules.size()); |
879 | EXPECT_EQ(0x400d5000u, filtered_modules[0]->BaseOfImage); |
880 | } |
881 | |
882 | TEST_F(MinidumpParserTest, MinidumpModuleOrder) { |
883 | ASSERT_THAT_ERROR(SetUpFromYaml(R"( |
884 | --- !minidump |
885 | Streams: |
886 | - Type: ModuleList |
887 | Modules: |
888 | - Base of Image: 0x0000000000002000 |
889 | Size of Image: 0x00001000 |
890 | Module Name: '/tmp/a' |
891 | CodeView Record: '' |
892 | - Base of Image: 0x0000000000001000 |
893 | Size of Image: 0x00001000 |
894 | Module Name: '/tmp/b' |
895 | CodeView Record: '' |
896 | ... |
897 | )" ), |
898 | llvm::Succeeded()); |
899 | // Test module filtering does not affect the overall module order. Previous |
900 | // versions of the MinidumpParser::GetFilteredModuleList() function would sort |
901 | // all images by address and modify the order of the modules. |
902 | std::vector<const minidump::Module *> filtered_modules = |
903 | parser->GetFilteredModuleList(); |
904 | ASSERT_EQ(2u, filtered_modules.size()); |
905 | EXPECT_EQ(0x0000000000002000u, filtered_modules[0]->BaseOfImage); |
906 | EXPECT_THAT_EXPECTED( |
907 | parser->GetMinidumpFile().getString(filtered_modules[0]->ModuleNameRVA), |
908 | llvm::HasValue("/tmp/a" )); |
909 | EXPECT_EQ(0x0000000000001000u, filtered_modules[1]->BaseOfImage); |
910 | EXPECT_THAT_EXPECTED( |
911 | parser->GetMinidumpFile().getString(filtered_modules[1]->ModuleNameRVA), |
912 | llvm::HasValue("/tmp/b" )); |
913 | } |
914 | |