Home | History | Annotate | Download | only in processor
      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 (at) mozilla.com> <jimb (at) 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 
     40 Section::Section(const Dump &dump)
     41   : test_assembler::Section(dump.endianness()) { }
     42 
     43 void Section::CiteLocationIn(test_assembler::Section *section) const {
     44   if (this)
     45     (*section).D32(size_).D32(file_offset_);
     46   else
     47     (*section).D32(0).D32(0);
     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   cv_record->CiteLocationIn(this);
    276   misc_record->CiteLocationIn(this);
    277   D64(0).D64(0);
    278 }
    279 
    280 const MDVSFixedFileInfo Module::stock_version_info = {
    281   MD_VSFIXEDFILEINFO_SIGNATURE,         // signature
    282   MD_VSFIXEDFILEINFO_VERSION,           // struct_version
    283   0x11111111,                           // file_version_hi
    284   0x22222222,                           // file_version_lo
    285   0x33333333,                           // product_version_hi
    286   0x44444444,                           // product_version_lo
    287   MD_VSFIXEDFILEINFO_FILE_FLAGS_DEBUG,  // file_flags_mask
    288   MD_VSFIXEDFILEINFO_FILE_FLAGS_DEBUG,  // file_flags
    289   MD_VSFIXEDFILEINFO_FILE_OS_NT | MD_VSFIXEDFILEINFO_FILE_OS__WINDOWS32,
    290                                         // file_os
    291   MD_VSFIXEDFILEINFO_FILE_TYPE_APP,     // file_type
    292   MD_VSFIXEDFILEINFO_FILE_SUBTYPE_UNKNOWN, // file_subtype
    293   0,                                    // file_date_hi
    294   0                                     // file_date_lo
    295 };
    296 
    297 Exception::Exception(const Dump &dump,
    298                      const Context &context,
    299                      uint32_t thread_id,
    300                      uint32_t exception_code,
    301                      uint32_t exception_flags,
    302                      uint64_t exception_address)
    303   : Stream(dump, MD_EXCEPTION_STREAM) {
    304   D32(thread_id);
    305   D32(0);  // __align
    306   D32(exception_code);
    307   D32(exception_flags);
    308   D64(0);  // exception_record
    309   D64(exception_address);
    310   D32(0);  // number_parameters
    311   D32(0);  // __align
    312   for (int i = 0; i < MD_EXCEPTION_MAXIMUM_PARAMETERS; ++i)
    313     D64(0);  // exception_information
    314   context.CiteLocationIn(this);
    315   assert(Size() == sizeof(MDRawExceptionStream));
    316 }
    317 
    318 Dump::Dump(uint64_t flags,
    319            Endianness endianness,
    320            uint32_t version,
    321            uint32_t date_time_stamp)
    322     : test_assembler::Section(endianness),
    323       file_start_(0),
    324       stream_directory_(*this),
    325       stream_count_(0),
    326       thread_list_(*this, MD_THREAD_LIST_STREAM),
    327       module_list_(*this, MD_MODULE_LIST_STREAM),
    328       memory_list_(*this, MD_MEMORY_LIST_STREAM)
    329  {
    330   D32(MD_HEADER_SIGNATURE);
    331   D32(version);
    332   D32(stream_count_label_);
    333   D32(stream_directory_rva_);
    334   D32(0);
    335   D32(date_time_stamp);
    336   D64(flags);
    337   assert(Size() == sizeof(MDRawHeader));
    338 }
    339 
    340 Dump &Dump::Add(SynthMinidump::Section *section) {
    341   section->Finish(file_start_ + Size());
    342   Append(*section);
    343   return *this;
    344 }
    345 
    346 Dump &Dump::Add(Stream *stream) {
    347   Add(static_cast<SynthMinidump::Section *>(stream));
    348   stream->CiteStreamIn(&stream_directory_);
    349   stream_count_++;
    350   return *this;
    351 }
    352 
    353 Dump &Dump::Add(Memory *memory) {
    354   // Add the memory contents themselves to the file.
    355   Add(static_cast<SynthMinidump::Section *>(memory));
    356 
    357   // The memory list is a list of MDMemoryDescriptors, not of actual
    358   // memory elements. Produce a descriptor, and add that to the list.
    359   SynthMinidump::Section descriptor(*this);
    360   memory->CiteMemoryIn(&descriptor);
    361   memory_list_.Add(&descriptor);
    362   return *this;
    363 }
    364 
    365 Dump &Dump::Add(Thread *thread) {
    366   thread_list_.Add(thread);
    367   return *this;
    368 }
    369 
    370 Dump &Dump::Add(Module *module) {
    371   module_list_.Add(module);
    372   return *this;
    373 }
    374 
    375 void Dump::Finish() {
    376   if (!thread_list_.Empty()) Add(&thread_list_);
    377   if (!module_list_.Empty()) Add(&module_list_);
    378   if (!memory_list_.Empty()) Add(&memory_list_);
    379 
    380   // Create the stream directory. We don't use
    381   // stream_directory_.Finish here, because the stream directory isn't
    382   // cited using a location descriptor; rather, the Minidump header
    383   // has the stream count and MDRVA.
    384   stream_count_label_ = stream_count_;
    385   stream_directory_rva_ = file_start_ + Size();
    386   Append(static_cast<test_assembler::Section &>(stream_directory_));
    387 }
    388 
    389 } // namespace SynthMinidump
    390 
    391 } // namespace google_breakpad
    392