|
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 |
|
36 namespace google_breakpad { |
|
37 |
|
38 namespace SynthMinidump { |
|
39 |
|
40 Section::Section(const Dump &dump) |
|
41 : test_assembler::Section(dump.endianness()) { } |
|
42 |
|
43 void 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 |
|
50 void Stream::CiteStreamIn(test_assembler::Section *section) const { |
|
51 section->D32(type_); |
|
52 CiteLocationIn(section); |
|
53 } |
|
54 |
|
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 { |
|
81 D64(system_info.cpu.other_cpu_info.processor_features[0]); |
|
82 D64(system_info.cpu.other_cpu_info.processor_features[1]); |
|
83 } |
|
84 } |
|
85 |
|
86 const MDRawSystemInfo SystemInfo::windows_x86 = { |
|
87 MD_CPU_ARCHITECTURE_X86, // processor_architecture |
|
88 6, // processor_level |
|
89 0xd08, // processor_revision |
|
90 1, // number_of_processors |
|
91 1, // product_type |
|
92 5, // major_version |
|
93 1, // minor_version |
|
94 2600, // build_number |
|
95 2, // platform_id |
|
96 0xdeadbeef, // csd_version_rva |
|
97 0x100, // suite_mask |
|
98 0, // reserved2 |
|
99 { // cpu |
|
100 { // x86_cpu_info |
|
101 { 0x756e6547, 0x49656e69, 0x6c65746e }, // vendor_id |
|
102 0x6d8, // version_information |
|
103 0xafe9fbff, // feature_information |
|
104 0xffffffff // amd_extended_cpu_features |
|
105 } |
|
106 } |
|
107 }; |
|
108 |
|
109 const string SystemInfo::windows_x86_csd_version = "Service Pack 2"; |
|
110 |
|
111 String::String(const Dump &dump, const string &contents) : Section(dump) { |
|
112 D32(contents.size() * 2); |
|
113 for (string::const_iterator i = contents.begin(); i != contents.end(); i++) |
|
114 D16(*i); |
|
115 } |
|
116 |
|
117 void String::CiteStringIn(test_assembler::Section *section) const { |
|
118 section->D32(file_offset_); |
|
119 } |
|
120 |
|
121 void Memory::CiteMemoryIn(test_assembler::Section *section) const { |
|
122 section->D64(address_); |
|
123 CiteLocationIn(section); |
|
124 } |
|
125 |
|
126 Context::Context(const Dump &dump, const MDRawContextX86 &context) |
|
127 : Section(dump) { |
|
128 // The caller should have properly set the CPU type flag. |
|
129 // The high 24 bits identify the CPU. Note that context records with no CPU |
|
130 // type information can be valid (e.g. produced by ::RtlCaptureContext). |
|
131 assert(((context.context_flags & MD_CONTEXT_CPU_MASK) == 0) || |
|
132 (context.context_flags & MD_CONTEXT_X86)); |
|
133 // It doesn't make sense to store x86 registers in big-endian form. |
|
134 assert(dump.endianness() == kLittleEndian); |
|
135 D32(context.context_flags); |
|
136 D32(context.dr0); |
|
137 D32(context.dr1); |
|
138 D32(context.dr2); |
|
139 D32(context.dr3); |
|
140 D32(context.dr6); |
|
141 D32(context.dr7); |
|
142 D32(context.float_save.control_word); |
|
143 D32(context.float_save.status_word); |
|
144 D32(context.float_save.tag_word); |
|
145 D32(context.float_save.error_offset); |
|
146 D32(context.float_save.error_selector); |
|
147 D32(context.float_save.data_offset); |
|
148 D32(context.float_save.data_selector); |
|
149 // context.float_save.register_area[] contains 8-bit quantities and |
|
150 // does not need to be swapped. |
|
151 Append(context.float_save.register_area, |
|
152 sizeof(context.float_save.register_area)); |
|
153 D32(context.float_save.cr0_npx_state); |
|
154 D32(context.gs); |
|
155 D32(context.fs); |
|
156 D32(context.es); |
|
157 D32(context.ds); |
|
158 D32(context.edi); |
|
159 D32(context.esi); |
|
160 D32(context.ebx); |
|
161 D32(context.edx); |
|
162 D32(context.ecx); |
|
163 D32(context.eax); |
|
164 D32(context.ebp); |
|
165 D32(context.eip); |
|
166 D32(context.cs); |
|
167 D32(context.eflags); |
|
168 D32(context.esp); |
|
169 D32(context.ss); |
|
170 // context.extended_registers[] contains 8-bit quantities and does |
|
171 // not need to be swapped. |
|
172 Append(context.extended_registers, sizeof(context.extended_registers)); |
|
173 assert(Size() == sizeof(MDRawContextX86)); |
|
174 } |
|
175 |
|
176 Context::Context(const Dump &dump, const MDRawContextARM &context) |
|
177 : Section(dump) { |
|
178 // The caller should have properly set the CPU type flag. |
|
179 assert((context.context_flags & MD_CONTEXT_ARM) || |
|
180 (context.context_flags & MD_CONTEXT_ARM_OLD)); |
|
181 // It doesn't make sense to store ARM registers in big-endian form. |
|
182 assert(dump.endianness() == kLittleEndian); |
|
183 D32(context.context_flags); |
|
184 for (int i = 0; i < MD_CONTEXT_ARM_GPR_COUNT; ++i) |
|
185 D32(context.iregs[i]); |
|
186 D32(context.cpsr); |
|
187 D64(context.float_save.fpscr); |
|
188 for (int i = 0; i < MD_FLOATINGSAVEAREA_ARM_FPR_COUNT; ++i) |
|
189 D64(context.float_save.regs[i]); |
|
190 for (int i = 0; i < MD_FLOATINGSAVEAREA_ARM_FPEXTRA_COUNT; ++i) |
|
191 D32(context.float_save.extra[i]); |
|
192 assert(Size() == sizeof(MDRawContextARM)); |
|
193 } |
|
194 |
|
195 Thread::Thread(const Dump &dump, |
|
196 uint32_t thread_id, const Memory &stack, const Context &context, |
|
197 uint32_t suspend_count, uint32_t priority_class, |
|
198 uint32_t priority, uint64_t teb) : Section(dump) { |
|
199 D32(thread_id); |
|
200 D32(suspend_count); |
|
201 D32(priority_class); |
|
202 D32(priority); |
|
203 D64(teb); |
|
204 stack.CiteMemoryIn(this); |
|
205 context.CiteLocationIn(this); |
|
206 assert(Size() == sizeof(MDRawThread)); |
|
207 } |
|
208 |
|
209 Module::Module(const Dump &dump, |
|
210 uint64_t base_of_image, |
|
211 uint32_t size_of_image, |
|
212 const String &name, |
|
213 uint32_t time_date_stamp, |
|
214 uint32_t checksum, |
|
215 const MDVSFixedFileInfo &version_info, |
|
216 const Section *cv_record, |
|
217 const Section *misc_record) : Section(dump) { |
|
218 D64(base_of_image); |
|
219 D32(size_of_image); |
|
220 D32(checksum); |
|
221 D32(time_date_stamp); |
|
222 name.CiteStringIn(this); |
|
223 D32(version_info.signature); |
|
224 D32(version_info.struct_version); |
|
225 D32(version_info.file_version_hi); |
|
226 D32(version_info.file_version_lo); |
|
227 D32(version_info.product_version_hi); |
|
228 D32(version_info.product_version_lo); |
|
229 D32(version_info.file_flags_mask); |
|
230 D32(version_info.file_flags); |
|
231 D32(version_info.file_os); |
|
232 D32(version_info.file_type); |
|
233 D32(version_info.file_subtype); |
|
234 D32(version_info.file_date_hi); |
|
235 D32(version_info.file_date_lo); |
|
236 cv_record->CiteLocationIn(this); |
|
237 misc_record->CiteLocationIn(this); |
|
238 D64(0).D64(0); |
|
239 } |
|
240 |
|
241 const MDVSFixedFileInfo Module::stock_version_info = { |
|
242 MD_VSFIXEDFILEINFO_SIGNATURE, // signature |
|
243 MD_VSFIXEDFILEINFO_VERSION, // struct_version |
|
244 0x11111111, // file_version_hi |
|
245 0x22222222, // file_version_lo |
|
246 0x33333333, // product_version_hi |
|
247 0x44444444, // product_version_lo |
|
248 MD_VSFIXEDFILEINFO_FILE_FLAGS_DEBUG, // file_flags_mask |
|
249 MD_VSFIXEDFILEINFO_FILE_FLAGS_DEBUG, // file_flags |
|
250 MD_VSFIXEDFILEINFO_FILE_OS_NT | MD_VSFIXEDFILEINFO_FILE_OS__WINDOWS32, |
|
251 // file_os |
|
252 MD_VSFIXEDFILEINFO_FILE_TYPE_APP, // file_type |
|
253 MD_VSFIXEDFILEINFO_FILE_SUBTYPE_UNKNOWN, // file_subtype |
|
254 0, // file_date_hi |
|
255 0 // file_date_lo |
|
256 }; |
|
257 |
|
258 Exception::Exception(const Dump &dump, |
|
259 const Context &context, |
|
260 uint32_t thread_id, |
|
261 uint32_t exception_code, |
|
262 uint32_t exception_flags, |
|
263 uint64_t exception_address) |
|
264 : Stream(dump, MD_EXCEPTION_STREAM) { |
|
265 D32(thread_id); |
|
266 D32(0); // __align |
|
267 D32(exception_code); |
|
268 D32(exception_flags); |
|
269 D64(0); // exception_record |
|
270 D64(exception_address); |
|
271 D32(0); // number_parameters |
|
272 D32(0); // __align |
|
273 for (int i = 0; i < MD_EXCEPTION_MAXIMUM_PARAMETERS; ++i) |
|
274 D64(0); // exception_information |
|
275 context.CiteLocationIn(this); |
|
276 assert(Size() == sizeof(MDRawExceptionStream)); |
|
277 } |
|
278 |
|
279 Dump::Dump(uint64_t flags, |
|
280 Endianness endianness, |
|
281 uint32_t version, |
|
282 uint32_t date_time_stamp) |
|
283 : test_assembler::Section(endianness), |
|
284 file_start_(0), |
|
285 stream_directory_(*this), |
|
286 stream_count_(0), |
|
287 thread_list_(*this, MD_THREAD_LIST_STREAM), |
|
288 module_list_(*this, MD_MODULE_LIST_STREAM), |
|
289 memory_list_(*this, MD_MEMORY_LIST_STREAM) |
|
290 { |
|
291 D32(MD_HEADER_SIGNATURE); |
|
292 D32(version); |
|
293 D32(stream_count_label_); |
|
294 D32(stream_directory_rva_); |
|
295 D32(0); |
|
296 D32(date_time_stamp); |
|
297 D64(flags); |
|
298 assert(Size() == sizeof(MDRawHeader)); |
|
299 } |
|
300 |
|
301 Dump &Dump::Add(SynthMinidump::Section *section) { |
|
302 section->Finish(file_start_ + Size()); |
|
303 Append(*section); |
|
304 return *this; |
|
305 } |
|
306 |
|
307 Dump &Dump::Add(Stream *stream) { |
|
308 Add(static_cast<SynthMinidump::Section *>(stream)); |
|
309 stream->CiteStreamIn(&stream_directory_); |
|
310 stream_count_++; |
|
311 return *this; |
|
312 } |
|
313 |
|
314 Dump &Dump::Add(Memory *memory) { |
|
315 // Add the memory contents themselves to the file. |
|
316 Add(static_cast<SynthMinidump::Section *>(memory)); |
|
317 |
|
318 // The memory list is a list of MDMemoryDescriptors, not of actual |
|
319 // memory elements. Produce a descriptor, and add that to the list. |
|
320 SynthMinidump::Section descriptor(*this); |
|
321 memory->CiteMemoryIn(&descriptor); |
|
322 memory_list_.Add(&descriptor); |
|
323 return *this; |
|
324 } |
|
325 |
|
326 Dump &Dump::Add(Thread *thread) { |
|
327 thread_list_.Add(thread); |
|
328 return *this; |
|
329 } |
|
330 |
|
331 Dump &Dump::Add(Module *module) { |
|
332 module_list_.Add(module); |
|
333 return *this; |
|
334 } |
|
335 |
|
336 void Dump::Finish() { |
|
337 if (!thread_list_.Empty()) Add(&thread_list_); |
|
338 if (!module_list_.Empty()) Add(&module_list_); |
|
339 if (!memory_list_.Empty()) Add(&memory_list_); |
|
340 |
|
341 // Create the stream directory. We don't use |
|
342 // stream_directory_.Finish here, because the stream directory isn't |
|
343 // cited using a location descriptor; rather, the Minidump header |
|
344 // has the stream count and MDRVA. |
|
345 stream_count_label_ = stream_count_; |
|
346 stream_directory_rva_ = file_start_ + Size(); |
|
347 Append(static_cast<test_assembler::Section &>(stream_directory_)); |
|
348 } |
|
349 |
|
350 } // namespace SynthMinidump |
|
351 |
|
352 } // namespace google_breakpad |