xref: /aosp_15_r20/external/google-breakpad/src/processor/synth_minidump.cc (revision 9712c20fc9bbfbac4935993a2ca0b3958c5adad2)
1 // Copyright 2010 Google LLC
2 //
3 // Redistribution and use in source and binary forms, with or without
4 // modification, are permitted provided that the following conditions are
5 // met:
6 //
7 //     * Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 //     * Redistributions in binary form must reproduce the above
10 // copyright notice, this list of conditions and the following disclaimer
11 // in the documentation and/or other materials provided with the
12 // distribution.
13 //     * Neither the name of Google LLC nor the names of its
14 // contributors may be used to endorse or promote products derived from
15 // this software without specific prior written permission.
16 //
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 
29 // Original author: Jim Blandy <[email protected]> <[email protected]>
30 
31 // synth_minidump.cc: Implementation of SynthMinidump.  See synth_minidump.h
32 
33 #ifdef HAVE_CONFIG_H
34 #include <config.h>  // Must come first
35 #endif
36 
37 #include "processor/synth_minidump.h"
38 
39 namespace google_breakpad {
40 
41 namespace SynthMinidump {
42 
Section(const Dump & dump)43 Section::Section(const Dump& dump)
44   : test_assembler::Section(dump.endianness()) { }
45 
CiteLocationIn(test_assembler::Section * section) const46 void Section::CiteLocationIn(test_assembler::Section *section) const {
47   (*section).D32(size_).D32(file_offset_);
48 }
49 
CiteStreamIn(test_assembler::Section * section) const50 void Stream::CiteStreamIn(test_assembler::Section *section) const {
51   section->D32(type_);
52   CiteLocationIn(section);
53 }
54 
SystemInfo(const Dump & dump,const MDRawSystemInfo & system_info,const String & csd_version)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 
String(const Dump & dump,const string & contents)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 
CiteStringIn(test_assembler::Section * section) const120 void String::CiteStringIn(test_assembler::Section *section) const {
121   section->D32(file_offset_);
122 }
123 
CiteMemoryIn(test_assembler::Section * section) const124 void Memory::CiteMemoryIn(test_assembler::Section *section) const {
125   section->D64(address_);
126   CiteLocationIn(section);
127 }
128 
Context(const Dump & dump,const MDRawContextX86 & context)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 
Context(const Dump & dump,const MDRawContextARM & context)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 
Context(const Dump & dump,const MDRawContextMIPS & context)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 
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)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 
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)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   if (cv_record)
276     cv_record->CiteLocationIn(this);
277   else
278     D32(0).D32(0);
279   if (misc_record)
280     misc_record->CiteLocationIn(this);
281   else
282     D32(0).D32(0);
283   D64(0).D64(0);
284 }
285 
286 const MDVSFixedFileInfo Module::stock_version_info = {
287   MD_VSFIXEDFILEINFO_SIGNATURE,         // signature
288   MD_VSFIXEDFILEINFO_VERSION,           // struct_version
289   0x11111111,                           // file_version_hi
290   0x22222222,                           // file_version_lo
291   0x33333333,                           // product_version_hi
292   0x44444444,                           // product_version_lo
293   MD_VSFIXEDFILEINFO_FILE_FLAGS_DEBUG,  // file_flags_mask
294   MD_VSFIXEDFILEINFO_FILE_FLAGS_DEBUG,  // file_flags
295   MD_VSFIXEDFILEINFO_FILE_OS_NT | MD_VSFIXEDFILEINFO_FILE_OS__WINDOWS32,
296                                         // file_os
297   MD_VSFIXEDFILEINFO_FILE_TYPE_APP,     // file_type
298   MD_VSFIXEDFILEINFO_FILE_SUBTYPE_UNKNOWN, // file_subtype
299   0,                                    // file_date_hi
300   0                                     // file_date_lo
301 };
302 
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)303 UnloadedModule::UnloadedModule(const Dump& dump,
304                                uint64_t base_of_image,
305                                uint32_t size_of_image,
306                                const String& name,
307                                uint32_t checksum,
308                                uint32_t time_date_stamp) : Section(dump) {
309   D64(base_of_image);
310   D32(size_of_image);
311   D32(checksum);
312   D32(time_date_stamp);
313   name.CiteStringIn(this);
314 }
315 
UnloadedModuleList(const Dump & dump,uint32_t type)316 UnloadedModuleList::UnloadedModuleList(const Dump& dump, uint32_t type)
317   : List<UnloadedModule>(dump, type, false) {
318   D32(sizeof(MDRawUnloadedModuleList));
319   D32(sizeof(MDRawUnloadedModule));
320   D32(count_label_);
321 }
322 
Exception(const Dump & dump,const Context & context,uint32_t thread_id,uint32_t exception_code,uint32_t exception_flags,uint64_t exception_address)323 Exception::Exception(const Dump& dump,
324                      const Context& context,
325                      uint32_t thread_id,
326                      uint32_t exception_code,
327                      uint32_t exception_flags,
328                      uint64_t exception_address)
329   : Stream(dump, MD_EXCEPTION_STREAM) {
330   D32(thread_id);
331   D32(0);  // __align
332   D32(exception_code);
333   D32(exception_flags);
334   D64(0);  // exception_record
335   D64(exception_address);
336   D32(0);  // number_parameters
337   D32(0);  // __align
338   for (size_t i = 0; i < MD_EXCEPTION_MAXIMUM_PARAMETERS; ++i)
339     D64(0);  // exception_information
340   context.CiteLocationIn(this);
341   assert(Size() == sizeof(MDRawExceptionStream));
342 }
343 
Dump(uint64_t flags,Endianness endianness,uint32_t version,uint32_t date_time_stamp)344 Dump::Dump(uint64_t flags,
345            Endianness endianness,
346            uint32_t version,
347            uint32_t date_time_stamp)
348     : test_assembler::Section(endianness),
349       file_start_(0),
350       stream_directory_(*this),
351       stream_count_(0),
352       thread_list_(*this, MD_THREAD_LIST_STREAM),
353       module_list_(*this, MD_MODULE_LIST_STREAM),
354       unloaded_module_list_(*this, MD_UNLOADED_MODULE_LIST_STREAM),
355       memory_list_(*this, MD_MEMORY_LIST_STREAM)
356  {
357   D32(MD_HEADER_SIGNATURE);
358   D32(version);
359   D32(stream_count_label_);
360   D32(stream_directory_rva_);
361   D32(0);
362   D32(date_time_stamp);
363   D64(flags);
364   assert(Size() == sizeof(MDRawHeader));
365 }
366 
Add(SynthMinidump::Section * section)367 Dump& Dump::Add(SynthMinidump::Section *section) {
368   section->Finish(file_start_ + Size());
369   Append(*section);
370   return *this;
371 }
372 
Add(Stream * stream)373 Dump& Dump::Add(Stream *stream) {
374   Add(static_cast<SynthMinidump::Section*>(stream));
375   stream->CiteStreamIn(&stream_directory_);
376   stream_count_++;
377   return *this;
378 }
379 
Add(Memory * memory)380 Dump& Dump::Add(Memory *memory) {
381   // Add the memory contents themselves to the file.
382   Add(static_cast<SynthMinidump::Section*>(memory));
383 
384   // The memory list is a list of MDMemoryDescriptors, not of actual
385   // memory elements. Produce a descriptor, and add that to the list.
386   SynthMinidump::Section descriptor(*this);
387   memory->CiteMemoryIn(&descriptor);
388   memory_list_.Add(&descriptor);
389   return *this;
390 }
391 
Add(Thread * thread)392 Dump& Dump::Add(Thread *thread) {
393   thread_list_.Add(thread);
394   return *this;
395 }
396 
Add(Module * module)397 Dump& Dump::Add(Module *module) {
398   module_list_.Add(module);
399   return *this;
400 }
401 
Add(UnloadedModule * unloaded_module)402 Dump& Dump::Add(UnloadedModule *unloaded_module) {
403   unloaded_module_list_.Add(unloaded_module);
404   return *this;
405 }
406 
Finish()407 void Dump::Finish() {
408   if (!thread_list_.Empty()) Add(&thread_list_);
409   if (!module_list_.Empty()) Add(&module_list_);
410   if (!unloaded_module_list_.Empty()) Add(&unloaded_module_list_);
411   if (!memory_list_.Empty()) Add(&memory_list_);
412 
413   // Create the stream directory. We don't use
414   // stream_directory_.Finish here, because the stream directory isn't
415   // cited using a location descriptor; rather, the Minidump header
416   // has the stream count and MDRVA.
417   stream_count_label_ = stream_count_;
418   stream_directory_rva_ = file_start_ + Size();
419   Append(static_cast<test_assembler::Section& >(stream_directory_));
420 }
421 
422 } // namespace SynthMinidump
423 
424 } // namespace google_breakpad
425