michael@0: // Copyright (c) 2010, Google Inc. michael@0: // All rights reserved. michael@0: // michael@0: // Redistribution and use in source and binary forms, with or without michael@0: // modification, are permitted provided that the following conditions are michael@0: // met: michael@0: // michael@0: // * Redistributions of source code must retain the above copyright michael@0: // notice, this list of conditions and the following disclaimer. michael@0: // * Redistributions in binary form must reproduce the above michael@0: // copyright notice, this list of conditions and the following disclaimer michael@0: // in the documentation and/or other materials provided with the michael@0: // distribution. michael@0: // * Neither the name of Google Inc. nor the names of its michael@0: // contributors may be used to endorse or promote products derived from michael@0: // this software without specific prior written permission. michael@0: // michael@0: // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS michael@0: // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT michael@0: // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR michael@0: // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT michael@0: // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, michael@0: // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT michael@0: // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, michael@0: // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY michael@0: // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT michael@0: // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE michael@0: // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. michael@0: michael@0: // Original author: Jim Blandy michael@0: michael@0: // synth_minidump.cc: Implementation of SynthMinidump. See synth_minidump.h michael@0: michael@0: #include "processor/synth_minidump.h" michael@0: michael@0: namespace google_breakpad { michael@0: michael@0: namespace SynthMinidump { michael@0: michael@0: Section::Section(const Dump &dump) michael@0: : test_assembler::Section(dump.endianness()) { } michael@0: michael@0: void Section::CiteLocationIn(test_assembler::Section *section) const { michael@0: if (this) michael@0: (*section).D32(size_).D32(file_offset_); michael@0: else michael@0: (*section).D32(0).D32(0); michael@0: } michael@0: michael@0: void Stream::CiteStreamIn(test_assembler::Section *section) const { michael@0: section->D32(type_); michael@0: CiteLocationIn(section); michael@0: } michael@0: michael@0: SystemInfo::SystemInfo(const Dump &dump, michael@0: const MDRawSystemInfo &system_info, michael@0: const String &csd_version) michael@0: : Stream(dump, MD_SYSTEM_INFO_STREAM) { michael@0: D16(system_info.processor_architecture); michael@0: D16(system_info.processor_level); michael@0: D16(system_info.processor_revision); michael@0: D8(system_info.number_of_processors); michael@0: D8(system_info.product_type); michael@0: D32(system_info.major_version); michael@0: D32(system_info.minor_version); michael@0: D32(system_info.build_number); michael@0: D32(system_info.platform_id); michael@0: csd_version.CiteStringIn(this); michael@0: D16(system_info.suite_mask); michael@0: D16(system_info.reserved2); // Well, why not? michael@0: michael@0: // MDCPUInformation cpu; michael@0: if (system_info.processor_architecture == MD_CPU_ARCHITECTURE_X86) { michael@0: D32(system_info.cpu.x86_cpu_info.vendor_id[0]); michael@0: D32(system_info.cpu.x86_cpu_info.vendor_id[1]); michael@0: D32(system_info.cpu.x86_cpu_info.vendor_id[2]); michael@0: D32(system_info.cpu.x86_cpu_info.version_information); michael@0: D32(system_info.cpu.x86_cpu_info.feature_information); michael@0: D32(system_info.cpu.x86_cpu_info.amd_extended_cpu_features); michael@0: } else { michael@0: D64(system_info.cpu.other_cpu_info.processor_features[0]); michael@0: D64(system_info.cpu.other_cpu_info.processor_features[1]); michael@0: } michael@0: } michael@0: michael@0: const MDRawSystemInfo SystemInfo::windows_x86 = { michael@0: MD_CPU_ARCHITECTURE_X86, // processor_architecture michael@0: 6, // processor_level michael@0: 0xd08, // processor_revision michael@0: 1, // number_of_processors michael@0: 1, // product_type michael@0: 5, // major_version michael@0: 1, // minor_version michael@0: 2600, // build_number michael@0: 2, // platform_id michael@0: 0xdeadbeef, // csd_version_rva michael@0: 0x100, // suite_mask michael@0: 0, // reserved2 michael@0: { // cpu michael@0: { // x86_cpu_info michael@0: { 0x756e6547, 0x49656e69, 0x6c65746e }, // vendor_id michael@0: 0x6d8, // version_information michael@0: 0xafe9fbff, // feature_information michael@0: 0xffffffff // amd_extended_cpu_features michael@0: } michael@0: } michael@0: }; michael@0: michael@0: const string SystemInfo::windows_x86_csd_version = "Service Pack 2"; michael@0: michael@0: String::String(const Dump &dump, const string &contents) : Section(dump) { michael@0: D32(contents.size() * 2); michael@0: for (string::const_iterator i = contents.begin(); i != contents.end(); i++) michael@0: D16(*i); michael@0: } michael@0: michael@0: void String::CiteStringIn(test_assembler::Section *section) const { michael@0: section->D32(file_offset_); michael@0: } michael@0: michael@0: void Memory::CiteMemoryIn(test_assembler::Section *section) const { michael@0: section->D64(address_); michael@0: CiteLocationIn(section); michael@0: } michael@0: michael@0: Context::Context(const Dump &dump, const MDRawContextX86 &context) michael@0: : Section(dump) { michael@0: // The caller should have properly set the CPU type flag. michael@0: // The high 24 bits identify the CPU. Note that context records with no CPU michael@0: // type information can be valid (e.g. produced by ::RtlCaptureContext). michael@0: assert(((context.context_flags & MD_CONTEXT_CPU_MASK) == 0) || michael@0: (context.context_flags & MD_CONTEXT_X86)); michael@0: // It doesn't make sense to store x86 registers in big-endian form. michael@0: assert(dump.endianness() == kLittleEndian); michael@0: D32(context.context_flags); michael@0: D32(context.dr0); michael@0: D32(context.dr1); michael@0: D32(context.dr2); michael@0: D32(context.dr3); michael@0: D32(context.dr6); michael@0: D32(context.dr7); michael@0: D32(context.float_save.control_word); michael@0: D32(context.float_save.status_word); michael@0: D32(context.float_save.tag_word); michael@0: D32(context.float_save.error_offset); michael@0: D32(context.float_save.error_selector); michael@0: D32(context.float_save.data_offset); michael@0: D32(context.float_save.data_selector); michael@0: // context.float_save.register_area[] contains 8-bit quantities and michael@0: // does not need to be swapped. michael@0: Append(context.float_save.register_area, michael@0: sizeof(context.float_save.register_area)); michael@0: D32(context.float_save.cr0_npx_state); michael@0: D32(context.gs); michael@0: D32(context.fs); michael@0: D32(context.es); michael@0: D32(context.ds); michael@0: D32(context.edi); michael@0: D32(context.esi); michael@0: D32(context.ebx); michael@0: D32(context.edx); michael@0: D32(context.ecx); michael@0: D32(context.eax); michael@0: D32(context.ebp); michael@0: D32(context.eip); michael@0: D32(context.cs); michael@0: D32(context.eflags); michael@0: D32(context.esp); michael@0: D32(context.ss); michael@0: // context.extended_registers[] contains 8-bit quantities and does michael@0: // not need to be swapped. michael@0: Append(context.extended_registers, sizeof(context.extended_registers)); michael@0: assert(Size() == sizeof(MDRawContextX86)); michael@0: } michael@0: michael@0: Context::Context(const Dump &dump, const MDRawContextARM &context) michael@0: : Section(dump) { michael@0: // The caller should have properly set the CPU type flag. michael@0: assert((context.context_flags & MD_CONTEXT_ARM) || michael@0: (context.context_flags & MD_CONTEXT_ARM_OLD)); michael@0: // It doesn't make sense to store ARM registers in big-endian form. michael@0: assert(dump.endianness() == kLittleEndian); michael@0: D32(context.context_flags); michael@0: for (int i = 0; i < MD_CONTEXT_ARM_GPR_COUNT; ++i) michael@0: D32(context.iregs[i]); michael@0: D32(context.cpsr); michael@0: D64(context.float_save.fpscr); michael@0: for (int i = 0; i < MD_FLOATINGSAVEAREA_ARM_FPR_COUNT; ++i) michael@0: D64(context.float_save.regs[i]); michael@0: for (int i = 0; i < MD_FLOATINGSAVEAREA_ARM_FPEXTRA_COUNT; ++i) michael@0: D32(context.float_save.extra[i]); michael@0: assert(Size() == sizeof(MDRawContextARM)); michael@0: } michael@0: michael@0: Thread::Thread(const Dump &dump, michael@0: uint32_t thread_id, const Memory &stack, const Context &context, michael@0: uint32_t suspend_count, uint32_t priority_class, michael@0: uint32_t priority, uint64_t teb) : Section(dump) { michael@0: D32(thread_id); michael@0: D32(suspend_count); michael@0: D32(priority_class); michael@0: D32(priority); michael@0: D64(teb); michael@0: stack.CiteMemoryIn(this); michael@0: context.CiteLocationIn(this); michael@0: assert(Size() == sizeof(MDRawThread)); michael@0: } michael@0: michael@0: Module::Module(const Dump &dump, michael@0: uint64_t base_of_image, michael@0: uint32_t size_of_image, michael@0: const String &name, michael@0: uint32_t time_date_stamp, michael@0: uint32_t checksum, michael@0: const MDVSFixedFileInfo &version_info, michael@0: const Section *cv_record, michael@0: const Section *misc_record) : Section(dump) { michael@0: D64(base_of_image); michael@0: D32(size_of_image); michael@0: D32(checksum); michael@0: D32(time_date_stamp); michael@0: name.CiteStringIn(this); michael@0: D32(version_info.signature); michael@0: D32(version_info.struct_version); michael@0: D32(version_info.file_version_hi); michael@0: D32(version_info.file_version_lo); michael@0: D32(version_info.product_version_hi); michael@0: D32(version_info.product_version_lo); michael@0: D32(version_info.file_flags_mask); michael@0: D32(version_info.file_flags); michael@0: D32(version_info.file_os); michael@0: D32(version_info.file_type); michael@0: D32(version_info.file_subtype); michael@0: D32(version_info.file_date_hi); michael@0: D32(version_info.file_date_lo); michael@0: cv_record->CiteLocationIn(this); michael@0: misc_record->CiteLocationIn(this); michael@0: D64(0).D64(0); michael@0: } michael@0: michael@0: const MDVSFixedFileInfo Module::stock_version_info = { michael@0: MD_VSFIXEDFILEINFO_SIGNATURE, // signature michael@0: MD_VSFIXEDFILEINFO_VERSION, // struct_version michael@0: 0x11111111, // file_version_hi michael@0: 0x22222222, // file_version_lo michael@0: 0x33333333, // product_version_hi michael@0: 0x44444444, // product_version_lo michael@0: MD_VSFIXEDFILEINFO_FILE_FLAGS_DEBUG, // file_flags_mask michael@0: MD_VSFIXEDFILEINFO_FILE_FLAGS_DEBUG, // file_flags michael@0: MD_VSFIXEDFILEINFO_FILE_OS_NT | MD_VSFIXEDFILEINFO_FILE_OS__WINDOWS32, michael@0: // file_os michael@0: MD_VSFIXEDFILEINFO_FILE_TYPE_APP, // file_type michael@0: MD_VSFIXEDFILEINFO_FILE_SUBTYPE_UNKNOWN, // file_subtype michael@0: 0, // file_date_hi michael@0: 0 // file_date_lo michael@0: }; michael@0: michael@0: Exception::Exception(const Dump &dump, michael@0: const Context &context, michael@0: uint32_t thread_id, michael@0: uint32_t exception_code, michael@0: uint32_t exception_flags, michael@0: uint64_t exception_address) michael@0: : Stream(dump, MD_EXCEPTION_STREAM) { michael@0: D32(thread_id); michael@0: D32(0); // __align michael@0: D32(exception_code); michael@0: D32(exception_flags); michael@0: D64(0); // exception_record michael@0: D64(exception_address); michael@0: D32(0); // number_parameters michael@0: D32(0); // __align michael@0: for (int i = 0; i < MD_EXCEPTION_MAXIMUM_PARAMETERS; ++i) michael@0: D64(0); // exception_information michael@0: context.CiteLocationIn(this); michael@0: assert(Size() == sizeof(MDRawExceptionStream)); michael@0: } michael@0: michael@0: Dump::Dump(uint64_t flags, michael@0: Endianness endianness, michael@0: uint32_t version, michael@0: uint32_t date_time_stamp) michael@0: : test_assembler::Section(endianness), michael@0: file_start_(0), michael@0: stream_directory_(*this), michael@0: stream_count_(0), michael@0: thread_list_(*this, MD_THREAD_LIST_STREAM), michael@0: module_list_(*this, MD_MODULE_LIST_STREAM), michael@0: memory_list_(*this, MD_MEMORY_LIST_STREAM) michael@0: { michael@0: D32(MD_HEADER_SIGNATURE); michael@0: D32(version); michael@0: D32(stream_count_label_); michael@0: D32(stream_directory_rva_); michael@0: D32(0); michael@0: D32(date_time_stamp); michael@0: D64(flags); michael@0: assert(Size() == sizeof(MDRawHeader)); michael@0: } michael@0: michael@0: Dump &Dump::Add(SynthMinidump::Section *section) { michael@0: section->Finish(file_start_ + Size()); michael@0: Append(*section); michael@0: return *this; michael@0: } michael@0: michael@0: Dump &Dump::Add(Stream *stream) { michael@0: Add(static_cast(stream)); michael@0: stream->CiteStreamIn(&stream_directory_); michael@0: stream_count_++; michael@0: return *this; michael@0: } michael@0: michael@0: Dump &Dump::Add(Memory *memory) { michael@0: // Add the memory contents themselves to the file. michael@0: Add(static_cast(memory)); michael@0: michael@0: // The memory list is a list of MDMemoryDescriptors, not of actual michael@0: // memory elements. Produce a descriptor, and add that to the list. michael@0: SynthMinidump::Section descriptor(*this); michael@0: memory->CiteMemoryIn(&descriptor); michael@0: memory_list_.Add(&descriptor); michael@0: return *this; michael@0: } michael@0: michael@0: Dump &Dump::Add(Thread *thread) { michael@0: thread_list_.Add(thread); michael@0: return *this; michael@0: } michael@0: michael@0: Dump &Dump::Add(Module *module) { michael@0: module_list_.Add(module); michael@0: return *this; michael@0: } michael@0: michael@0: void Dump::Finish() { michael@0: if (!thread_list_.Empty()) Add(&thread_list_); michael@0: if (!module_list_.Empty()) Add(&module_list_); michael@0: if (!memory_list_.Empty()) Add(&memory_list_); michael@0: michael@0: // Create the stream directory. We don't use michael@0: // stream_directory_.Finish here, because the stream directory isn't michael@0: // cited using a location descriptor; rather, the Minidump header michael@0: // has the stream count and MDRVA. michael@0: stream_count_label_ = stream_count_; michael@0: stream_directory_rva_ = file_start_ + Size(); michael@0: Append(static_cast(stream_directory_)); michael@0: } michael@0: michael@0: } // namespace SynthMinidump michael@0: michael@0: } // namespace google_breakpad