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