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@mozilla.com> <jimb@red-bean.com>
31
32// synth_minidump.cc: Implementation of SynthMinidump.  See synth_minidump.h
33
34#include "processor/synth_minidump.h"
35
36namespace google_breakpad {
37
38namespace SynthMinidump {
39
40Section::Section(const Dump &dump)
41  : test_assembler::Section(dump.endianness()) { }
42
43void 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
50void Stream::CiteStreamIn(test_assembler::Section *section) const {
51  section->D32(type_);
52  CiteLocationIn(section);
53}
54
55SystemInfo::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
89const 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
112const string SystemInfo::windows_x86_csd_version = "Service Pack 2";
113
114String::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
120void String::CiteStringIn(test_assembler::Section *section) const {
121  section->D32(file_offset_);
122}
123
124void Memory::CiteMemoryIn(test_assembler::Section *section) const {
125  section->D64(address_);
126  CiteLocationIn(section);
127}
128
129Context::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
179Context::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
198Context::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
234Thread::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
248Module::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
280const 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
297Exception::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
318Dump::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
340Dump &Dump::Add(SynthMinidump::Section *section) {
341  section->Finish(file_start_ + Size());
342  Append(*section);
343  return *this;
344}
345
346Dump &Dump::Add(Stream *stream) {
347  Add(static_cast<SynthMinidump::Section *>(stream));
348  stream->CiteStreamIn(&stream_directory_);
349  stream_count_++;
350  return *this;
351}
352
353Dump &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
365Dump &Dump::Add(Thread *thread) {
366  thread_list_.Add(thread);
367  return *this;
368}
369
370Dump &Dump::Add(Module *module) {
371  module_list_.Add(module);
372  return *this;
373}
374
375void 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