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