mirror of
https://github.com/yuzu-emu/breakpad.git
synced 2025-01-28 23:21:06 +00:00
6f598cc435
A=kmixter R=ted http://breakpad.appspot.com/132001 git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@629 4c0a9323-5329-0410-9bdc-e9ce6186880e
310 lines
11 KiB
C++
310 lines
11 KiB
C++
// Copyright (c) 2010, Google Inc.
|
|
// All rights reserved.
|
|
//
|
|
// 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 Inc. 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
|
|
|
|
#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 {
|
|
if (this)
|
|
(*section).D32(size_).D32(file_offset_);
|
|
else
|
|
(*section).D32(0).D32(0);
|
|
}
|
|
|
|
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 {
|
|
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.
|
|
assert(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));
|
|
}
|
|
|
|
Thread::Thread(const Dump &dump,
|
|
u_int32_t thread_id, const Memory &stack, const Context &context,
|
|
u_int32_t suspend_count, u_int32_t priority_class,
|
|
u_int32_t priority, u_int64_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,
|
|
u_int64_t base_of_image,
|
|
u_int32_t size_of_image,
|
|
const String &name,
|
|
u_int32_t time_date_stamp,
|
|
u_int32_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);
|
|
cv_record->CiteLocationIn(this);
|
|
misc_record->CiteLocationIn(this);
|
|
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
|
|
};
|
|
|
|
Dump::Dump(u_int64_t flags,
|
|
Endianness endianness,
|
|
u_int32_t version,
|
|
u_int32_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),
|
|
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;
|
|
}
|
|
|
|
void Dump::Finish() {
|
|
if (!thread_list_.Empty()) Add(&thread_list_);
|
|
if (!module_list_.Empty()) Add(&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
|