1 // Copyright (c) 2010, Google Inc.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 //     * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 //     * Redistributions in binary form must reproduce the above
11 // copyright notice, this list of conditions and the following disclaimer
12 // in the documentation and/or other materials provided with the
13 // distribution.
14 //     * Neither the name of Google Inc. nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 
30 // Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
31 
32 // synth_minidump.cc: Implementation of SynthMinidump.  See synth_minidump.h
33 
34 #include "processor/synth_minidump.h"
35 
36 namespace google_breakpad {
37 
38 namespace SynthMinidump {
39 
Section(const Dump & dump)40 Section::Section(const Dump &dump)
41   : test_assembler::Section(dump.endianness()) { }
42 
CiteLocationIn(test_assembler::Section * section) const43 void Section::CiteLocationIn(test_assembler::Section *section) const {
44   (*section).D32(size_).D32(file_offset_);
45 }
46 
CiteStreamIn(test_assembler::Section * section) const47 void Stream::CiteStreamIn(test_assembler::Section *section) const {
48   section->D32(type_);
49   CiteLocationIn(section);
50 }
51 
SystemInfo(const Dump & dump,const MDRawSystemInfo & system_info,const String & csd_version)52 SystemInfo::SystemInfo(const Dump &dump,
53                        const MDRawSystemInfo &system_info,
54                        const String &csd_version)
55     : Stream(dump, MD_SYSTEM_INFO_STREAM) {
56   D16(system_info.processor_architecture);
57   D16(system_info.processor_level);
58   D16(system_info.processor_revision);
59   D8(system_info.number_of_processors);
60   D8(system_info.product_type);
61   D32(system_info.major_version);
62   D32(system_info.minor_version);
63   D32(system_info.build_number);
64   D32(system_info.platform_id);
65   csd_version.CiteStringIn(this);
66   D16(system_info.suite_mask);
67   D16(system_info.reserved2);           // Well, why not?
68 
69   // MDCPUInformation cpu;
70   if (system_info.processor_architecture == MD_CPU_ARCHITECTURE_X86) {
71     D32(system_info.cpu.x86_cpu_info.vendor_id[0]);
72     D32(system_info.cpu.x86_cpu_info.vendor_id[1]);
73     D32(system_info.cpu.x86_cpu_info.vendor_id[2]);
74     D32(system_info.cpu.x86_cpu_info.version_information);
75     D32(system_info.cpu.x86_cpu_info.feature_information);
76     D32(system_info.cpu.x86_cpu_info.amd_extended_cpu_features);
77   } else if (system_info.processor_architecture == MD_CPU_ARCHITECTURE_ARM) {
78     D32(system_info.cpu.arm_cpu_info.cpuid);
79     D32(system_info.cpu.arm_cpu_info.elf_hwcaps);
80   } else {
81     D64(system_info.cpu.other_cpu_info.processor_features[0]);
82     D64(system_info.cpu.other_cpu_info.processor_features[1]);
83   }
84 }
85 
86 const MDRawSystemInfo SystemInfo::windows_x86 = {
87   MD_CPU_ARCHITECTURE_X86,              // processor_architecture
88   6,                                    // processor_level
89   0xd08,                                // processor_revision
90   1,                                    // number_of_processors
91   1,                                    // product_type
92   5,                                    // major_version
93   1,                                    // minor_version
94   2600,                                 // build_number
95   2,                                    // platform_id
96   0xdeadbeef,                           // csd_version_rva
97   0x100,                                // suite_mask
98   0,                                    // reserved2
99   {                                     // cpu
100     { // x86_cpu_info
101       { 0x756e6547, 0x49656e69, 0x6c65746e }, // vendor_id
102       0x6d8,                                  // version_information
103       0xafe9fbff,                             // feature_information
104       0xffffffff                              // amd_extended_cpu_features
105     }
106   }
107 };
108 
109 const string SystemInfo::windows_x86_csd_version = "Service Pack 2";
110 
String(const Dump & dump,const string & contents)111 String::String(const Dump &dump, const string &contents) : Section(dump) {
112   D32(contents.size() * 2);
113   for (string::const_iterator i = contents.begin(); i != contents.end(); i++)
114     D16(*i);
115 }
116 
CiteStringIn(test_assembler::Section * section) const117 void String::CiteStringIn(test_assembler::Section *section) const {
118   section->D32(file_offset_);
119 }
120 
CiteMemoryIn(test_assembler::Section * section) const121 void Memory::CiteMemoryIn(test_assembler::Section *section) const {
122   section->D64(address_);
123   CiteLocationIn(section);
124 }
125 
Context(const Dump & dump,const MDRawContextX86 & context)126 Context::Context(const Dump &dump, const MDRawContextX86 &context)
127   : Section(dump) {
128   // The caller should have properly set the CPU type flag.
129   // The high 24 bits identify the CPU.  Note that context records with no CPU
130   // type information can be valid (e.g. produced by ::RtlCaptureContext).
131   assert(((context.context_flags & MD_CONTEXT_CPU_MASK) == 0) ||
132          (context.context_flags & MD_CONTEXT_X86));
133   // It doesn't make sense to store x86 registers in big-endian form.
134   assert(dump.endianness() == kLittleEndian);
135   D32(context.context_flags);
136   D32(context.dr0);
137   D32(context.dr1);
138   D32(context.dr2);
139   D32(context.dr3);
140   D32(context.dr6);
141   D32(context.dr7);
142   D32(context.float_save.control_word);
143   D32(context.float_save.status_word);
144   D32(context.float_save.tag_word);
145   D32(context.float_save.error_offset);
146   D32(context.float_save.error_selector);
147   D32(context.float_save.data_offset);
148   D32(context.float_save.data_selector);
149   // context.float_save.register_area[] contains 8-bit quantities and
150   // does not need to be swapped.
151   Append(context.float_save.register_area,
152          sizeof(context.float_save.register_area));
153   D32(context.float_save.cr0_npx_state);
154   D32(context.gs);
155   D32(context.fs);
156   D32(context.es);
157   D32(context.ds);
158   D32(context.edi);
159   D32(context.esi);
160   D32(context.ebx);
161   D32(context.edx);
162   D32(context.ecx);
163   D32(context.eax);
164   D32(context.ebp);
165   D32(context.eip);
166   D32(context.cs);
167   D32(context.eflags);
168   D32(context.esp);
169   D32(context.ss);
170   // context.extended_registers[] contains 8-bit quantities and does
171   // not need to be swapped.
172   Append(context.extended_registers, sizeof(context.extended_registers));
173   assert(Size() == sizeof(MDRawContextX86));
174 }
175 
Context(const Dump & dump,const MDRawContextARM & context)176 Context::Context(const Dump &dump, const MDRawContextARM &context)
177   : Section(dump) {
178   // The caller should have properly set the CPU type flag.
179   assert((context.context_flags & MD_CONTEXT_ARM) ||
180          (context.context_flags & MD_CONTEXT_ARM_OLD));
181   // It doesn't make sense to store ARM registers in big-endian form.
182   assert(dump.endianness() == kLittleEndian);
183   D32(context.context_flags);
184   for (int i = 0; i < MD_CONTEXT_ARM_GPR_COUNT; ++i)
185     D32(context.iregs[i]);
186   D32(context.cpsr);
187   D64(context.float_save.fpscr);
188   for (int i = 0; i < MD_FLOATINGSAVEAREA_ARM_FPR_COUNT; ++i)
189     D64(context.float_save.regs[i]);
190   for (int i = 0; i < MD_FLOATINGSAVEAREA_ARM_FPEXTRA_COUNT; ++i)
191     D32(context.float_save.extra[i]);
192   assert(Size() == sizeof(MDRawContextARM));
193 }
194 
Context(const Dump & dump,const MDRawContextMIPS & context)195 Context::Context(const Dump &dump, const MDRawContextMIPS &context)
196     : Section(dump) {
197   // The caller should have properly set the CPU type flag.
198   assert(context.context_flags & MD_CONTEXT_MIPS);
199   D32(context.context_flags);
200   D32(context._pad0);
201 
202   for (int i = 0; i < MD_CONTEXT_MIPS_GPR_COUNT; ++i)
203     D64(context.iregs[i]);
204 
205   D64(context.mdhi);
206   D64(context.mdlo);
207 
208   for (int i = 0; i < MD_CONTEXT_MIPS_DSP_COUNT; ++i)
209     D32(context.hi[i]);
210 
211   for (int i = 0; i < MD_CONTEXT_MIPS_DSP_COUNT; ++i)
212     D32(context.lo[i]);
213 
214   D32(context.dsp_control);
215   D32(context._pad1);
216 
217   D64(context.epc);
218   D64(context.badvaddr);
219   D32(context.status);
220   D32(context.cause);
221 
222   for (int i = 0; i < MD_FLOATINGSAVEAREA_MIPS_FPR_COUNT; ++i)
223     D64(context.float_save.regs[i]);
224 
225   D32(context.float_save.fpcsr);
226   D32(context.float_save.fir);
227 
228   assert(Size() == sizeof(MDRawContextMIPS));
229 }
230 
Thread(const Dump & dump,uint32_t thread_id,const Memory & stack,const Context & context,uint32_t suspend_count,uint32_t priority_class,uint32_t priority,uint64_t teb)231 Thread::Thread(const Dump &dump,
232                uint32_t thread_id, const Memory &stack, const Context &context,
233                uint32_t suspend_count, uint32_t priority_class,
234                uint32_t priority, uint64_t teb) : Section(dump) {
235   D32(thread_id);
236   D32(suspend_count);
237   D32(priority_class);
238   D32(priority);
239   D64(teb);
240   stack.CiteMemoryIn(this);
241   context.CiteLocationIn(this);
242   assert(Size() == sizeof(MDRawThread));
243 }
244 
Module(const Dump & dump,uint64_t base_of_image,uint32_t size_of_image,const String & name,uint32_t time_date_stamp,uint32_t checksum,const MDVSFixedFileInfo & version_info,const Section * cv_record,const Section * misc_record)245 Module::Module(const Dump &dump,
246                uint64_t base_of_image,
247                uint32_t size_of_image,
248                const String &name,
249                uint32_t time_date_stamp,
250                uint32_t checksum,
251                const MDVSFixedFileInfo &version_info,
252                const Section *cv_record,
253                const Section *misc_record) : Section(dump) {
254   D64(base_of_image);
255   D32(size_of_image);
256   D32(checksum);
257   D32(time_date_stamp);
258   name.CiteStringIn(this);
259   D32(version_info.signature);
260   D32(version_info.struct_version);
261   D32(version_info.file_version_hi);
262   D32(version_info.file_version_lo);
263   D32(version_info.product_version_hi);
264   D32(version_info.product_version_lo);
265   D32(version_info.file_flags_mask);
266   D32(version_info.file_flags);
267   D32(version_info.file_os);
268   D32(version_info.file_type);
269   D32(version_info.file_subtype);
270   D32(version_info.file_date_hi);
271   D32(version_info.file_date_lo);
272   if (cv_record)
273     cv_record->CiteLocationIn(this);
274   else
275     D32(0).D32(0);
276   if (misc_record)
277     misc_record->CiteLocationIn(this);
278   else
279     D32(0).D32(0);
280   D64(0).D64(0);
281 }
282 
283 const MDVSFixedFileInfo Module::stock_version_info = {
284   MD_VSFIXEDFILEINFO_SIGNATURE,         // signature
285   MD_VSFIXEDFILEINFO_VERSION,           // struct_version
286   0x11111111,                           // file_version_hi
287   0x22222222,                           // file_version_lo
288   0x33333333,                           // product_version_hi
289   0x44444444,                           // product_version_lo
290   MD_VSFIXEDFILEINFO_FILE_FLAGS_DEBUG,  // file_flags_mask
291   MD_VSFIXEDFILEINFO_FILE_FLAGS_DEBUG,  // file_flags
292   MD_VSFIXEDFILEINFO_FILE_OS_NT | MD_VSFIXEDFILEINFO_FILE_OS__WINDOWS32,
293                                         // file_os
294   MD_VSFIXEDFILEINFO_FILE_TYPE_APP,     // file_type
295   MD_VSFIXEDFILEINFO_FILE_SUBTYPE_UNKNOWN, // file_subtype
296   0,                                    // file_date_hi
297   0                                     // file_date_lo
298 };
299 
UnloadedModule(const Dump & dump,uint64_t base_of_image,uint32_t size_of_image,const String & name,uint32_t checksum,uint32_t time_date_stamp)300 UnloadedModule::UnloadedModule(const Dump &dump,
301                                uint64_t base_of_image,
302                                uint32_t size_of_image,
303                                const String &name,
304                                uint32_t checksum,
305                                uint32_t time_date_stamp) : Section(dump) {
306   D64(base_of_image);
307   D32(size_of_image);
308   D32(checksum);
309   D32(time_date_stamp);
310   name.CiteStringIn(this);
311 }
312 
UnloadedModuleList(const Dump & dump,uint32_t type)313 UnloadedModuleList::UnloadedModuleList(const Dump &dump, uint32_t type)
314   : List<UnloadedModule>(dump, type, false) {
315   D32(sizeof(MDRawUnloadedModuleList));
316   D32(sizeof(MDRawUnloadedModule));
317   D32(count_label_);
318 }
319 
Exception(const Dump & dump,const Context & context,uint32_t thread_id,uint32_t exception_code,uint32_t exception_flags,uint64_t exception_address)320 Exception::Exception(const Dump &dump,
321                      const Context &context,
322                      uint32_t thread_id,
323                      uint32_t exception_code,
324                      uint32_t exception_flags,
325                      uint64_t exception_address)
326   : Stream(dump, MD_EXCEPTION_STREAM) {
327   D32(thread_id);
328   D32(0);  // __align
329   D32(exception_code);
330   D32(exception_flags);
331   D64(0);  // exception_record
332   D64(exception_address);
333   D32(0);  // number_parameters
334   D32(0);  // __align
335   for (int i = 0; i < MD_EXCEPTION_MAXIMUM_PARAMETERS; ++i)
336     D64(0);  // exception_information
337   context.CiteLocationIn(this);
338   assert(Size() == sizeof(MDRawExceptionStream));
339 }
340 
Dump(uint64_t flags,Endianness endianness,uint32_t version,uint32_t date_time_stamp)341 Dump::Dump(uint64_t flags,
342            Endianness endianness,
343            uint32_t version,
344            uint32_t date_time_stamp)
345     : test_assembler::Section(endianness),
346       file_start_(0),
347       stream_directory_(*this),
348       stream_count_(0),
349       thread_list_(*this, MD_THREAD_LIST_STREAM),
350       module_list_(*this, MD_MODULE_LIST_STREAM),
351       unloaded_module_list_(*this, MD_UNLOADED_MODULE_LIST_STREAM),
352       memory_list_(*this, MD_MEMORY_LIST_STREAM)
353  {
354   D32(MD_HEADER_SIGNATURE);
355   D32(version);
356   D32(stream_count_label_);
357   D32(stream_directory_rva_);
358   D32(0);
359   D32(date_time_stamp);
360   D64(flags);
361   assert(Size() == sizeof(MDRawHeader));
362 }
363 
Add(SynthMinidump::Section * section)364 Dump &Dump::Add(SynthMinidump::Section *section) {
365   section->Finish(file_start_ + Size());
366   Append(*section);
367   return *this;
368 }
369 
Add(Stream * stream)370 Dump &Dump::Add(Stream *stream) {
371   Add(static_cast<SynthMinidump::Section *>(stream));
372   stream->CiteStreamIn(&stream_directory_);
373   stream_count_++;
374   return *this;
375 }
376 
Add(Memory * memory)377 Dump &Dump::Add(Memory *memory) {
378   // Add the memory contents themselves to the file.
379   Add(static_cast<SynthMinidump::Section *>(memory));
380 
381   // The memory list is a list of MDMemoryDescriptors, not of actual
382   // memory elements. Produce a descriptor, and add that to the list.
383   SynthMinidump::Section descriptor(*this);
384   memory->CiteMemoryIn(&descriptor);
385   memory_list_.Add(&descriptor);
386   return *this;
387 }
388 
Add(Thread * thread)389 Dump &Dump::Add(Thread *thread) {
390   thread_list_.Add(thread);
391   return *this;
392 }
393 
Add(Module * module)394 Dump &Dump::Add(Module *module) {
395   module_list_.Add(module);
396   return *this;
397 }
398 
Add(UnloadedModule * unloaded_module)399 Dump &Dump::Add(UnloadedModule *unloaded_module) {
400   unloaded_module_list_.Add(unloaded_module);
401   return *this;
402 }
403 
Finish()404 void Dump::Finish() {
405   if (!thread_list_.Empty()) Add(&thread_list_);
406   if (!module_list_.Empty()) Add(&module_list_);
407   if (!unloaded_module_list_.Empty()) Add(&unloaded_module_list_);
408   if (!memory_list_.Empty()) Add(&memory_list_);
409 
410   // Create the stream directory. We don't use
411   // stream_directory_.Finish here, because the stream directory isn't
412   // cited using a location descriptor; rather, the Minidump header
413   // has the stream count and MDRVA.
414   stream_count_label_ = stream_count_;
415   stream_directory_rva_ = file_start_ + Size();
416   Append(static_cast<test_assembler::Section &>(stream_directory_));
417 }
418 
419 } // namespace SynthMinidump
420 
421 } // namespace google_breakpad
422