synth_minidump.cc
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 <jimb@mozilla.com> <jimb@red-bean.com> 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 43 Section::Section(const Dump& dump) 44 : test_assembler::Section(dump.endianness()) { } 45 46 void Section::CiteLocationIn(test_assembler::Section *section) const { 47 (*section).D32(size_).D32(file_offset_); 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 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 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 120 void String::CiteStringIn(test_assembler::Section *section) const { 121 section->D32(file_offset_); 122 } 123 124 void Memory::CiteMemoryIn(test_assembler::Section *section) const { 125 section->D64(address_); 126 CiteLocationIn(section); 127 } 128 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 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 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 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 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 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 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 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 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 367 Dump& Dump::Add(SynthMinidump::Section *section) { 368 section->Finish(file_start_ + Size()); 369 Append(*section); 370 return *this; 371 } 372 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 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 392 Dump& Dump::Add(Thread *thread) { 393 thread_list_.Add(thread); 394 return *this; 395 } 396 397 Dump& Dump::Add(Module *module) { 398 module_list_.Add(module); 399 return *this; 400 } 401 402 Dump& Dump::Add(UnloadedModule *unloaded_module) { 403 unloaded_module_list_.Add(unloaded_module); 404 return *this; 405 } 406 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