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