Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1258)

Side by Side Diff: minidump/minidump_thread_writer_test.cc

Issue 637503006: Add MinidumpThreadWriter, MinidumpThreadListWriter, and their test (Closed) Base URL: https://chromium.googlesource.com/crashpad/crashpad@minidump_memory_writer_test_util
Patch Set: Address review feedback Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « minidump/minidump_thread_writer.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2014 The Crashpad Authors. All rights reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "minidump/minidump_thread_writer.h"
16
17 #include <dbghelp.h>
18
19 #include "gtest/gtest.h"
20 #include "minidump/minidump_context_test_util.h"
21 #include "minidump/minidump_context_writer.h"
22 #include "minidump/minidump_memory_writer.h"
23 #include "minidump/minidump_memory_writer_test_util.h"
24 #include "minidump/minidump_file_writer.h"
25 #include "minidump/minidump_test_util.h"
26 #include "util/file/string_file_writer.h"
27
28 namespace crashpad {
29 namespace test {
30 namespace {
31
32 // This returns the MINIDUMP_THREAD_LIST stream in |thread_list|. If
33 // |memory_list| is non-NULL, a MINIDUMP_MEMORY_LIST stream is also expected in
34 // |file_contents|, and that stream will be returned in |memory_list|.
35 void GetThreadListStream(const std::string& file_contents,
36 const MINIDUMP_THREAD_LIST** thread_list,
37 const MINIDUMP_MEMORY_LIST** memory_list) {
38 const size_t kDirectoryOffset = sizeof(MINIDUMP_HEADER);
39 const uint32_t kExpectedStreams = memory_list ? 2 : 1;
40 const size_t kThreadListStreamOffset =
41 kDirectoryOffset + kExpectedStreams * sizeof(MINIDUMP_DIRECTORY);
42 const size_t kThreadsOffset =
43 kThreadListStreamOffset + sizeof(MINIDUMP_THREAD_LIST);
44
45 ASSERT_GE(file_contents.size(), kThreadsOffset);
46
47 const MINIDUMP_HEADER* header =
48 reinterpret_cast<const MINIDUMP_HEADER*>(&file_contents[0]);
49
50 ASSERT_NO_FATAL_FAILURE(VerifyMinidumpHeader(header, kExpectedStreams, 0));
51
52 const MINIDUMP_DIRECTORY* directory =
53 reinterpret_cast<const MINIDUMP_DIRECTORY*>(
54 &file_contents[kDirectoryOffset]);
55
56 ASSERT_EQ(kMinidumpStreamTypeThreadList, directory[0].StreamType);
57 ASSERT_GE(directory[0].Location.DataSize, sizeof(MINIDUMP_THREAD_LIST));
58 ASSERT_EQ(kThreadListStreamOffset, directory[0].Location.Rva);
59
60 *thread_list = reinterpret_cast<const MINIDUMP_THREAD_LIST*>(
61 &file_contents[kThreadListStreamOffset]);
62
63 ASSERT_EQ(sizeof(MINIDUMP_THREAD_LIST) +
64 (*thread_list)->NumberOfThreads * sizeof(MINIDUMP_THREAD),
65 directory[0].Location.DataSize);
66
67 if (memory_list) {
68 *memory_list = reinterpret_cast<const MINIDUMP_MEMORY_LIST*>(
69 &file_contents[directory[1].Location.Rva]);
70 }
71 }
72
73 TEST(MinidumpThreadWriter, EmptyThreadList) {
74 MinidumpFileWriter minidump_file_writer;
75 MinidumpThreadListWriter thread_list_writer;
76
77 minidump_file_writer.AddStream(&thread_list_writer);
78
79 StringFileWriter file_writer;
80 ASSERT_TRUE(minidump_file_writer.WriteEverything(&file_writer));
81
82 ASSERT_EQ(sizeof(MINIDUMP_HEADER) + sizeof(MINIDUMP_DIRECTORY) +
83 sizeof(MINIDUMP_THREAD_LIST),
84 file_writer.string().size());
85
86 const MINIDUMP_THREAD_LIST* thread_list;
87 ASSERT_NO_FATAL_FAILURE(
88 GetThreadListStream(file_writer.string(), &thread_list, NULL));
89
90 EXPECT_EQ(0u, thread_list->NumberOfThreads);
91 }
92
93 // The MINIDUMP_THREADs |expected| and |observed| are compared against each
94 // other using gtest assertions. If |stack| is non-NULL, |observed| is expected
95 // to contain a populated MINIDUMP_MEMORY_DESCRIPTOR in its Stack field,
96 // otherwise, its Stack field is expected to be zeroed out. The memory
97 // descriptor will be placed in |stack|. |observed| must contain a populated
98 // ThreadContext field. The context will be recovered from |file_contents| and
99 // stored in |context_base|.
100 void ExpectThread(const MINIDUMP_THREAD* expected,
101 const MINIDUMP_THREAD* observed,
102 const std::string& file_contents,
103 const MINIDUMP_MEMORY_DESCRIPTOR** stack,
104 const void** context_base) {
105 EXPECT_EQ(expected->ThreadId, observed->ThreadId);
106 EXPECT_EQ(expected->SuspendCount, observed->SuspendCount);
107 EXPECT_EQ(expected->PriorityClass, observed->PriorityClass);
108 EXPECT_EQ(expected->Priority, observed->Priority);
109 EXPECT_EQ(expected->Teb, observed->Teb);
110
111 EXPECT_EQ(expected->Stack.StartOfMemoryRange,
112 observed->Stack.StartOfMemoryRange);
113 EXPECT_EQ(expected->Stack.Memory.DataSize, observed->Stack.Memory.DataSize);
114 if (stack) {
115 ASSERT_NE(0u, observed->Stack.Memory.DataSize);
116 ASSERT_NE(0u, observed->Stack.Memory.Rva);
117 ASSERT_GE(file_contents.size(),
118 observed->Stack.Memory.Rva + observed->Stack.Memory.DataSize);
119 *stack = &observed->Stack;
120 } else {
121 EXPECT_EQ(0u, observed->Stack.StartOfMemoryRange);
122 EXPECT_EQ(0u, observed->Stack.Memory.DataSize);
123 EXPECT_EQ(0u, observed->Stack.Memory.Rva);
124 }
125
126 EXPECT_EQ(expected->ThreadContext.DataSize, observed->ThreadContext.DataSize);
127 ASSERT_NE(0u, observed->ThreadContext.DataSize);
128 ASSERT_NE(0u, observed->ThreadContext.Rva);
129 ASSERT_GE(file_contents.size(),
130 observed->ThreadContext.Rva + expected->ThreadContext.DataSize);
131 *context_base = &file_contents[observed->ThreadContext.Rva];
132 }
133
134 TEST(MinidumpThreadWriter, OneThread_x86_NoStack) {
135 MinidumpFileWriter minidump_file_writer;
136 MinidumpThreadListWriter thread_list_writer;
137
138 const uint32_t kThreadID = 0x11111111;
139 const uint32_t kSuspendCount = 1;
140 const uint32_t kPriorityClass = 0x20;
141 const uint32_t kPriority = 10;
142 const uint64_t kTEB = 0x55555555;
143 const uint32_t kSeed = 123;
144
145 MinidumpThreadWriter thread_writer;
146 thread_writer.SetThreadID(kThreadID);
147 thread_writer.SetSuspendCount(kSuspendCount);
148 thread_writer.SetPriorityClass(kPriorityClass);
149 thread_writer.SetPriority(kPriority);
150 thread_writer.SetTEB(kTEB);
151
152 MinidumpContextX86Writer context_x86_writer;
153 InitializeMinidumpContextX86(context_x86_writer.context(), kSeed);
154 thread_writer.SetContext(&context_x86_writer);
155
156 thread_list_writer.AddThread(&thread_writer);
157 minidump_file_writer.AddStream(&thread_list_writer);
158
159 StringFileWriter file_writer;
160 ASSERT_TRUE(minidump_file_writer.WriteEverything(&file_writer));
161
162 ASSERT_EQ(sizeof(MINIDUMP_HEADER) + sizeof(MINIDUMP_DIRECTORY) +
163 sizeof(MINIDUMP_THREAD_LIST) + 1 * sizeof(MINIDUMP_THREAD) +
164 1 * sizeof(MinidumpContextX86),
165 file_writer.string().size());
166
167 const MINIDUMP_THREAD_LIST* thread_list;
168 ASSERT_NO_FATAL_FAILURE(
169 GetThreadListStream(file_writer.string(), &thread_list, NULL));
170
171 EXPECT_EQ(1u, thread_list->NumberOfThreads);
172
173 MINIDUMP_THREAD expected = {};
174 expected.ThreadId = kThreadID;
175 expected.SuspendCount = kSuspendCount;
176 expected.PriorityClass = kPriorityClass;
177 expected.Priority = kPriority;
178 expected.Teb = kTEB;
179 expected.ThreadContext.DataSize = sizeof(MinidumpContextX86);
180
181 const MinidumpContextX86* observed_context;
182 ASSERT_NO_FATAL_FAILURE(
183 ExpectThread(&expected,
184 &thread_list->Threads[0],
185 file_writer.string(),
186 NULL,
187 reinterpret_cast<const void**>(&observed_context)));
188
189 ASSERT_NO_FATAL_FAILURE(ExpectMinidumpContextX86(kSeed, observed_context));
190 }
191
192 TEST(MinidumpThreadWriter, OneThread_AMD64_Stack) {
193 MinidumpFileWriter minidump_file_writer;
194 MinidumpThreadListWriter thread_list_writer;
195
196 const uint32_t kThreadID = 0x22222222;
197 const uint32_t kSuspendCount = 2;
198 const uint32_t kPriorityClass = 0x30;
199 const uint32_t kPriority = 20;
200 const uint64_t kTEB = 0x5555555555555555;
201 const uint64_t kMemoryBase = 0x765432100000;
202 const size_t kMemorySize = 32;
203 const uint8_t kMemoryValue = 99;
204 const uint32_t kSeed = 456;
205
206 MinidumpThreadWriter thread_writer;
207 thread_writer.SetThreadID(kThreadID);
208 thread_writer.SetSuspendCount(kSuspendCount);
209 thread_writer.SetPriorityClass(kPriorityClass);
210 thread_writer.SetPriority(kPriority);
211 thread_writer.SetTEB(kTEB);
212
213 TestMinidumpMemoryWriter memory_writer(
214 kMemoryBase, kMemorySize, kMemoryValue);
215 thread_writer.SetStack(&memory_writer);
216
217 MinidumpContextAMD64Writer context_amd64_writer;
218 InitializeMinidumpContextAMD64(context_amd64_writer.context(), kSeed);
219 thread_writer.SetContext(&context_amd64_writer);
220
221 thread_list_writer.AddThread(&thread_writer);
222 minidump_file_writer.AddStream(&thread_list_writer);
223
224 StringFileWriter file_writer;
225 ASSERT_TRUE(minidump_file_writer.WriteEverything(&file_writer));
226
227 ASSERT_EQ(sizeof(MINIDUMP_HEADER) + sizeof(MINIDUMP_DIRECTORY) +
228 sizeof(MINIDUMP_THREAD_LIST) + 1 * sizeof(MINIDUMP_THREAD) +
229 1 * sizeof(MinidumpContextAMD64) + kMemorySize,
230 file_writer.string().size());
231
232 const MINIDUMP_THREAD_LIST* thread_list;
233 ASSERT_NO_FATAL_FAILURE(
234 GetThreadListStream(file_writer.string(), &thread_list, NULL));
235
236 EXPECT_EQ(1u, thread_list->NumberOfThreads);
237
238 MINIDUMP_THREAD expected = {};
239 expected.ThreadId = kThreadID;
240 expected.SuspendCount = kSuspendCount;
241 expected.PriorityClass = kPriorityClass;
242 expected.Priority = kPriority;
243 expected.Teb = kTEB;
244 expected.Stack.StartOfMemoryRange = kMemoryBase;
245 expected.Stack.Memory.DataSize = kMemorySize;
246 expected.ThreadContext.DataSize = sizeof(MinidumpContextAMD64);
247
248 const MINIDUMP_MEMORY_DESCRIPTOR* observed_stack;
249 const MinidumpContextAMD64* observed_context;
250 ASSERT_NO_FATAL_FAILURE(
251 ExpectThread(&expected,
252 &thread_list->Threads[0],
253 file_writer.string(),
254 &observed_stack,
255 reinterpret_cast<const void**>(&observed_context)));
256
257 ASSERT_NO_FATAL_FAILURE(
258 ExpectMinidumpMemoryDescriptorAndContents(&expected.Stack,
259 observed_stack,
260 file_writer.string(),
261 kMemoryValue,
262 true));
263 ASSERT_NO_FATAL_FAILURE(ExpectMinidumpContextAMD64(kSeed, observed_context));
264 }
265
266 TEST(MinidumpThreadWriter, ThreeThreads_x86_MemoryList) {
267 MinidumpFileWriter minidump_file_writer;
268 MinidumpThreadListWriter thread_list_writer;
269 MinidumpMemoryListWriter memory_list_writer;
270 thread_list_writer.SetMemoryListWriter(&memory_list_writer);
271
272 const uint32_t kThreadID0 = 1111111;
273 const uint32_t kSuspendCount0 = 111111;
274 const uint32_t kPriorityClass0 = 11111;
275 const uint32_t kPriority0 = 1111;
276 const uint64_t kTEB0 = 111;
277 const uint64_t kMemoryBase0 = 0x1110;
278 const size_t kMemorySize0 = 16;
279 const uint8_t kMemoryValue0 = 11;
280 const uint32_t kSeed0 = 1;
281
282 MinidumpThreadWriter thread_writer_0;
283 thread_writer_0.SetThreadID(kThreadID0);
284 thread_writer_0.SetSuspendCount(kSuspendCount0);
285 thread_writer_0.SetPriorityClass(kPriorityClass0);
286 thread_writer_0.SetPriority(kPriority0);
287 thread_writer_0.SetTEB(kTEB0);
288
289 TestMinidumpMemoryWriter memory_writer_0(
290 kMemoryBase0, kMemorySize0, kMemoryValue0);
291 thread_writer_0.SetStack(&memory_writer_0);
292
293 MinidumpContextX86Writer context_x86_writer_0;
294 InitializeMinidumpContextX86(context_x86_writer_0.context(), kSeed0);
295 thread_writer_0.SetContext(&context_x86_writer_0);
296
297 thread_list_writer.AddThread(&thread_writer_0);
298
299 const uint32_t kThreadID1 = 2222222;
300 const uint32_t kSuspendCount1 = 222222;
301 const uint32_t kPriorityClass1 = 22222;
302 const uint32_t kPriority1 = 2222;
303 const uint64_t kTEB1 = 222;
304 const uint64_t kMemoryBase1 = 0x2220;
305 const size_t kMemorySize1 = 32;
306 const uint8_t kMemoryValue1 = 22;
307 const uint32_t kSeed1 = 2;
308
309 MinidumpThreadWriter thread_writer_1;
310 thread_writer_1.SetThreadID(kThreadID1);
311 thread_writer_1.SetSuspendCount(kSuspendCount1);
312 thread_writer_1.SetPriorityClass(kPriorityClass1);
313 thread_writer_1.SetPriority(kPriority1);
314 thread_writer_1.SetTEB(kTEB1);
315
316 TestMinidumpMemoryWriter memory_writer_1(
317 kMemoryBase1, kMemorySize1, kMemoryValue1);
318 thread_writer_1.SetStack(&memory_writer_1);
319
320 MinidumpContextX86Writer context_x86_writer_1;
321 InitializeMinidumpContextX86(context_x86_writer_1.context(), kSeed1);
322 thread_writer_1.SetContext(&context_x86_writer_1);
323
324 thread_list_writer.AddThread(&thread_writer_1);
325
326 const uint32_t kThreadID2 = 3333333;
327 const uint32_t kSuspendCount2 = 333333;
328 const uint32_t kPriorityClass2 = 33333;
329 const uint32_t kPriority2 = 3333;
330 const uint64_t kTEB2 = 333;
331 const uint64_t kMemoryBase2 = 0x3330;
332 const size_t kMemorySize2 = 48;
333 const uint8_t kMemoryValue2 = 33;
334 const uint32_t kSeed2 = 3;
335
336 MinidumpThreadWriter thread_writer_2;
337 thread_writer_2.SetThreadID(kThreadID2);
338 thread_writer_2.SetSuspendCount(kSuspendCount2);
339 thread_writer_2.SetPriorityClass(kPriorityClass2);
340 thread_writer_2.SetPriority(kPriority2);
341 thread_writer_2.SetTEB(kTEB2);
342
343 TestMinidumpMemoryWriter memory_writer_2(
344 kMemoryBase2, kMemorySize2, kMemoryValue2);
345 thread_writer_2.SetStack(&memory_writer_2);
346
347 MinidumpContextX86Writer context_x86_writer_2;
348 InitializeMinidumpContextX86(context_x86_writer_2.context(), kSeed2);
349 thread_writer_2.SetContext(&context_x86_writer_2);
350
351 thread_list_writer.AddThread(&thread_writer_2);
352
353 minidump_file_writer.AddStream(&thread_list_writer);
354 minidump_file_writer.AddStream(&memory_list_writer);
355
356 StringFileWriter file_writer;
357 ASSERT_TRUE(minidump_file_writer.WriteEverything(&file_writer));
358
359 ASSERT_EQ(sizeof(MINIDUMP_HEADER) + 2 * sizeof(MINIDUMP_DIRECTORY) +
360 sizeof(MINIDUMP_THREAD_LIST) + 3 * sizeof(MINIDUMP_THREAD) +
361 sizeof(MINIDUMP_MEMORY_LIST) +
362 3 * sizeof(MINIDUMP_MEMORY_DESCRIPTOR) +
363 3 * sizeof(MinidumpContextX86) + kMemorySize0 + kMemorySize1 +
364 kMemorySize2 + 12, // 12 for alignment
365 file_writer.string().size());
366
367 const MINIDUMP_THREAD_LIST* thread_list;
368 const MINIDUMP_MEMORY_LIST* memory_list;
369 ASSERT_NO_FATAL_FAILURE(
370 GetThreadListStream(file_writer.string(), &thread_list, &memory_list));
371
372 EXPECT_EQ(3u, thread_list->NumberOfThreads);
373 EXPECT_EQ(3u, memory_list->NumberOfMemoryRanges);
374
375 {
376 SCOPED_TRACE("thread 0");
377
378 MINIDUMP_THREAD expected = {};
379 expected.ThreadId = kThreadID0;
380 expected.SuspendCount = kSuspendCount0;
381 expected.PriorityClass = kPriorityClass0;
382 expected.Priority = kPriority0;
383 expected.Teb = kTEB0;
384 expected.Stack.StartOfMemoryRange = kMemoryBase0;
385 expected.Stack.Memory.DataSize = kMemorySize0;
386 expected.ThreadContext.DataSize = sizeof(MinidumpContextX86);
387
388 const MINIDUMP_MEMORY_DESCRIPTOR* observed_stack;
389 const MinidumpContextX86* observed_context;
390 ASSERT_NO_FATAL_FAILURE(
391 ExpectThread(&expected,
392 &thread_list->Threads[0],
393 file_writer.string(),
394 &observed_stack,
395 reinterpret_cast<const void**>(&observed_context)));
396
397 ASSERT_NO_FATAL_FAILURE(
398 ExpectMinidumpMemoryDescriptorAndContents(&expected.Stack,
399 observed_stack,
400 file_writer.string(),
401 kMemoryValue0,
402 false));
403 ASSERT_NO_FATAL_FAILURE(ExpectMinidumpContextX86(kSeed0, observed_context));
404 ASSERT_NO_FATAL_FAILURE(ExpectMinidumpMemoryDescriptor(
405 observed_stack, &memory_list->MemoryRanges[0]));
406 }
407
408 {
409 SCOPED_TRACE("thread 1");
410
411 MINIDUMP_THREAD expected = {};
412 expected.ThreadId = kThreadID1;
413 expected.SuspendCount = kSuspendCount1;
414 expected.PriorityClass = kPriorityClass1;
415 expected.Priority = kPriority1;
416 expected.Teb = kTEB1;
417 expected.Stack.StartOfMemoryRange = kMemoryBase1;
418 expected.Stack.Memory.DataSize = kMemorySize1;
419 expected.ThreadContext.DataSize = sizeof(MinidumpContextX86);
420
421 const MINIDUMP_MEMORY_DESCRIPTOR* observed_stack;
422 const MinidumpContextX86* observed_context;
423 ASSERT_NO_FATAL_FAILURE(
424 ExpectThread(&expected,
425 &thread_list->Threads[1],
426 file_writer.string(),
427 &observed_stack,
428 reinterpret_cast<const void**>(&observed_context)));
429
430 ASSERT_NO_FATAL_FAILURE(
431 ExpectMinidumpMemoryDescriptorAndContents(&expected.Stack,
432 observed_stack,
433 file_writer.string(),
434 kMemoryValue1,
435 false));
436 ASSERT_NO_FATAL_FAILURE(ExpectMinidumpContextX86(kSeed1, observed_context));
437 ASSERT_NO_FATAL_FAILURE(ExpectMinidumpMemoryDescriptor(
438 observed_stack, &memory_list->MemoryRanges[1]));
439 }
440
441 {
442 SCOPED_TRACE("thread 2");
443
444 MINIDUMP_THREAD expected = {};
445 expected.ThreadId = kThreadID2;
446 expected.SuspendCount = kSuspendCount2;
447 expected.PriorityClass = kPriorityClass2;
448 expected.Priority = kPriority2;
449 expected.Teb = kTEB2;
450 expected.Stack.StartOfMemoryRange = kMemoryBase2;
451 expected.Stack.Memory.DataSize = kMemorySize2;
452 expected.ThreadContext.DataSize = sizeof(MinidumpContextX86);
453
454 const MINIDUMP_MEMORY_DESCRIPTOR* observed_stack;
455 const MinidumpContextX86* observed_context;
456 ASSERT_NO_FATAL_FAILURE(
457 ExpectThread(&expected,
458 &thread_list->Threads[2],
459 file_writer.string(),
460 &observed_stack,
461 reinterpret_cast<const void**>(&observed_context)));
462
463 ASSERT_NO_FATAL_FAILURE(
464 ExpectMinidumpMemoryDescriptorAndContents(&expected.Stack,
465 observed_stack,
466 file_writer.string(),
467 kMemoryValue2,
468 true));
469 ASSERT_NO_FATAL_FAILURE(ExpectMinidumpContextX86(kSeed2, observed_context));
470 ASSERT_NO_FATAL_FAILURE(ExpectMinidumpMemoryDescriptor(
471 observed_stack, &memory_list->MemoryRanges[2]));
472 }
473 }
474
475 TEST(MinidumpThreadWriterDeathTest, NoContext) {
476 MinidumpFileWriter minidump_file_writer;
477 MinidumpThreadListWriter thread_list_writer;
478
479 MinidumpThreadWriter thread_writer;
480
481 thread_list_writer.AddThread(&thread_writer);
482 minidump_file_writer.AddStream(&thread_list_writer);
483
484 StringFileWriter file_writer;
485 ASSERT_DEATH(minidump_file_writer.WriteEverything(&file_writer), "context_");
486 }
487
488 } // namespace
489 } // namespace test
490 } // namespace crashpad
OLDNEW
« no previous file with comments | « minidump/minidump_thread_writer.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698