1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/toolkit/crashreporter/google-breakpad/src/processor/minidump.cc Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,4343 @@ 1.4 +// Copyright (c) 2010 Google Inc. 1.5 +// All rights reserved. 1.6 +// 1.7 +// Redistribution and use in source and binary forms, with or without 1.8 +// modification, are permitted provided that the following conditions are 1.9 +// met: 1.10 +// 1.11 +// * Redistributions of source code must retain the above copyright 1.12 +// notice, this list of conditions and the following disclaimer. 1.13 +// * Redistributions in binary form must reproduce the above 1.14 +// copyright notice, this list of conditions and the following disclaimer 1.15 +// in the documentation and/or other materials provided with the 1.16 +// distribution. 1.17 +// * Neither the name of Google Inc. nor the names of its 1.18 +// contributors may be used to endorse or promote products derived from 1.19 +// this software without specific prior written permission. 1.20 +// 1.21 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1.22 +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 1.23 +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 1.24 +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 1.25 +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 1.26 +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 1.27 +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 1.28 +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 1.29 +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 1.30 +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 1.31 +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 1.32 + 1.33 +// minidump.cc: A minidump reader. 1.34 +// 1.35 +// See minidump.h for documentation. 1.36 +// 1.37 +// Author: Mark Mentovai 1.38 + 1.39 +#include "google_breakpad/processor/minidump.h" 1.40 + 1.41 +#include <assert.h> 1.42 +#include <fcntl.h> 1.43 +#include <stddef.h> 1.44 +#include <stdio.h> 1.45 +#include <string.h> 1.46 +#include <time.h> 1.47 + 1.48 +#ifdef _WIN32 1.49 +#include <io.h> 1.50 +#define PRIx64 "llx" 1.51 +#define PRIx32 "lx" 1.52 +#define snprintf _snprintf 1.53 +#else // _WIN32 1.54 +#include <unistd.h> 1.55 +#define O_BINARY 0 1.56 +#endif // _WIN32 1.57 + 1.58 +#include <fstream> 1.59 +#include <iostream> 1.60 +#include <limits> 1.61 +#include <map> 1.62 +#include <vector> 1.63 + 1.64 +#include "processor/range_map-inl.h" 1.65 + 1.66 +#include "common/scoped_ptr.h" 1.67 +#include "processor/basic_code_module.h" 1.68 +#include "processor/basic_code_modules.h" 1.69 +#include "common/logging.h" 1.70 + 1.71 + 1.72 + 1.73 +namespace google_breakpad { 1.74 + 1.75 + 1.76 +using std::istream; 1.77 +using std::ifstream; 1.78 +using std::numeric_limits; 1.79 +using std::vector; 1.80 + 1.81 + 1.82 +// 1.83 +// Swapping routines 1.84 +// 1.85 +// Inlining these doesn't increase code size significantly, and it saves 1.86 +// a whole lot of unnecessary jumping back and forth. 1.87 +// 1.88 + 1.89 + 1.90 +// Swapping an 8-bit quantity is a no-op. This function is only provided 1.91 +// to account for certain templatized operations that require swapping for 1.92 +// wider types but handle uint8_t too 1.93 +// (MinidumpMemoryRegion::GetMemoryAtAddressInternal). 1.94 +static inline void Swap(uint8_t* value) { 1.95 +} 1.96 + 1.97 + 1.98 +// Optimization: don't need to AND the furthest right shift, because we're 1.99 +// shifting an unsigned quantity. The standard requires zero-filling in this 1.100 +// case. If the quantities were signed, a bitmask whould be needed for this 1.101 +// right shift to avoid an arithmetic shift (which retains the sign bit). 1.102 +// The furthest left shift never needs to be ANDed bitmask. 1.103 + 1.104 + 1.105 +static inline void Swap(uint16_t* value) { 1.106 + *value = (*value >> 8) | 1.107 + (*value << 8); 1.108 +} 1.109 + 1.110 + 1.111 +static inline void Swap(uint32_t* value) { 1.112 + *value = (*value >> 24) | 1.113 + ((*value >> 8) & 0x0000ff00) | 1.114 + ((*value << 8) & 0x00ff0000) | 1.115 + (*value << 24); 1.116 +} 1.117 + 1.118 + 1.119 +static inline void Swap(uint64_t* value) { 1.120 + uint32_t* value32 = reinterpret_cast<uint32_t*>(value); 1.121 + Swap(&value32[0]); 1.122 + Swap(&value32[1]); 1.123 + uint32_t temp = value32[0]; 1.124 + value32[0] = value32[1]; 1.125 + value32[1] = temp; 1.126 +} 1.127 + 1.128 + 1.129 +// Given a pointer to a 128-bit int in the minidump data, set the "low" 1.130 +// and "high" fields appropriately. 1.131 +static void Normalize128(uint128_struct* value, bool is_big_endian) { 1.132 + // The struct format is [high, low], so if the format is big-endian, 1.133 + // the most significant bytes will already be in the high field. 1.134 + if (!is_big_endian) { 1.135 + uint64_t temp = value->low; 1.136 + value->low = value->high; 1.137 + value->high = temp; 1.138 + } 1.139 +} 1.140 + 1.141 +// This just swaps each int64 half of the 128-bit value. 1.142 +// The value should also be normalized by calling Normalize128(). 1.143 +static void Swap(uint128_struct* value) { 1.144 + Swap(&value->low); 1.145 + Swap(&value->high); 1.146 +} 1.147 + 1.148 + 1.149 +static inline void Swap(MDLocationDescriptor* location_descriptor) { 1.150 + Swap(&location_descriptor->data_size); 1.151 + Swap(&location_descriptor->rva); 1.152 +} 1.153 + 1.154 + 1.155 +static inline void Swap(MDMemoryDescriptor* memory_descriptor) { 1.156 + Swap(&memory_descriptor->start_of_memory_range); 1.157 + Swap(&memory_descriptor->memory); 1.158 +} 1.159 + 1.160 + 1.161 +static inline void Swap(MDGUID* guid) { 1.162 + Swap(&guid->data1); 1.163 + Swap(&guid->data2); 1.164 + Swap(&guid->data3); 1.165 + // Don't swap guid->data4[] because it contains 8-bit quantities. 1.166 +} 1.167 + 1.168 + 1.169 +// 1.170 +// Character conversion routines 1.171 +// 1.172 + 1.173 + 1.174 +// Standard wide-character conversion routines depend on the system's own 1.175 +// idea of what width a wide character should be: some use 16 bits, and 1.176 +// some use 32 bits. For the purposes of a minidump, wide strings are 1.177 +// always represented with 16-bit UTF-16 chracters. iconv isn't available 1.178 +// everywhere, and its interface varies where it is available. iconv also 1.179 +// deals purely with char* pointers, so in addition to considering the swap 1.180 +// parameter, a converter that uses iconv would also need to take the host 1.181 +// CPU's endianness into consideration. It doesn't seems worth the trouble 1.182 +// of making it a dependency when we don't care about anything but UTF-16. 1.183 +static string* UTF16ToUTF8(const vector<uint16_t>& in, 1.184 + bool swap) { 1.185 + scoped_ptr<string> out(new string()); 1.186 + 1.187 + // Set the string's initial capacity to the number of UTF-16 characters, 1.188 + // because the UTF-8 representation will always be at least this long. 1.189 + // If the UTF-8 representation is longer, the string will grow dynamically. 1.190 + out->reserve(in.size()); 1.191 + 1.192 + for (vector<uint16_t>::const_iterator iterator = in.begin(); 1.193 + iterator != in.end(); 1.194 + ++iterator) { 1.195 + // Get a 16-bit value from the input 1.196 + uint16_t in_word = *iterator; 1.197 + if (swap) 1.198 + Swap(&in_word); 1.199 + 1.200 + // Convert the input value (in_word) into a Unicode code point (unichar). 1.201 + uint32_t unichar; 1.202 + if (in_word >= 0xdc00 && in_word <= 0xdcff) { 1.203 + BPLOG(ERROR) << "UTF16ToUTF8 found low surrogate " << 1.204 + HexString(in_word) << " without high"; 1.205 + return NULL; 1.206 + } else if (in_word >= 0xd800 && in_word <= 0xdbff) { 1.207 + // High surrogate. 1.208 + unichar = (in_word - 0xd7c0) << 10; 1.209 + if (++iterator == in.end()) { 1.210 + BPLOG(ERROR) << "UTF16ToUTF8 found high surrogate " << 1.211 + HexString(in_word) << " at end of string"; 1.212 + return NULL; 1.213 + } 1.214 + uint32_t high_word = in_word; 1.215 + in_word = *iterator; 1.216 + if (in_word < 0xdc00 || in_word > 0xdcff) { 1.217 + BPLOG(ERROR) << "UTF16ToUTF8 found high surrogate " << 1.218 + HexString(high_word) << " without low " << 1.219 + HexString(in_word); 1.220 + return NULL; 1.221 + } 1.222 + unichar |= in_word & 0x03ff; 1.223 + } else { 1.224 + // The ordinary case, a single non-surrogate Unicode character encoded 1.225 + // as a single 16-bit value. 1.226 + unichar = in_word; 1.227 + } 1.228 + 1.229 + // Convert the Unicode code point (unichar) into its UTF-8 representation, 1.230 + // appending it to the out string. 1.231 + if (unichar < 0x80) { 1.232 + (*out) += unichar; 1.233 + } else if (unichar < 0x800) { 1.234 + (*out) += 0xc0 | (unichar >> 6); 1.235 + (*out) += 0x80 | (unichar & 0x3f); 1.236 + } else if (unichar < 0x10000) { 1.237 + (*out) += 0xe0 | (unichar >> 12); 1.238 + (*out) += 0x80 | ((unichar >> 6) & 0x3f); 1.239 + (*out) += 0x80 | (unichar & 0x3f); 1.240 + } else if (unichar < 0x200000) { 1.241 + (*out) += 0xf0 | (unichar >> 18); 1.242 + (*out) += 0x80 | ((unichar >> 12) & 0x3f); 1.243 + (*out) += 0x80 | ((unichar >> 6) & 0x3f); 1.244 + (*out) += 0x80 | (unichar & 0x3f); 1.245 + } else { 1.246 + BPLOG(ERROR) << "UTF16ToUTF8 cannot represent high value " << 1.247 + HexString(unichar) << " in UTF-8"; 1.248 + return NULL; 1.249 + } 1.250 + } 1.251 + 1.252 + return out.release(); 1.253 +} 1.254 + 1.255 +// Return the smaller of the number of code units in the UTF-16 string, 1.256 +// not including the terminating null word, or maxlen. 1.257 +static size_t UTF16codeunits(const uint16_t *string, size_t maxlen) { 1.258 + size_t count = 0; 1.259 + while (count < maxlen && string[count] != 0) 1.260 + count++; 1.261 + return count; 1.262 +} 1.263 + 1.264 + 1.265 +// 1.266 +// MinidumpObject 1.267 +// 1.268 + 1.269 + 1.270 +MinidumpObject::MinidumpObject(Minidump* minidump) 1.271 + : minidump_(minidump), 1.272 + valid_(false) { 1.273 +} 1.274 + 1.275 + 1.276 +// 1.277 +// MinidumpStream 1.278 +// 1.279 + 1.280 + 1.281 +MinidumpStream::MinidumpStream(Minidump* minidump) 1.282 + : MinidumpObject(minidump) { 1.283 +} 1.284 + 1.285 + 1.286 +// 1.287 +// MinidumpContext 1.288 +// 1.289 + 1.290 + 1.291 +MinidumpContext::MinidumpContext(Minidump* minidump) 1.292 + : MinidumpStream(minidump), 1.293 + context_(), 1.294 + context_flags_(0) { 1.295 +} 1.296 + 1.297 + 1.298 +MinidumpContext::~MinidumpContext() { 1.299 + FreeContext(); 1.300 +} 1.301 + 1.302 + 1.303 +bool MinidumpContext::Read(uint32_t expected_size) { 1.304 + valid_ = false; 1.305 + 1.306 + FreeContext(); 1.307 + 1.308 + // First, figure out what type of CPU this context structure is for. 1.309 + // For some reason, the AMD64 Context doesn't have context_flags 1.310 + // at the beginning of the structure, so special case it here. 1.311 + if (expected_size == sizeof(MDRawContextAMD64)) { 1.312 + BPLOG(INFO) << "MinidumpContext: looks like AMD64 context"; 1.313 + 1.314 + scoped_ptr<MDRawContextAMD64> context_amd64(new MDRawContextAMD64()); 1.315 + if (!minidump_->ReadBytes(context_amd64.get(), 1.316 + sizeof(MDRawContextAMD64))) { 1.317 + BPLOG(ERROR) << "MinidumpContext could not read amd64 context"; 1.318 + return false; 1.319 + } 1.320 + 1.321 + if (minidump_->swap()) 1.322 + Swap(&context_amd64->context_flags); 1.323 + 1.324 + uint32_t cpu_type = context_amd64->context_flags & MD_CONTEXT_CPU_MASK; 1.325 + if (cpu_type == 0) { 1.326 + if (minidump_->GetContextCPUFlagsFromSystemInfo(&cpu_type)) { 1.327 + context_amd64->context_flags |= cpu_type; 1.328 + } else { 1.329 + BPLOG(ERROR) << "Failed to preserve the current stream position"; 1.330 + return false; 1.331 + } 1.332 + } 1.333 + 1.334 + if (cpu_type != MD_CONTEXT_AMD64) { 1.335 + //TODO: fall through to switch below? 1.336 + // need a Tell method to be able to SeekSet back to beginning 1.337 + // http://code.google.com/p/google-breakpad/issues/detail?id=224 1.338 + BPLOG(ERROR) << "MinidumpContext not actually amd64 context"; 1.339 + return false; 1.340 + } 1.341 + 1.342 + // Do this after reading the entire MDRawContext structure because 1.343 + // GetSystemInfo may seek minidump to a new position. 1.344 + if (!CheckAgainstSystemInfo(cpu_type)) { 1.345 + BPLOG(ERROR) << "MinidumpContext amd64 does not match system info"; 1.346 + return false; 1.347 + } 1.348 + 1.349 + // Normalize the 128-bit types in the dump. 1.350 + // Since this is AMD64, by definition, the values are little-endian. 1.351 + for (unsigned int vr_index = 0; 1.352 + vr_index < MD_CONTEXT_AMD64_VR_COUNT; 1.353 + ++vr_index) 1.354 + Normalize128(&context_amd64->vector_register[vr_index], false); 1.355 + 1.356 + if (minidump_->swap()) { 1.357 + Swap(&context_amd64->p1_home); 1.358 + Swap(&context_amd64->p2_home); 1.359 + Swap(&context_amd64->p3_home); 1.360 + Swap(&context_amd64->p4_home); 1.361 + Swap(&context_amd64->p5_home); 1.362 + Swap(&context_amd64->p6_home); 1.363 + // context_flags is already swapped 1.364 + Swap(&context_amd64->mx_csr); 1.365 + Swap(&context_amd64->cs); 1.366 + Swap(&context_amd64->ds); 1.367 + Swap(&context_amd64->es); 1.368 + Swap(&context_amd64->fs); 1.369 + Swap(&context_amd64->ss); 1.370 + Swap(&context_amd64->eflags); 1.371 + Swap(&context_amd64->dr0); 1.372 + Swap(&context_amd64->dr1); 1.373 + Swap(&context_amd64->dr2); 1.374 + Swap(&context_amd64->dr3); 1.375 + Swap(&context_amd64->dr6); 1.376 + Swap(&context_amd64->dr7); 1.377 + Swap(&context_amd64->rax); 1.378 + Swap(&context_amd64->rcx); 1.379 + Swap(&context_amd64->rdx); 1.380 + Swap(&context_amd64->rbx); 1.381 + Swap(&context_amd64->rsp); 1.382 + Swap(&context_amd64->rbp); 1.383 + Swap(&context_amd64->rsi); 1.384 + Swap(&context_amd64->rdi); 1.385 + Swap(&context_amd64->r8); 1.386 + Swap(&context_amd64->r9); 1.387 + Swap(&context_amd64->r10); 1.388 + Swap(&context_amd64->r11); 1.389 + Swap(&context_amd64->r12); 1.390 + Swap(&context_amd64->r13); 1.391 + Swap(&context_amd64->r14); 1.392 + Swap(&context_amd64->r15); 1.393 + Swap(&context_amd64->rip); 1.394 + //FIXME: I'm not sure what actually determines 1.395 + // which member of the union {flt_save, sse_registers} 1.396 + // is valid. We're not currently using either, 1.397 + // but it would be good to have them swapped properly. 1.398 + 1.399 + for (unsigned int vr_index = 0; 1.400 + vr_index < MD_CONTEXT_AMD64_VR_COUNT; 1.401 + ++vr_index) 1.402 + Swap(&context_amd64->vector_register[vr_index]); 1.403 + Swap(&context_amd64->vector_control); 1.404 + Swap(&context_amd64->debug_control); 1.405 + Swap(&context_amd64->last_branch_to_rip); 1.406 + Swap(&context_amd64->last_branch_from_rip); 1.407 + Swap(&context_amd64->last_exception_to_rip); 1.408 + Swap(&context_amd64->last_exception_from_rip); 1.409 + } 1.410 + 1.411 + context_flags_ = context_amd64->context_flags; 1.412 + 1.413 + context_.amd64 = context_amd64.release(); 1.414 + } 1.415 + else { 1.416 + uint32_t context_flags; 1.417 + if (!minidump_->ReadBytes(&context_flags, sizeof(context_flags))) { 1.418 + BPLOG(ERROR) << "MinidumpContext could not read context flags"; 1.419 + return false; 1.420 + } 1.421 + if (minidump_->swap()) 1.422 + Swap(&context_flags); 1.423 + 1.424 + uint32_t cpu_type = context_flags & MD_CONTEXT_CPU_MASK; 1.425 + if (cpu_type == 0) { 1.426 + // Unfortunately the flag for MD_CONTEXT_ARM that was taken 1.427 + // from a Windows CE SDK header conflicts in practice with 1.428 + // the CONTEXT_XSTATE flag. MD_CONTEXT_ARM has been renumbered, 1.429 + // but handle dumps with the legacy value gracefully here. 1.430 + if (context_flags & MD_CONTEXT_ARM_OLD) { 1.431 + context_flags |= MD_CONTEXT_ARM; 1.432 + context_flags &= ~MD_CONTEXT_ARM_OLD; 1.433 + cpu_type = MD_CONTEXT_ARM; 1.434 + } 1.435 + } 1.436 + 1.437 + if (cpu_type == 0) { 1.438 + if (minidump_->GetContextCPUFlagsFromSystemInfo(&cpu_type)) { 1.439 + context_flags |= cpu_type; 1.440 + } else { 1.441 + BPLOG(ERROR) << "Failed to preserve the current stream position"; 1.442 + return false; 1.443 + } 1.444 + } 1.445 + 1.446 + // Allocate the context structure for the correct CPU and fill it. The 1.447 + // casts are slightly unorthodox, but it seems better to do that than to 1.448 + // maintain a separate pointer for each type of CPU context structure 1.449 + // when only one of them will be used. 1.450 + switch (cpu_type) { 1.451 + case MD_CONTEXT_X86: { 1.452 + if (expected_size != sizeof(MDRawContextX86)) { 1.453 + BPLOG(ERROR) << "MinidumpContext x86 size mismatch, " << 1.454 + expected_size << " != " << sizeof(MDRawContextX86); 1.455 + return false; 1.456 + } 1.457 + 1.458 + scoped_ptr<MDRawContextX86> context_x86(new MDRawContextX86()); 1.459 + 1.460 + // Set the context_flags member, which has already been read, and 1.461 + // read the rest of the structure beginning with the first member 1.462 + // after context_flags. 1.463 + context_x86->context_flags = context_flags; 1.464 + 1.465 + size_t flags_size = sizeof(context_x86->context_flags); 1.466 + uint8_t* context_after_flags = 1.467 + reinterpret_cast<uint8_t*>(context_x86.get()) + flags_size; 1.468 + if (!minidump_->ReadBytes(context_after_flags, 1.469 + sizeof(MDRawContextX86) - flags_size)) { 1.470 + BPLOG(ERROR) << "MinidumpContext could not read x86 context"; 1.471 + return false; 1.472 + } 1.473 + 1.474 + // Do this after reading the entire MDRawContext structure because 1.475 + // GetSystemInfo may seek minidump to a new position. 1.476 + if (!CheckAgainstSystemInfo(cpu_type)) { 1.477 + BPLOG(ERROR) << "MinidumpContext x86 does not match system info"; 1.478 + return false; 1.479 + } 1.480 + 1.481 + if (minidump_->swap()) { 1.482 + // context_x86->context_flags was already swapped. 1.483 + Swap(&context_x86->dr0); 1.484 + Swap(&context_x86->dr1); 1.485 + Swap(&context_x86->dr2); 1.486 + Swap(&context_x86->dr3); 1.487 + Swap(&context_x86->dr6); 1.488 + Swap(&context_x86->dr7); 1.489 + Swap(&context_x86->float_save.control_word); 1.490 + Swap(&context_x86->float_save.status_word); 1.491 + Swap(&context_x86->float_save.tag_word); 1.492 + Swap(&context_x86->float_save.error_offset); 1.493 + Swap(&context_x86->float_save.error_selector); 1.494 + Swap(&context_x86->float_save.data_offset); 1.495 + Swap(&context_x86->float_save.data_selector); 1.496 + // context_x86->float_save.register_area[] contains 8-bit quantities 1.497 + // and does not need to be swapped. 1.498 + Swap(&context_x86->float_save.cr0_npx_state); 1.499 + Swap(&context_x86->gs); 1.500 + Swap(&context_x86->fs); 1.501 + Swap(&context_x86->es); 1.502 + Swap(&context_x86->ds); 1.503 + Swap(&context_x86->edi); 1.504 + Swap(&context_x86->esi); 1.505 + Swap(&context_x86->ebx); 1.506 + Swap(&context_x86->edx); 1.507 + Swap(&context_x86->ecx); 1.508 + Swap(&context_x86->eax); 1.509 + Swap(&context_x86->ebp); 1.510 + Swap(&context_x86->eip); 1.511 + Swap(&context_x86->cs); 1.512 + Swap(&context_x86->eflags); 1.513 + Swap(&context_x86->esp); 1.514 + Swap(&context_x86->ss); 1.515 + // context_x86->extended_registers[] contains 8-bit quantities and 1.516 + // does not need to be swapped. 1.517 + } 1.518 + 1.519 + context_.x86 = context_x86.release(); 1.520 + 1.521 + break; 1.522 + } 1.523 + 1.524 + case MD_CONTEXT_PPC: { 1.525 + if (expected_size != sizeof(MDRawContextPPC)) { 1.526 + BPLOG(ERROR) << "MinidumpContext ppc size mismatch, " << 1.527 + expected_size << " != " << sizeof(MDRawContextPPC); 1.528 + return false; 1.529 + } 1.530 + 1.531 + scoped_ptr<MDRawContextPPC> context_ppc(new MDRawContextPPC()); 1.532 + 1.533 + // Set the context_flags member, which has already been read, and 1.534 + // read the rest of the structure beginning with the first member 1.535 + // after context_flags. 1.536 + context_ppc->context_flags = context_flags; 1.537 + 1.538 + size_t flags_size = sizeof(context_ppc->context_flags); 1.539 + uint8_t* context_after_flags = 1.540 + reinterpret_cast<uint8_t*>(context_ppc.get()) + flags_size; 1.541 + if (!minidump_->ReadBytes(context_after_flags, 1.542 + sizeof(MDRawContextPPC) - flags_size)) { 1.543 + BPLOG(ERROR) << "MinidumpContext could not read ppc context"; 1.544 + return false; 1.545 + } 1.546 + 1.547 + // Do this after reading the entire MDRawContext structure because 1.548 + // GetSystemInfo may seek minidump to a new position. 1.549 + if (!CheckAgainstSystemInfo(cpu_type)) { 1.550 + BPLOG(ERROR) << "MinidumpContext ppc does not match system info"; 1.551 + return false; 1.552 + } 1.553 + 1.554 + // Normalize the 128-bit types in the dump. 1.555 + // Since this is PowerPC, by definition, the values are big-endian. 1.556 + for (unsigned int vr_index = 0; 1.557 + vr_index < MD_VECTORSAVEAREA_PPC_VR_COUNT; 1.558 + ++vr_index) { 1.559 + Normalize128(&context_ppc->vector_save.save_vr[vr_index], true); 1.560 + } 1.561 + 1.562 + if (minidump_->swap()) { 1.563 + // context_ppc->context_flags was already swapped. 1.564 + Swap(&context_ppc->srr0); 1.565 + Swap(&context_ppc->srr1); 1.566 + for (unsigned int gpr_index = 0; 1.567 + gpr_index < MD_CONTEXT_PPC_GPR_COUNT; 1.568 + ++gpr_index) { 1.569 + Swap(&context_ppc->gpr[gpr_index]); 1.570 + } 1.571 + Swap(&context_ppc->cr); 1.572 + Swap(&context_ppc->xer); 1.573 + Swap(&context_ppc->lr); 1.574 + Swap(&context_ppc->ctr); 1.575 + Swap(&context_ppc->mq); 1.576 + Swap(&context_ppc->vrsave); 1.577 + for (unsigned int fpr_index = 0; 1.578 + fpr_index < MD_FLOATINGSAVEAREA_PPC_FPR_COUNT; 1.579 + ++fpr_index) { 1.580 + Swap(&context_ppc->float_save.fpregs[fpr_index]); 1.581 + } 1.582 + // Don't swap context_ppc->float_save.fpscr_pad because it is only 1.583 + // used for padding. 1.584 + Swap(&context_ppc->float_save.fpscr); 1.585 + for (unsigned int vr_index = 0; 1.586 + vr_index < MD_VECTORSAVEAREA_PPC_VR_COUNT; 1.587 + ++vr_index) { 1.588 + Swap(&context_ppc->vector_save.save_vr[vr_index]); 1.589 + } 1.590 + Swap(&context_ppc->vector_save.save_vscr); 1.591 + // Don't swap the padding fields in vector_save. 1.592 + Swap(&context_ppc->vector_save.save_vrvalid); 1.593 + } 1.594 + 1.595 + context_.ppc = context_ppc.release(); 1.596 + 1.597 + break; 1.598 + } 1.599 + 1.600 + case MD_CONTEXT_SPARC: { 1.601 + if (expected_size != sizeof(MDRawContextSPARC)) { 1.602 + BPLOG(ERROR) << "MinidumpContext sparc size mismatch, " << 1.603 + expected_size << " != " << sizeof(MDRawContextSPARC); 1.604 + return false; 1.605 + } 1.606 + 1.607 + scoped_ptr<MDRawContextSPARC> context_sparc(new MDRawContextSPARC()); 1.608 + 1.609 + // Set the context_flags member, which has already been read, and 1.610 + // read the rest of the structure beginning with the first member 1.611 + // after context_flags. 1.612 + context_sparc->context_flags = context_flags; 1.613 + 1.614 + size_t flags_size = sizeof(context_sparc->context_flags); 1.615 + uint8_t* context_after_flags = 1.616 + reinterpret_cast<uint8_t*>(context_sparc.get()) + flags_size; 1.617 + if (!minidump_->ReadBytes(context_after_flags, 1.618 + sizeof(MDRawContextSPARC) - flags_size)) { 1.619 + BPLOG(ERROR) << "MinidumpContext could not read sparc context"; 1.620 + return false; 1.621 + } 1.622 + 1.623 + // Do this after reading the entire MDRawContext structure because 1.624 + // GetSystemInfo may seek minidump to a new position. 1.625 + if (!CheckAgainstSystemInfo(cpu_type)) { 1.626 + BPLOG(ERROR) << "MinidumpContext sparc does not match system info"; 1.627 + return false; 1.628 + } 1.629 + 1.630 + if (minidump_->swap()) { 1.631 + // context_sparc->context_flags was already swapped. 1.632 + for (unsigned int gpr_index = 0; 1.633 + gpr_index < MD_CONTEXT_SPARC_GPR_COUNT; 1.634 + ++gpr_index) { 1.635 + Swap(&context_sparc->g_r[gpr_index]); 1.636 + } 1.637 + Swap(&context_sparc->ccr); 1.638 + Swap(&context_sparc->pc); 1.639 + Swap(&context_sparc->npc); 1.640 + Swap(&context_sparc->y); 1.641 + Swap(&context_sparc->asi); 1.642 + Swap(&context_sparc->fprs); 1.643 + for (unsigned int fpr_index = 0; 1.644 + fpr_index < MD_FLOATINGSAVEAREA_SPARC_FPR_COUNT; 1.645 + ++fpr_index) { 1.646 + Swap(&context_sparc->float_save.regs[fpr_index]); 1.647 + } 1.648 + Swap(&context_sparc->float_save.filler); 1.649 + Swap(&context_sparc->float_save.fsr); 1.650 + } 1.651 + context_.ctx_sparc = context_sparc.release(); 1.652 + 1.653 + break; 1.654 + } 1.655 + 1.656 + case MD_CONTEXT_ARM: { 1.657 + if (expected_size != sizeof(MDRawContextARM)) { 1.658 + BPLOG(ERROR) << "MinidumpContext arm size mismatch, " << 1.659 + expected_size << " != " << sizeof(MDRawContextARM); 1.660 + return false; 1.661 + } 1.662 + 1.663 + scoped_ptr<MDRawContextARM> context_arm(new MDRawContextARM()); 1.664 + 1.665 + // Set the context_flags member, which has already been read, and 1.666 + // read the rest of the structure beginning with the first member 1.667 + // after context_flags. 1.668 + context_arm->context_flags = context_flags; 1.669 + 1.670 + size_t flags_size = sizeof(context_arm->context_flags); 1.671 + uint8_t* context_after_flags = 1.672 + reinterpret_cast<uint8_t*>(context_arm.get()) + flags_size; 1.673 + if (!minidump_->ReadBytes(context_after_flags, 1.674 + sizeof(MDRawContextARM) - flags_size)) { 1.675 + BPLOG(ERROR) << "MinidumpContext could not read arm context"; 1.676 + return false; 1.677 + } 1.678 + 1.679 + // Do this after reading the entire MDRawContext structure because 1.680 + // GetSystemInfo may seek minidump to a new position. 1.681 + if (!CheckAgainstSystemInfo(cpu_type)) { 1.682 + BPLOG(ERROR) << "MinidumpContext arm does not match system info"; 1.683 + return false; 1.684 + } 1.685 + 1.686 + if (minidump_->swap()) { 1.687 + // context_arm->context_flags was already swapped. 1.688 + for (unsigned int ireg_index = 0; 1.689 + ireg_index < MD_CONTEXT_ARM_GPR_COUNT; 1.690 + ++ireg_index) { 1.691 + Swap(&context_arm->iregs[ireg_index]); 1.692 + } 1.693 + Swap(&context_arm->cpsr); 1.694 + Swap(&context_arm->float_save.fpscr); 1.695 + for (unsigned int fpr_index = 0; 1.696 + fpr_index < MD_FLOATINGSAVEAREA_ARM_FPR_COUNT; 1.697 + ++fpr_index) { 1.698 + Swap(&context_arm->float_save.regs[fpr_index]); 1.699 + } 1.700 + for (unsigned int fpe_index = 0; 1.701 + fpe_index < MD_FLOATINGSAVEAREA_ARM_FPEXTRA_COUNT; 1.702 + ++fpe_index) { 1.703 + Swap(&context_arm->float_save.extra[fpe_index]); 1.704 + } 1.705 + } 1.706 + context_.arm = context_arm.release(); 1.707 + 1.708 + break; 1.709 + } 1.710 + 1.711 + default: { 1.712 + // Unknown context type - Don't log as an error yet. Let the 1.713 + // caller work that out. 1.714 + BPLOG(INFO) << "MinidumpContext unknown context type " << 1.715 + HexString(cpu_type); 1.716 + return false; 1.717 + break; 1.718 + } 1.719 + } 1.720 + context_flags_ = context_flags; 1.721 + } 1.722 + 1.723 + valid_ = true; 1.724 + return true; 1.725 +} 1.726 + 1.727 + 1.728 +uint32_t MinidumpContext::GetContextCPU() const { 1.729 + if (!valid_) { 1.730 + // Don't log a message, GetContextCPU can be legitimately called with 1.731 + // valid_ false by FreeContext, which is called by Read. 1.732 + return 0; 1.733 + } 1.734 + 1.735 + return context_flags_ & MD_CONTEXT_CPU_MASK; 1.736 +} 1.737 + 1.738 +bool MinidumpContext::GetInstructionPointer(uint64_t* ip) const { 1.739 + BPLOG_IF(ERROR, !ip) << "MinidumpContext::GetInstructionPointer " 1.740 + "requires |ip|"; 1.741 + assert(ip); 1.742 + *ip = 0; 1.743 + 1.744 + if (!valid_) { 1.745 + BPLOG(ERROR) << "Invalid MinidumpContext for GetInstructionPointer"; 1.746 + return false; 1.747 + } 1.748 + 1.749 + switch (context_flags_ & MD_CONTEXT_CPU_MASK) { 1.750 + case MD_CONTEXT_AMD64: 1.751 + *ip = context_.amd64->rip; 1.752 + break; 1.753 + case MD_CONTEXT_ARM: 1.754 + *ip = context_.arm->iregs[MD_CONTEXT_ARM_REG_PC]; 1.755 + break; 1.756 + case MD_CONTEXT_PPC: 1.757 + *ip = context_.ppc->srr0; 1.758 + break; 1.759 + case MD_CONTEXT_SPARC: 1.760 + *ip = context_.ctx_sparc->pc; 1.761 + break; 1.762 + case MD_CONTEXT_X86: 1.763 + *ip = context_.x86->eip; 1.764 + break; 1.765 + default: 1.766 + // This should never happen. 1.767 + BPLOG(ERROR) << "Unknown CPU architecture in GetInstructionPointer"; 1.768 + return false; 1.769 + } 1.770 + return true; 1.771 +} 1.772 + 1.773 + 1.774 +const MDRawContextX86* MinidumpContext::GetContextX86() const { 1.775 + if (GetContextCPU() != MD_CONTEXT_X86) { 1.776 + BPLOG(ERROR) << "MinidumpContext cannot get x86 context"; 1.777 + return NULL; 1.778 + } 1.779 + 1.780 + return context_.x86; 1.781 +} 1.782 + 1.783 + 1.784 +const MDRawContextPPC* MinidumpContext::GetContextPPC() const { 1.785 + if (GetContextCPU() != MD_CONTEXT_PPC) { 1.786 + BPLOG(ERROR) << "MinidumpContext cannot get ppc context"; 1.787 + return NULL; 1.788 + } 1.789 + 1.790 + return context_.ppc; 1.791 +} 1.792 + 1.793 +const MDRawContextAMD64* MinidumpContext::GetContextAMD64() const { 1.794 + if (GetContextCPU() != MD_CONTEXT_AMD64) { 1.795 + BPLOG(ERROR) << "MinidumpContext cannot get amd64 context"; 1.796 + return NULL; 1.797 + } 1.798 + 1.799 + return context_.amd64; 1.800 +} 1.801 + 1.802 +const MDRawContextSPARC* MinidumpContext::GetContextSPARC() const { 1.803 + if (GetContextCPU() != MD_CONTEXT_SPARC) { 1.804 + BPLOG(ERROR) << "MinidumpContext cannot get sparc context"; 1.805 + return NULL; 1.806 + } 1.807 + 1.808 + return context_.ctx_sparc; 1.809 +} 1.810 + 1.811 +const MDRawContextARM* MinidumpContext::GetContextARM() const { 1.812 + if (GetContextCPU() != MD_CONTEXT_ARM) { 1.813 + BPLOG(ERROR) << "MinidumpContext cannot get arm context"; 1.814 + return NULL; 1.815 + } 1.816 + 1.817 + return context_.arm; 1.818 +} 1.819 + 1.820 +void MinidumpContext::FreeContext() { 1.821 + switch (GetContextCPU()) { 1.822 + case MD_CONTEXT_X86: 1.823 + delete context_.x86; 1.824 + break; 1.825 + 1.826 + case MD_CONTEXT_PPC: 1.827 + delete context_.ppc; 1.828 + break; 1.829 + 1.830 + case MD_CONTEXT_AMD64: 1.831 + delete context_.amd64; 1.832 + break; 1.833 + 1.834 + case MD_CONTEXT_SPARC: 1.835 + delete context_.ctx_sparc; 1.836 + break; 1.837 + 1.838 + case MD_CONTEXT_ARM: 1.839 + delete context_.arm; 1.840 + break; 1.841 + 1.842 + default: 1.843 + // There is no context record (valid_ is false) or there's a 1.844 + // context record for an unknown CPU (shouldn't happen, only known 1.845 + // records are stored by Read). 1.846 + break; 1.847 + } 1.848 + 1.849 + context_flags_ = 0; 1.850 + context_.base = NULL; 1.851 +} 1.852 + 1.853 + 1.854 +bool MinidumpContext::CheckAgainstSystemInfo(uint32_t context_cpu_type) { 1.855 + // It's OK if the minidump doesn't contain an MD_SYSTEM_INFO_STREAM, 1.856 + // as this function just implements a sanity check. 1.857 + MinidumpSystemInfo* system_info = minidump_->GetSystemInfo(); 1.858 + if (!system_info) { 1.859 + BPLOG(INFO) << "MinidumpContext could not be compared against " 1.860 + "MinidumpSystemInfo"; 1.861 + return true; 1.862 + } 1.863 + 1.864 + // If there is an MD_SYSTEM_INFO_STREAM, it should contain valid system info. 1.865 + const MDRawSystemInfo* raw_system_info = system_info->system_info(); 1.866 + if (!raw_system_info) { 1.867 + BPLOG(INFO) << "MinidumpContext could not be compared against " 1.868 + "MDRawSystemInfo"; 1.869 + return false; 1.870 + } 1.871 + 1.872 + MDCPUArchitecture system_info_cpu_type = static_cast<MDCPUArchitecture>( 1.873 + raw_system_info->processor_architecture); 1.874 + 1.875 + // Compare the CPU type of the context record to the CPU type in the 1.876 + // minidump's system info stream. 1.877 + bool return_value = false; 1.878 + switch (context_cpu_type) { 1.879 + case MD_CONTEXT_X86: 1.880 + if (system_info_cpu_type == MD_CPU_ARCHITECTURE_X86 || 1.881 + system_info_cpu_type == MD_CPU_ARCHITECTURE_X86_WIN64 || 1.882 + system_info_cpu_type == MD_CPU_ARCHITECTURE_AMD64) { 1.883 + return_value = true; 1.884 + } 1.885 + break; 1.886 + 1.887 + case MD_CONTEXT_PPC: 1.888 + if (system_info_cpu_type == MD_CPU_ARCHITECTURE_PPC) 1.889 + return_value = true; 1.890 + break; 1.891 + 1.892 + case MD_CONTEXT_AMD64: 1.893 + if (system_info_cpu_type == MD_CPU_ARCHITECTURE_AMD64) 1.894 + return_value = true; 1.895 + break; 1.896 + 1.897 + case MD_CONTEXT_SPARC: 1.898 + if (system_info_cpu_type == MD_CPU_ARCHITECTURE_SPARC) 1.899 + return_value = true; 1.900 + break; 1.901 + 1.902 + case MD_CONTEXT_ARM: 1.903 + if (system_info_cpu_type == MD_CPU_ARCHITECTURE_ARM) 1.904 + return_value = true; 1.905 + break; 1.906 + } 1.907 + 1.908 + BPLOG_IF(ERROR, !return_value) << "MinidumpContext CPU " << 1.909 + HexString(context_cpu_type) << 1.910 + " wrong for MinidumpSystemInfo CPU " << 1.911 + HexString(system_info_cpu_type); 1.912 + 1.913 + return return_value; 1.914 +} 1.915 + 1.916 + 1.917 +void MinidumpContext::Print() { 1.918 + if (!valid_) { 1.919 + BPLOG(ERROR) << "MinidumpContext cannot print invalid data"; 1.920 + return; 1.921 + } 1.922 + 1.923 + switch (GetContextCPU()) { 1.924 + case MD_CONTEXT_X86: { 1.925 + const MDRawContextX86* context_x86 = GetContextX86(); 1.926 + printf("MDRawContextX86\n"); 1.927 + printf(" context_flags = 0x%x\n", 1.928 + context_x86->context_flags); 1.929 + printf(" dr0 = 0x%x\n", context_x86->dr0); 1.930 + printf(" dr1 = 0x%x\n", context_x86->dr1); 1.931 + printf(" dr2 = 0x%x\n", context_x86->dr2); 1.932 + printf(" dr3 = 0x%x\n", context_x86->dr3); 1.933 + printf(" dr6 = 0x%x\n", context_x86->dr6); 1.934 + printf(" dr7 = 0x%x\n", context_x86->dr7); 1.935 + printf(" float_save.control_word = 0x%x\n", 1.936 + context_x86->float_save.control_word); 1.937 + printf(" float_save.status_word = 0x%x\n", 1.938 + context_x86->float_save.status_word); 1.939 + printf(" float_save.tag_word = 0x%x\n", 1.940 + context_x86->float_save.tag_word); 1.941 + printf(" float_save.error_offset = 0x%x\n", 1.942 + context_x86->float_save.error_offset); 1.943 + printf(" float_save.error_selector = 0x%x\n", 1.944 + context_x86->float_save.error_selector); 1.945 + printf(" float_save.data_offset = 0x%x\n", 1.946 + context_x86->float_save.data_offset); 1.947 + printf(" float_save.data_selector = 0x%x\n", 1.948 + context_x86->float_save.data_selector); 1.949 + printf(" float_save.register_area[%2d] = 0x", 1.950 + MD_FLOATINGSAVEAREA_X86_REGISTERAREA_SIZE); 1.951 + for (unsigned int register_index = 0; 1.952 + register_index < MD_FLOATINGSAVEAREA_X86_REGISTERAREA_SIZE; 1.953 + ++register_index) { 1.954 + printf("%02x", context_x86->float_save.register_area[register_index]); 1.955 + } 1.956 + printf("\n"); 1.957 + printf(" float_save.cr0_npx_state = 0x%x\n", 1.958 + context_x86->float_save.cr0_npx_state); 1.959 + printf(" gs = 0x%x\n", context_x86->gs); 1.960 + printf(" fs = 0x%x\n", context_x86->fs); 1.961 + printf(" es = 0x%x\n", context_x86->es); 1.962 + printf(" ds = 0x%x\n", context_x86->ds); 1.963 + printf(" edi = 0x%x\n", context_x86->edi); 1.964 + printf(" esi = 0x%x\n", context_x86->esi); 1.965 + printf(" ebx = 0x%x\n", context_x86->ebx); 1.966 + printf(" edx = 0x%x\n", context_x86->edx); 1.967 + printf(" ecx = 0x%x\n", context_x86->ecx); 1.968 + printf(" eax = 0x%x\n", context_x86->eax); 1.969 + printf(" ebp = 0x%x\n", context_x86->ebp); 1.970 + printf(" eip = 0x%x\n", context_x86->eip); 1.971 + printf(" cs = 0x%x\n", context_x86->cs); 1.972 + printf(" eflags = 0x%x\n", context_x86->eflags); 1.973 + printf(" esp = 0x%x\n", context_x86->esp); 1.974 + printf(" ss = 0x%x\n", context_x86->ss); 1.975 + printf(" extended_registers[%3d] = 0x", 1.976 + MD_CONTEXT_X86_EXTENDED_REGISTERS_SIZE); 1.977 + for (unsigned int register_index = 0; 1.978 + register_index < MD_CONTEXT_X86_EXTENDED_REGISTERS_SIZE; 1.979 + ++register_index) { 1.980 + printf("%02x", context_x86->extended_registers[register_index]); 1.981 + } 1.982 + printf("\n\n"); 1.983 + 1.984 + break; 1.985 + } 1.986 + 1.987 + case MD_CONTEXT_PPC: { 1.988 + const MDRawContextPPC* context_ppc = GetContextPPC(); 1.989 + printf("MDRawContextPPC\n"); 1.990 + printf(" context_flags = 0x%x\n", 1.991 + context_ppc->context_flags); 1.992 + printf(" srr0 = 0x%x\n", context_ppc->srr0); 1.993 + printf(" srr1 = 0x%x\n", context_ppc->srr1); 1.994 + for (unsigned int gpr_index = 0; 1.995 + gpr_index < MD_CONTEXT_PPC_GPR_COUNT; 1.996 + ++gpr_index) { 1.997 + printf(" gpr[%2d] = 0x%x\n", 1.998 + gpr_index, context_ppc->gpr[gpr_index]); 1.999 + } 1.1000 + printf(" cr = 0x%x\n", context_ppc->cr); 1.1001 + printf(" xer = 0x%x\n", context_ppc->xer); 1.1002 + printf(" lr = 0x%x\n", context_ppc->lr); 1.1003 + printf(" ctr = 0x%x\n", context_ppc->ctr); 1.1004 + printf(" mq = 0x%x\n", context_ppc->mq); 1.1005 + printf(" vrsave = 0x%x\n", context_ppc->vrsave); 1.1006 + for (unsigned int fpr_index = 0; 1.1007 + fpr_index < MD_FLOATINGSAVEAREA_PPC_FPR_COUNT; 1.1008 + ++fpr_index) { 1.1009 + printf(" float_save.fpregs[%2d] = 0x%" PRIx64 "\n", 1.1010 + fpr_index, context_ppc->float_save.fpregs[fpr_index]); 1.1011 + } 1.1012 + printf(" float_save.fpscr = 0x%x\n", 1.1013 + context_ppc->float_save.fpscr); 1.1014 + // TODO(mmentovai): print the 128-bit quantities in 1.1015 + // context_ppc->vector_save. This isn't done yet because printf 1.1016 + // doesn't support 128-bit quantities, and printing them using 1.1017 + // PRIx64 as two 64-bit quantities requires knowledge of the CPU's 1.1018 + // byte ordering. 1.1019 + printf(" vector_save.save_vrvalid = 0x%x\n", 1.1020 + context_ppc->vector_save.save_vrvalid); 1.1021 + printf("\n"); 1.1022 + 1.1023 + break; 1.1024 + } 1.1025 + 1.1026 + case MD_CONTEXT_AMD64: { 1.1027 + const MDRawContextAMD64* context_amd64 = GetContextAMD64(); 1.1028 + printf("MDRawContextAMD64\n"); 1.1029 + printf(" p1_home = 0x%" PRIx64 "\n", 1.1030 + context_amd64->p1_home); 1.1031 + printf(" p2_home = 0x%" PRIx64 "\n", 1.1032 + context_amd64->p2_home); 1.1033 + printf(" p3_home = 0x%" PRIx64 "\n", 1.1034 + context_amd64->p3_home); 1.1035 + printf(" p4_home = 0x%" PRIx64 "\n", 1.1036 + context_amd64->p4_home); 1.1037 + printf(" p5_home = 0x%" PRIx64 "\n", 1.1038 + context_amd64->p5_home); 1.1039 + printf(" p6_home = 0x%" PRIx64 "\n", 1.1040 + context_amd64->p6_home); 1.1041 + printf(" context_flags = 0x%x\n", 1.1042 + context_amd64->context_flags); 1.1043 + printf(" mx_csr = 0x%x\n", 1.1044 + context_amd64->mx_csr); 1.1045 + printf(" cs = 0x%x\n", context_amd64->cs); 1.1046 + printf(" ds = 0x%x\n", context_amd64->ds); 1.1047 + printf(" es = 0x%x\n", context_amd64->es); 1.1048 + printf(" fs = 0x%x\n", context_amd64->fs); 1.1049 + printf(" gs = 0x%x\n", context_amd64->gs); 1.1050 + printf(" ss = 0x%x\n", context_amd64->ss); 1.1051 + printf(" eflags = 0x%x\n", context_amd64->eflags); 1.1052 + printf(" dr0 = 0x%" PRIx64 "\n", context_amd64->dr0); 1.1053 + printf(" dr1 = 0x%" PRIx64 "\n", context_amd64->dr1); 1.1054 + printf(" dr2 = 0x%" PRIx64 "\n", context_amd64->dr2); 1.1055 + printf(" dr3 = 0x%" PRIx64 "\n", context_amd64->dr3); 1.1056 + printf(" dr6 = 0x%" PRIx64 "\n", context_amd64->dr6); 1.1057 + printf(" dr7 = 0x%" PRIx64 "\n", context_amd64->dr7); 1.1058 + printf(" rax = 0x%" PRIx64 "\n", context_amd64->rax); 1.1059 + printf(" rcx = 0x%" PRIx64 "\n", context_amd64->rcx); 1.1060 + printf(" rdx = 0x%" PRIx64 "\n", context_amd64->rdx); 1.1061 + printf(" rbx = 0x%" PRIx64 "\n", context_amd64->rbx); 1.1062 + printf(" rsp = 0x%" PRIx64 "\n", context_amd64->rsp); 1.1063 + printf(" rbp = 0x%" PRIx64 "\n", context_amd64->rbp); 1.1064 + printf(" rsi = 0x%" PRIx64 "\n", context_amd64->rsi); 1.1065 + printf(" rdi = 0x%" PRIx64 "\n", context_amd64->rdi); 1.1066 + printf(" r8 = 0x%" PRIx64 "\n", context_amd64->r8); 1.1067 + printf(" r9 = 0x%" PRIx64 "\n", context_amd64->r9); 1.1068 + printf(" r10 = 0x%" PRIx64 "\n", context_amd64->r10); 1.1069 + printf(" r11 = 0x%" PRIx64 "\n", context_amd64->r11); 1.1070 + printf(" r12 = 0x%" PRIx64 "\n", context_amd64->r12); 1.1071 + printf(" r13 = 0x%" PRIx64 "\n", context_amd64->r13); 1.1072 + printf(" r14 = 0x%" PRIx64 "\n", context_amd64->r14); 1.1073 + printf(" r15 = 0x%" PRIx64 "\n", context_amd64->r15); 1.1074 + printf(" rip = 0x%" PRIx64 "\n", context_amd64->rip); 1.1075 + //TODO: print xmm, vector, debug registers 1.1076 + printf("\n"); 1.1077 + break; 1.1078 + } 1.1079 + 1.1080 + case MD_CONTEXT_SPARC: { 1.1081 + const MDRawContextSPARC* context_sparc = GetContextSPARC(); 1.1082 + printf("MDRawContextSPARC\n"); 1.1083 + printf(" context_flags = 0x%x\n", 1.1084 + context_sparc->context_flags); 1.1085 + for (unsigned int g_r_index = 0; 1.1086 + g_r_index < MD_CONTEXT_SPARC_GPR_COUNT; 1.1087 + ++g_r_index) { 1.1088 + printf(" g_r[%2d] = 0x%" PRIx64 "\n", 1.1089 + g_r_index, context_sparc->g_r[g_r_index]); 1.1090 + } 1.1091 + printf(" ccr = 0x%" PRIx64 "\n", context_sparc->ccr); 1.1092 + printf(" pc = 0x%" PRIx64 "\n", context_sparc->pc); 1.1093 + printf(" npc = 0x%" PRIx64 "\n", context_sparc->npc); 1.1094 + printf(" y = 0x%" PRIx64 "\n", context_sparc->y); 1.1095 + printf(" asi = 0x%" PRIx64 "\n", context_sparc->asi); 1.1096 + printf(" fprs = 0x%" PRIx64 "\n", context_sparc->fprs); 1.1097 + 1.1098 + for (unsigned int fpr_index = 0; 1.1099 + fpr_index < MD_FLOATINGSAVEAREA_SPARC_FPR_COUNT; 1.1100 + ++fpr_index) { 1.1101 + printf(" float_save.regs[%2d] = 0x%" PRIx64 "\n", 1.1102 + fpr_index, context_sparc->float_save.regs[fpr_index]); 1.1103 + } 1.1104 + printf(" float_save.filler = 0x%" PRIx64 "\n", 1.1105 + context_sparc->float_save.filler); 1.1106 + printf(" float_save.fsr = 0x%" PRIx64 "\n", 1.1107 + context_sparc->float_save.fsr); 1.1108 + break; 1.1109 + } 1.1110 + 1.1111 + case MD_CONTEXT_ARM: { 1.1112 + const MDRawContextARM* context_arm = GetContextARM(); 1.1113 + printf("MDRawContextARM\n"); 1.1114 + printf(" context_flags = 0x%x\n", 1.1115 + context_arm->context_flags); 1.1116 + for (unsigned int ireg_index = 0; 1.1117 + ireg_index < MD_CONTEXT_ARM_GPR_COUNT; 1.1118 + ++ireg_index) { 1.1119 + printf(" iregs[%2d] = 0x%x\n", 1.1120 + ireg_index, context_arm->iregs[ireg_index]); 1.1121 + } 1.1122 + printf(" cpsr = 0x%x\n", context_arm->cpsr); 1.1123 + printf(" float_save.fpscr = 0x%" PRIx64 "\n", 1.1124 + context_arm->float_save.fpscr); 1.1125 + for (unsigned int fpr_index = 0; 1.1126 + fpr_index < MD_FLOATINGSAVEAREA_ARM_FPR_COUNT; 1.1127 + ++fpr_index) { 1.1128 + printf(" float_save.regs[%2d] = 0x%" PRIx64 "\n", 1.1129 + fpr_index, context_arm->float_save.regs[fpr_index]); 1.1130 + } 1.1131 + for (unsigned int fpe_index = 0; 1.1132 + fpe_index < MD_FLOATINGSAVEAREA_ARM_FPEXTRA_COUNT; 1.1133 + ++fpe_index) { 1.1134 + printf(" float_save.extra[%2d] = 0x%" PRIx32 "\n", 1.1135 + fpe_index, context_arm->float_save.extra[fpe_index]); 1.1136 + } 1.1137 + 1.1138 + break; 1.1139 + } 1.1140 + 1.1141 + default: { 1.1142 + break; 1.1143 + } 1.1144 + } 1.1145 +} 1.1146 + 1.1147 + 1.1148 +// 1.1149 +// MinidumpMemoryRegion 1.1150 +// 1.1151 + 1.1152 + 1.1153 +uint32_t MinidumpMemoryRegion::max_bytes_ = 1024 * 1024; // 1MB 1.1154 + 1.1155 + 1.1156 +MinidumpMemoryRegion::MinidumpMemoryRegion(Minidump* minidump) 1.1157 + : MinidumpObject(minidump), 1.1158 + descriptor_(NULL), 1.1159 + memory_(NULL) { 1.1160 +} 1.1161 + 1.1162 + 1.1163 +MinidumpMemoryRegion::~MinidumpMemoryRegion() { 1.1164 + delete memory_; 1.1165 +} 1.1166 + 1.1167 + 1.1168 +void MinidumpMemoryRegion::SetDescriptor(MDMemoryDescriptor* descriptor) { 1.1169 + descriptor_ = descriptor; 1.1170 + valid_ = descriptor && 1.1171 + descriptor_->memory.data_size <= 1.1172 + numeric_limits<uint64_t>::max() - 1.1173 + descriptor_->start_of_memory_range; 1.1174 +} 1.1175 + 1.1176 + 1.1177 +const uint8_t* MinidumpMemoryRegion::GetMemory() const { 1.1178 + if (!valid_) { 1.1179 + BPLOG(ERROR) << "Invalid MinidumpMemoryRegion for GetMemory"; 1.1180 + return NULL; 1.1181 + } 1.1182 + 1.1183 + if (!memory_) { 1.1184 + if (descriptor_->memory.data_size == 0) { 1.1185 + BPLOG(ERROR) << "MinidumpMemoryRegion is empty"; 1.1186 + return NULL; 1.1187 + } 1.1188 + 1.1189 + if (!minidump_->SeekSet(descriptor_->memory.rva)) { 1.1190 + BPLOG(ERROR) << "MinidumpMemoryRegion could not seek to memory region"; 1.1191 + return NULL; 1.1192 + } 1.1193 + 1.1194 + if (descriptor_->memory.data_size > max_bytes_) { 1.1195 + BPLOG(ERROR) << "MinidumpMemoryRegion size " << 1.1196 + descriptor_->memory.data_size << " exceeds maximum " << 1.1197 + max_bytes_; 1.1198 + return NULL; 1.1199 + } 1.1200 + 1.1201 + scoped_ptr< vector<uint8_t> > memory( 1.1202 + new vector<uint8_t>(descriptor_->memory.data_size)); 1.1203 + 1.1204 + if (!minidump_->ReadBytes(&(*memory)[0], descriptor_->memory.data_size)) { 1.1205 + BPLOG(ERROR) << "MinidumpMemoryRegion could not read memory region"; 1.1206 + return NULL; 1.1207 + } 1.1208 + 1.1209 + memory_ = memory.release(); 1.1210 + } 1.1211 + 1.1212 + return &(*memory_)[0]; 1.1213 +} 1.1214 + 1.1215 + 1.1216 +uint64_t MinidumpMemoryRegion::GetBase() const { 1.1217 + if (!valid_) { 1.1218 + BPLOG(ERROR) << "Invalid MinidumpMemoryRegion for GetBase"; 1.1219 + return static_cast<uint64_t>(-1); 1.1220 + } 1.1221 + 1.1222 + return descriptor_->start_of_memory_range; 1.1223 +} 1.1224 + 1.1225 + 1.1226 +uint32_t MinidumpMemoryRegion::GetSize() const { 1.1227 + if (!valid_) { 1.1228 + BPLOG(ERROR) << "Invalid MinidumpMemoryRegion for GetSize"; 1.1229 + return 0; 1.1230 + } 1.1231 + 1.1232 + return descriptor_->memory.data_size; 1.1233 +} 1.1234 + 1.1235 + 1.1236 +void MinidumpMemoryRegion::FreeMemory() { 1.1237 + delete memory_; 1.1238 + memory_ = NULL; 1.1239 +} 1.1240 + 1.1241 + 1.1242 +template<typename T> 1.1243 +bool MinidumpMemoryRegion::GetMemoryAtAddressInternal(uint64_t address, 1.1244 + T* value) const { 1.1245 + BPLOG_IF(ERROR, !value) << "MinidumpMemoryRegion::GetMemoryAtAddressInternal " 1.1246 + "requires |value|"; 1.1247 + assert(value); 1.1248 + *value = 0; 1.1249 + 1.1250 + if (!valid_) { 1.1251 + BPLOG(ERROR) << "Invalid MinidumpMemoryRegion for " 1.1252 + "GetMemoryAtAddressInternal"; 1.1253 + return false; 1.1254 + } 1.1255 + 1.1256 + // Common failure case 1.1257 + if (address < descriptor_->start_of_memory_range || 1.1258 + sizeof(T) > numeric_limits<uint64_t>::max() - address || 1.1259 + address + sizeof(T) > descriptor_->start_of_memory_range + 1.1260 + descriptor_->memory.data_size) { 1.1261 + BPLOG(INFO) << "MinidumpMemoryRegion request out of range: " << 1.1262 + HexString(address) << "+" << sizeof(T) << "/" << 1.1263 + HexString(descriptor_->start_of_memory_range) << "+" << 1.1264 + HexString(descriptor_->memory.data_size); 1.1265 + return false; 1.1266 + } 1.1267 + 1.1268 + const uint8_t* memory = GetMemory(); 1.1269 + if (!memory) { 1.1270 + // GetMemory already logged a perfectly good message. 1.1271 + return false; 1.1272 + } 1.1273 + 1.1274 + // If the CPU requires memory accesses to be aligned, this can crash. 1.1275 + // x86 and ppc are able to cope, though. 1.1276 + *value = *reinterpret_cast<const T*>( 1.1277 + &memory[address - descriptor_->start_of_memory_range]); 1.1278 + 1.1279 + if (minidump_->swap()) 1.1280 + Swap(value); 1.1281 + 1.1282 + return true; 1.1283 +} 1.1284 + 1.1285 + 1.1286 +bool MinidumpMemoryRegion::GetMemoryAtAddress(uint64_t address, 1.1287 + uint8_t* value) const { 1.1288 + return GetMemoryAtAddressInternal(address, value); 1.1289 +} 1.1290 + 1.1291 + 1.1292 +bool MinidumpMemoryRegion::GetMemoryAtAddress(uint64_t address, 1.1293 + uint16_t* value) const { 1.1294 + return GetMemoryAtAddressInternal(address, value); 1.1295 +} 1.1296 + 1.1297 + 1.1298 +bool MinidumpMemoryRegion::GetMemoryAtAddress(uint64_t address, 1.1299 + uint32_t* value) const { 1.1300 + return GetMemoryAtAddressInternal(address, value); 1.1301 +} 1.1302 + 1.1303 + 1.1304 +bool MinidumpMemoryRegion::GetMemoryAtAddress(uint64_t address, 1.1305 + uint64_t* value) const { 1.1306 + return GetMemoryAtAddressInternal(address, value); 1.1307 +} 1.1308 + 1.1309 + 1.1310 +void MinidumpMemoryRegion::Print() { 1.1311 + if (!valid_) { 1.1312 + BPLOG(ERROR) << "MinidumpMemoryRegion cannot print invalid data"; 1.1313 + return; 1.1314 + } 1.1315 + 1.1316 + const uint8_t* memory = GetMemory(); 1.1317 + if (memory) { 1.1318 + printf("0x"); 1.1319 + for (unsigned int byte_index = 0; 1.1320 + byte_index < descriptor_->memory.data_size; 1.1321 + byte_index++) { 1.1322 + printf("%02x", memory[byte_index]); 1.1323 + } 1.1324 + printf("\n"); 1.1325 + } else { 1.1326 + printf("No memory\n"); 1.1327 + } 1.1328 +} 1.1329 + 1.1330 + 1.1331 +// 1.1332 +// MinidumpThread 1.1333 +// 1.1334 + 1.1335 + 1.1336 +MinidumpThread::MinidumpThread(Minidump* minidump) 1.1337 + : MinidumpObject(minidump), 1.1338 + thread_(), 1.1339 + memory_(NULL), 1.1340 + context_(NULL) { 1.1341 +} 1.1342 + 1.1343 + 1.1344 +MinidumpThread::~MinidumpThread() { 1.1345 + delete memory_; 1.1346 + delete context_; 1.1347 +} 1.1348 + 1.1349 + 1.1350 +bool MinidumpThread::Read() { 1.1351 + // Invalidate cached data. 1.1352 + delete memory_; 1.1353 + memory_ = NULL; 1.1354 + delete context_; 1.1355 + context_ = NULL; 1.1356 + 1.1357 + valid_ = false; 1.1358 + 1.1359 + if (!minidump_->ReadBytes(&thread_, sizeof(thread_))) { 1.1360 + BPLOG(ERROR) << "MinidumpThread cannot read thread"; 1.1361 + return false; 1.1362 + } 1.1363 + 1.1364 + if (minidump_->swap()) { 1.1365 + Swap(&thread_.thread_id); 1.1366 + Swap(&thread_.suspend_count); 1.1367 + Swap(&thread_.priority_class); 1.1368 + Swap(&thread_.priority); 1.1369 + Swap(&thread_.teb); 1.1370 + Swap(&thread_.stack); 1.1371 + Swap(&thread_.thread_context); 1.1372 + } 1.1373 + 1.1374 + // Check for base + size overflow or undersize. 1.1375 + if (thread_.stack.memory.data_size == 0 || 1.1376 + thread_.stack.memory.data_size > numeric_limits<uint64_t>::max() - 1.1377 + thread_.stack.start_of_memory_range) { 1.1378 + // This is ok, but log an error anyway. 1.1379 + BPLOG(ERROR) << "MinidumpThread has a memory region problem, " << 1.1380 + HexString(thread_.stack.start_of_memory_range) << "+" << 1.1381 + HexString(thread_.stack.memory.data_size); 1.1382 + } else { 1.1383 + memory_ = new MinidumpMemoryRegion(minidump_); 1.1384 + memory_->SetDescriptor(&thread_.stack); 1.1385 + } 1.1386 + 1.1387 + valid_ = true; 1.1388 + return true; 1.1389 +} 1.1390 + 1.1391 + 1.1392 +MinidumpMemoryRegion* MinidumpThread::GetMemory() { 1.1393 + if (!valid_) { 1.1394 + BPLOG(ERROR) << "Invalid MinidumpThread for GetMemory"; 1.1395 + return NULL; 1.1396 + } 1.1397 + 1.1398 + return memory_; 1.1399 +} 1.1400 + 1.1401 + 1.1402 +MinidumpContext* MinidumpThread::GetContext() { 1.1403 + if (!valid_) { 1.1404 + BPLOG(ERROR) << "Invalid MinidumpThread for GetContext"; 1.1405 + return NULL; 1.1406 + } 1.1407 + 1.1408 + if (!context_) { 1.1409 + if (!minidump_->SeekSet(thread_.thread_context.rva)) { 1.1410 + BPLOG(ERROR) << "MinidumpThread cannot seek to context"; 1.1411 + return NULL; 1.1412 + } 1.1413 + 1.1414 + scoped_ptr<MinidumpContext> context(new MinidumpContext(minidump_)); 1.1415 + 1.1416 + if (!context->Read(thread_.thread_context.data_size)) { 1.1417 + BPLOG(ERROR) << "MinidumpThread cannot read context"; 1.1418 + return NULL; 1.1419 + } 1.1420 + 1.1421 + context_ = context.release(); 1.1422 + } 1.1423 + 1.1424 + return context_; 1.1425 +} 1.1426 + 1.1427 + 1.1428 +bool MinidumpThread::GetThreadID(uint32_t *thread_id) const { 1.1429 + BPLOG_IF(ERROR, !thread_id) << "MinidumpThread::GetThreadID requires " 1.1430 + "|thread_id|"; 1.1431 + assert(thread_id); 1.1432 + *thread_id = 0; 1.1433 + 1.1434 + if (!valid_) { 1.1435 + BPLOG(ERROR) << "Invalid MinidumpThread for GetThreadID"; 1.1436 + return false; 1.1437 + } 1.1438 + 1.1439 + *thread_id = thread_.thread_id; 1.1440 + return true; 1.1441 +} 1.1442 + 1.1443 + 1.1444 +void MinidumpThread::Print() { 1.1445 + if (!valid_) { 1.1446 + BPLOG(ERROR) << "MinidumpThread cannot print invalid data"; 1.1447 + return; 1.1448 + } 1.1449 + 1.1450 + printf("MDRawThread\n"); 1.1451 + printf(" thread_id = 0x%x\n", thread_.thread_id); 1.1452 + printf(" suspend_count = %d\n", thread_.suspend_count); 1.1453 + printf(" priority_class = 0x%x\n", thread_.priority_class); 1.1454 + printf(" priority = 0x%x\n", thread_.priority); 1.1455 + printf(" teb = 0x%" PRIx64 "\n", thread_.teb); 1.1456 + printf(" stack.start_of_memory_range = 0x%" PRIx64 "\n", 1.1457 + thread_.stack.start_of_memory_range); 1.1458 + printf(" stack.memory.data_size = 0x%x\n", 1.1459 + thread_.stack.memory.data_size); 1.1460 + printf(" stack.memory.rva = 0x%x\n", thread_.stack.memory.rva); 1.1461 + printf(" thread_context.data_size = 0x%x\n", 1.1462 + thread_.thread_context.data_size); 1.1463 + printf(" thread_context.rva = 0x%x\n", 1.1464 + thread_.thread_context.rva); 1.1465 + 1.1466 + MinidumpContext* context = GetContext(); 1.1467 + if (context) { 1.1468 + printf("\n"); 1.1469 + context->Print(); 1.1470 + } else { 1.1471 + printf(" (no context)\n"); 1.1472 + printf("\n"); 1.1473 + } 1.1474 + 1.1475 + MinidumpMemoryRegion* memory = GetMemory(); 1.1476 + if (memory) { 1.1477 + printf("Stack\n"); 1.1478 + memory->Print(); 1.1479 + } else { 1.1480 + printf("No stack\n"); 1.1481 + } 1.1482 + printf("\n"); 1.1483 +} 1.1484 + 1.1485 + 1.1486 +// 1.1487 +// MinidumpThreadList 1.1488 +// 1.1489 + 1.1490 + 1.1491 +uint32_t MinidumpThreadList::max_threads_ = 4096; 1.1492 + 1.1493 + 1.1494 +MinidumpThreadList::MinidumpThreadList(Minidump* minidump) 1.1495 + : MinidumpStream(minidump), 1.1496 + id_to_thread_map_(), 1.1497 + threads_(NULL), 1.1498 + thread_count_(0) { 1.1499 +} 1.1500 + 1.1501 + 1.1502 +MinidumpThreadList::~MinidumpThreadList() { 1.1503 + delete threads_; 1.1504 +} 1.1505 + 1.1506 + 1.1507 +bool MinidumpThreadList::Read(uint32_t expected_size) { 1.1508 + // Invalidate cached data. 1.1509 + id_to_thread_map_.clear(); 1.1510 + delete threads_; 1.1511 + threads_ = NULL; 1.1512 + thread_count_ = 0; 1.1513 + 1.1514 + valid_ = false; 1.1515 + 1.1516 + uint32_t thread_count; 1.1517 + if (expected_size < sizeof(thread_count)) { 1.1518 + BPLOG(ERROR) << "MinidumpThreadList count size mismatch, " << 1.1519 + expected_size << " < " << sizeof(thread_count); 1.1520 + return false; 1.1521 + } 1.1522 + if (!minidump_->ReadBytes(&thread_count, sizeof(thread_count))) { 1.1523 + BPLOG(ERROR) << "MinidumpThreadList cannot read thread count"; 1.1524 + return false; 1.1525 + } 1.1526 + 1.1527 + if (minidump_->swap()) 1.1528 + Swap(&thread_count); 1.1529 + 1.1530 + if (thread_count > numeric_limits<uint32_t>::max() / sizeof(MDRawThread)) { 1.1531 + BPLOG(ERROR) << "MinidumpThreadList thread count " << thread_count << 1.1532 + " would cause multiplication overflow"; 1.1533 + return false; 1.1534 + } 1.1535 + 1.1536 + if (expected_size != sizeof(thread_count) + 1.1537 + thread_count * sizeof(MDRawThread)) { 1.1538 + // may be padded with 4 bytes on 64bit ABIs for alignment 1.1539 + if (expected_size == sizeof(thread_count) + 4 + 1.1540 + thread_count * sizeof(MDRawThread)) { 1.1541 + uint32_t useless; 1.1542 + if (!minidump_->ReadBytes(&useless, 4)) { 1.1543 + BPLOG(ERROR) << "MinidumpThreadList cannot read threadlist padded bytes"; 1.1544 + return false; 1.1545 + } 1.1546 + } else { 1.1547 + BPLOG(ERROR) << "MinidumpThreadList size mismatch, " << expected_size << 1.1548 + " != " << sizeof(thread_count) + 1.1549 + thread_count * sizeof(MDRawThread); 1.1550 + return false; 1.1551 + } 1.1552 + } 1.1553 + 1.1554 + 1.1555 + if (thread_count > max_threads_) { 1.1556 + BPLOG(ERROR) << "MinidumpThreadList count " << thread_count << 1.1557 + " exceeds maximum " << max_threads_; 1.1558 + return false; 1.1559 + } 1.1560 + 1.1561 + if (thread_count != 0) { 1.1562 + scoped_ptr<MinidumpThreads> threads( 1.1563 + new MinidumpThreads(thread_count, MinidumpThread(minidump_))); 1.1564 + 1.1565 + for (unsigned int thread_index = 0; 1.1566 + thread_index < thread_count; 1.1567 + ++thread_index) { 1.1568 + MinidumpThread* thread = &(*threads)[thread_index]; 1.1569 + 1.1570 + // Assume that the file offset is correct after the last read. 1.1571 + if (!thread->Read()) { 1.1572 + BPLOG(ERROR) << "MinidumpThreadList cannot read thread " << 1.1573 + thread_index << "/" << thread_count; 1.1574 + return false; 1.1575 + } 1.1576 + 1.1577 + uint32_t thread_id; 1.1578 + if (!thread->GetThreadID(&thread_id)) { 1.1579 + BPLOG(ERROR) << "MinidumpThreadList cannot get thread ID for thread " << 1.1580 + thread_index << "/" << thread_count; 1.1581 + return false; 1.1582 + } 1.1583 + 1.1584 + if (GetThreadByID(thread_id)) { 1.1585 + // Another thread with this ID is already in the list. Data error. 1.1586 + BPLOG(ERROR) << "MinidumpThreadList found multiple threads with ID " << 1.1587 + HexString(thread_id) << " at thread " << 1.1588 + thread_index << "/" << thread_count; 1.1589 + return false; 1.1590 + } 1.1591 + id_to_thread_map_[thread_id] = thread; 1.1592 + } 1.1593 + 1.1594 + threads_ = threads.release(); 1.1595 + } 1.1596 + 1.1597 + thread_count_ = thread_count; 1.1598 + 1.1599 + valid_ = true; 1.1600 + return true; 1.1601 +} 1.1602 + 1.1603 + 1.1604 +MinidumpThread* MinidumpThreadList::GetThreadAtIndex(unsigned int index) 1.1605 + const { 1.1606 + if (!valid_) { 1.1607 + BPLOG(ERROR) << "Invalid MinidumpThreadList for GetThreadAtIndex"; 1.1608 + return NULL; 1.1609 + } 1.1610 + 1.1611 + if (index >= thread_count_) { 1.1612 + BPLOG(ERROR) << "MinidumpThreadList index out of range: " << 1.1613 + index << "/" << thread_count_; 1.1614 + return NULL; 1.1615 + } 1.1616 + 1.1617 + return &(*threads_)[index]; 1.1618 +} 1.1619 + 1.1620 + 1.1621 +MinidumpThread* MinidumpThreadList::GetThreadByID(uint32_t thread_id) { 1.1622 + // Don't check valid_. Read calls this method before everything is 1.1623 + // validated. It is safe to not check valid_ here. 1.1624 + return id_to_thread_map_[thread_id]; 1.1625 +} 1.1626 + 1.1627 + 1.1628 +void MinidumpThreadList::Print() { 1.1629 + if (!valid_) { 1.1630 + BPLOG(ERROR) << "MinidumpThreadList cannot print invalid data"; 1.1631 + return; 1.1632 + } 1.1633 + 1.1634 + printf("MinidumpThreadList\n"); 1.1635 + printf(" thread_count = %d\n", thread_count_); 1.1636 + printf("\n"); 1.1637 + 1.1638 + for (unsigned int thread_index = 0; 1.1639 + thread_index < thread_count_; 1.1640 + ++thread_index) { 1.1641 + printf("thread[%d]\n", thread_index); 1.1642 + 1.1643 + (*threads_)[thread_index].Print(); 1.1644 + } 1.1645 +} 1.1646 + 1.1647 + 1.1648 +// 1.1649 +// MinidumpModule 1.1650 +// 1.1651 + 1.1652 + 1.1653 +uint32_t MinidumpModule::max_cv_bytes_ = 32768; 1.1654 +uint32_t MinidumpModule::max_misc_bytes_ = 32768; 1.1655 + 1.1656 + 1.1657 +MinidumpModule::MinidumpModule(Minidump* minidump) 1.1658 + : MinidumpObject(minidump), 1.1659 + module_valid_(false), 1.1660 + has_debug_info_(false), 1.1661 + module_(), 1.1662 + name_(NULL), 1.1663 + cv_record_(NULL), 1.1664 + cv_record_signature_(MD_CVINFOUNKNOWN_SIGNATURE), 1.1665 + misc_record_(NULL) { 1.1666 +} 1.1667 + 1.1668 + 1.1669 +MinidumpModule::~MinidumpModule() { 1.1670 + delete name_; 1.1671 + delete cv_record_; 1.1672 + delete misc_record_; 1.1673 +} 1.1674 + 1.1675 + 1.1676 +bool MinidumpModule::Read() { 1.1677 + // Invalidate cached data. 1.1678 + delete name_; 1.1679 + name_ = NULL; 1.1680 + delete cv_record_; 1.1681 + cv_record_ = NULL; 1.1682 + cv_record_signature_ = MD_CVINFOUNKNOWN_SIGNATURE; 1.1683 + delete misc_record_; 1.1684 + misc_record_ = NULL; 1.1685 + 1.1686 + module_valid_ = false; 1.1687 + has_debug_info_ = false; 1.1688 + valid_ = false; 1.1689 + 1.1690 + if (!minidump_->ReadBytes(&module_, MD_MODULE_SIZE)) { 1.1691 + BPLOG(ERROR) << "MinidumpModule cannot read module"; 1.1692 + return false; 1.1693 + } 1.1694 + 1.1695 + if (minidump_->swap()) { 1.1696 + Swap(&module_.base_of_image); 1.1697 + Swap(&module_.size_of_image); 1.1698 + Swap(&module_.checksum); 1.1699 + Swap(&module_.time_date_stamp); 1.1700 + Swap(&module_.module_name_rva); 1.1701 + Swap(&module_.version_info.signature); 1.1702 + Swap(&module_.version_info.struct_version); 1.1703 + Swap(&module_.version_info.file_version_hi); 1.1704 + Swap(&module_.version_info.file_version_lo); 1.1705 + Swap(&module_.version_info.product_version_hi); 1.1706 + Swap(&module_.version_info.product_version_lo); 1.1707 + Swap(&module_.version_info.file_flags_mask); 1.1708 + Swap(&module_.version_info.file_flags); 1.1709 + Swap(&module_.version_info.file_os); 1.1710 + Swap(&module_.version_info.file_type); 1.1711 + Swap(&module_.version_info.file_subtype); 1.1712 + Swap(&module_.version_info.file_date_hi); 1.1713 + Swap(&module_.version_info.file_date_lo); 1.1714 + Swap(&module_.cv_record); 1.1715 + Swap(&module_.misc_record); 1.1716 + // Don't swap reserved fields because their contents are unknown (as 1.1717 + // are their proper widths). 1.1718 + } 1.1719 + 1.1720 + // Check for base + size overflow or undersize. 1.1721 + if (module_.size_of_image == 0 || 1.1722 + module_.size_of_image > 1.1723 + numeric_limits<uint64_t>::max() - module_.base_of_image) { 1.1724 + BPLOG(ERROR) << "MinidumpModule has a module problem, " << 1.1725 + HexString(module_.base_of_image) << "+" << 1.1726 + HexString(module_.size_of_image); 1.1727 + return false; 1.1728 + } 1.1729 + 1.1730 + module_valid_ = true; 1.1731 + return true; 1.1732 +} 1.1733 + 1.1734 + 1.1735 +bool MinidumpModule::ReadAuxiliaryData() { 1.1736 + if (!module_valid_) { 1.1737 + BPLOG(ERROR) << "Invalid MinidumpModule for ReadAuxiliaryData"; 1.1738 + return false; 1.1739 + } 1.1740 + 1.1741 + // Each module must have a name. 1.1742 + name_ = minidump_->ReadString(module_.module_name_rva); 1.1743 + if (!name_) { 1.1744 + BPLOG(ERROR) << "MinidumpModule could not read name"; 1.1745 + return false; 1.1746 + } 1.1747 + 1.1748 + // At this point, we have enough info for the module to be valid. 1.1749 + valid_ = true; 1.1750 + 1.1751 + // CodeView and miscellaneous debug records are only required if the 1.1752 + // module indicates that they exist. 1.1753 + if (module_.cv_record.data_size && !GetCVRecord(NULL)) { 1.1754 + BPLOG(ERROR) << "MinidumpModule has no CodeView record, " 1.1755 + "but one was expected"; 1.1756 + return false; 1.1757 + } 1.1758 + 1.1759 + if (module_.misc_record.data_size && !GetMiscRecord(NULL)) { 1.1760 + BPLOG(ERROR) << "MinidumpModule has no miscellaneous debug record, " 1.1761 + "but one was expected"; 1.1762 + return false; 1.1763 + } 1.1764 + 1.1765 + has_debug_info_ = true; 1.1766 + return true; 1.1767 +} 1.1768 + 1.1769 + 1.1770 +string MinidumpModule::code_file() const { 1.1771 + if (!valid_) { 1.1772 + BPLOG(ERROR) << "Invalid MinidumpModule for code_file"; 1.1773 + return ""; 1.1774 + } 1.1775 + 1.1776 + return *name_; 1.1777 +} 1.1778 + 1.1779 + 1.1780 +string MinidumpModule::code_identifier() const { 1.1781 + if (!valid_) { 1.1782 + BPLOG(ERROR) << "Invalid MinidumpModule for code_identifier"; 1.1783 + return ""; 1.1784 + } 1.1785 + 1.1786 + if (!has_debug_info_) 1.1787 + return ""; 1.1788 + 1.1789 + MinidumpSystemInfo *minidump_system_info = minidump_->GetSystemInfo(); 1.1790 + if (!minidump_system_info) { 1.1791 + BPLOG(ERROR) << "MinidumpModule code_identifier requires " 1.1792 + "MinidumpSystemInfo"; 1.1793 + return ""; 1.1794 + } 1.1795 + 1.1796 + const MDRawSystemInfo *raw_system_info = minidump_system_info->system_info(); 1.1797 + if (!raw_system_info) { 1.1798 + BPLOG(ERROR) << "MinidumpModule code_identifier requires MDRawSystemInfo"; 1.1799 + return ""; 1.1800 + } 1.1801 + 1.1802 + string identifier; 1.1803 + 1.1804 + switch (raw_system_info->platform_id) { 1.1805 + case MD_OS_WIN32_NT: 1.1806 + case MD_OS_WIN32_WINDOWS: { 1.1807 + // Use the same format that the MS symbol server uses in filesystem 1.1808 + // hierarchies. 1.1809 + char identifier_string[17]; 1.1810 + snprintf(identifier_string, sizeof(identifier_string), "%08X%x", 1.1811 + module_.time_date_stamp, module_.size_of_image); 1.1812 + identifier = identifier_string; 1.1813 + break; 1.1814 + } 1.1815 + 1.1816 + case MD_OS_MAC_OS_X: 1.1817 + case MD_OS_IOS: 1.1818 + case MD_OS_SOLARIS: 1.1819 + case MD_OS_ANDROID: 1.1820 + case MD_OS_LINUX: { 1.1821 + // TODO(mmentovai): support uuid extension if present, otherwise fall 1.1822 + // back to version (from LC_ID_DYLIB?), otherwise fall back to something 1.1823 + // else. 1.1824 + identifier = "id"; 1.1825 + break; 1.1826 + } 1.1827 + 1.1828 + default: { 1.1829 + // Without knowing what OS generated the dump, we can't generate a good 1.1830 + // identifier. Return an empty string, signalling failure. 1.1831 + BPLOG(ERROR) << "MinidumpModule code_identifier requires known platform, " 1.1832 + "found " << HexString(raw_system_info->platform_id); 1.1833 + break; 1.1834 + } 1.1835 + } 1.1836 + 1.1837 + return identifier; 1.1838 +} 1.1839 + 1.1840 + 1.1841 +string MinidumpModule::debug_file() const { 1.1842 + if (!valid_) { 1.1843 + BPLOG(ERROR) << "Invalid MinidumpModule for debug_file"; 1.1844 + return ""; 1.1845 + } 1.1846 + 1.1847 + if (!has_debug_info_) 1.1848 + return ""; 1.1849 + 1.1850 + string file; 1.1851 + // Prefer the CodeView record if present. 1.1852 + if (cv_record_) { 1.1853 + if (cv_record_signature_ == MD_CVINFOPDB70_SIGNATURE) { 1.1854 + // It's actually an MDCVInfoPDB70 structure. 1.1855 + const MDCVInfoPDB70* cv_record_70 = 1.1856 + reinterpret_cast<const MDCVInfoPDB70*>(&(*cv_record_)[0]); 1.1857 + assert(cv_record_70->cv_signature == MD_CVINFOPDB70_SIGNATURE); 1.1858 + 1.1859 + // GetCVRecord guarantees pdb_file_name is null-terminated. 1.1860 + file = reinterpret_cast<const char*>(cv_record_70->pdb_file_name); 1.1861 + } else if (cv_record_signature_ == MD_CVINFOPDB20_SIGNATURE) { 1.1862 + // It's actually an MDCVInfoPDB20 structure. 1.1863 + const MDCVInfoPDB20* cv_record_20 = 1.1864 + reinterpret_cast<const MDCVInfoPDB20*>(&(*cv_record_)[0]); 1.1865 + assert(cv_record_20->cv_header.signature == MD_CVINFOPDB20_SIGNATURE); 1.1866 + 1.1867 + // GetCVRecord guarantees pdb_file_name is null-terminated. 1.1868 + file = reinterpret_cast<const char*>(cv_record_20->pdb_file_name); 1.1869 + } 1.1870 + 1.1871 + // If there's a CodeView record but it doesn't match a known signature, 1.1872 + // try the miscellaneous record. 1.1873 + } 1.1874 + 1.1875 + if (file.empty()) { 1.1876 + // No usable CodeView record. Try the miscellaneous debug record. 1.1877 + if (misc_record_) { 1.1878 + const MDImageDebugMisc* misc_record = 1.1879 + reinterpret_cast<const MDImageDebugMisc *>(&(*misc_record_)[0]); 1.1880 + if (!misc_record->unicode) { 1.1881 + // If it's not Unicode, just stuff it into the string. It's unclear 1.1882 + // if misc_record->data is 0-terminated, so use an explicit size. 1.1883 + file = string( 1.1884 + reinterpret_cast<const char*>(misc_record->data), 1.1885 + module_.misc_record.data_size - MDImageDebugMisc_minsize); 1.1886 + } else { 1.1887 + // There's a misc_record but it encodes the debug filename in UTF-16. 1.1888 + // (Actually, because miscellaneous records are so old, it's probably 1.1889 + // UCS-2.) Convert it to UTF-8 for congruity with the other strings 1.1890 + // that this method (and all other methods in the Minidump family) 1.1891 + // return. 1.1892 + 1.1893 + unsigned int bytes = 1.1894 + module_.misc_record.data_size - MDImageDebugMisc_minsize; 1.1895 + if (bytes % 2 == 0) { 1.1896 + unsigned int utf16_words = bytes / 2; 1.1897 + 1.1898 + // UTF16ToUTF8 expects a vector<uint16_t>, so create a temporary one 1.1899 + // and copy the UTF-16 data into it. 1.1900 + vector<uint16_t> string_utf16(utf16_words); 1.1901 + if (utf16_words) 1.1902 + memcpy(&string_utf16[0], &misc_record->data, bytes); 1.1903 + 1.1904 + // GetMiscRecord already byte-swapped the data[] field if it contains 1.1905 + // UTF-16, so pass false as the swap argument. 1.1906 + scoped_ptr<string> new_file(UTF16ToUTF8(string_utf16, false)); 1.1907 + file = *new_file; 1.1908 + } 1.1909 + } 1.1910 + } 1.1911 + } 1.1912 + 1.1913 + // Relatively common case 1.1914 + BPLOG_IF(INFO, file.empty()) << "MinidumpModule could not determine " 1.1915 + "debug_file for " << *name_; 1.1916 + 1.1917 + return file; 1.1918 +} 1.1919 + 1.1920 + 1.1921 +string MinidumpModule::debug_identifier() const { 1.1922 + if (!valid_) { 1.1923 + BPLOG(ERROR) << "Invalid MinidumpModule for debug_identifier"; 1.1924 + return ""; 1.1925 + } 1.1926 + 1.1927 + if (!has_debug_info_) 1.1928 + return ""; 1.1929 + 1.1930 + string identifier; 1.1931 + 1.1932 + // Use the CodeView record if present. 1.1933 + if (cv_record_) { 1.1934 + if (cv_record_signature_ == MD_CVINFOPDB70_SIGNATURE) { 1.1935 + // It's actually an MDCVInfoPDB70 structure. 1.1936 + const MDCVInfoPDB70* cv_record_70 = 1.1937 + reinterpret_cast<const MDCVInfoPDB70*>(&(*cv_record_)[0]); 1.1938 + assert(cv_record_70->cv_signature == MD_CVINFOPDB70_SIGNATURE); 1.1939 + 1.1940 + // Use the same format that the MS symbol server uses in filesystem 1.1941 + // hierarchies. 1.1942 + char identifier_string[41]; 1.1943 + snprintf(identifier_string, sizeof(identifier_string), 1.1944 + "%08X%04X%04X%02X%02X%02X%02X%02X%02X%02X%02X%x", 1.1945 + cv_record_70->signature.data1, 1.1946 + cv_record_70->signature.data2, 1.1947 + cv_record_70->signature.data3, 1.1948 + cv_record_70->signature.data4[0], 1.1949 + cv_record_70->signature.data4[1], 1.1950 + cv_record_70->signature.data4[2], 1.1951 + cv_record_70->signature.data4[3], 1.1952 + cv_record_70->signature.data4[4], 1.1953 + cv_record_70->signature.data4[5], 1.1954 + cv_record_70->signature.data4[6], 1.1955 + cv_record_70->signature.data4[7], 1.1956 + cv_record_70->age); 1.1957 + identifier = identifier_string; 1.1958 + } else if (cv_record_signature_ == MD_CVINFOPDB20_SIGNATURE) { 1.1959 + // It's actually an MDCVInfoPDB20 structure. 1.1960 + const MDCVInfoPDB20* cv_record_20 = 1.1961 + reinterpret_cast<const MDCVInfoPDB20*>(&(*cv_record_)[0]); 1.1962 + assert(cv_record_20->cv_header.signature == MD_CVINFOPDB20_SIGNATURE); 1.1963 + 1.1964 + // Use the same format that the MS symbol server uses in filesystem 1.1965 + // hierarchies. 1.1966 + char identifier_string[17]; 1.1967 + snprintf(identifier_string, sizeof(identifier_string), 1.1968 + "%08X%x", cv_record_20->signature, cv_record_20->age); 1.1969 + identifier = identifier_string; 1.1970 + } 1.1971 + } 1.1972 + 1.1973 + // TODO(mmentovai): if there's no usable CodeView record, there might be a 1.1974 + // miscellaneous debug record. It only carries a filename, though, and no 1.1975 + // identifier. I'm not sure what the right thing to do for the identifier 1.1976 + // is in that case, but I don't expect to find many modules without a 1.1977 + // CodeView record (or some other Breakpad extension structure in place of 1.1978 + // a CodeView record). Treat it as an error (empty identifier) for now. 1.1979 + 1.1980 + // TODO(mmentovai): on the Mac, provide fallbacks as in code_identifier(). 1.1981 + 1.1982 + // Relatively common case 1.1983 + BPLOG_IF(INFO, identifier.empty()) << "MinidumpModule could not determine " 1.1984 + "debug_identifier for " << *name_; 1.1985 + 1.1986 + return identifier; 1.1987 +} 1.1988 + 1.1989 + 1.1990 +string MinidumpModule::version() const { 1.1991 + if (!valid_) { 1.1992 + BPLOG(ERROR) << "Invalid MinidumpModule for version"; 1.1993 + return ""; 1.1994 + } 1.1995 + 1.1996 + string version; 1.1997 + 1.1998 + if (module_.version_info.signature == MD_VSFIXEDFILEINFO_SIGNATURE && 1.1999 + module_.version_info.struct_version & MD_VSFIXEDFILEINFO_VERSION) { 1.2000 + char version_string[24]; 1.2001 + snprintf(version_string, sizeof(version_string), "%u.%u.%u.%u", 1.2002 + module_.version_info.file_version_hi >> 16, 1.2003 + module_.version_info.file_version_hi & 0xffff, 1.2004 + module_.version_info.file_version_lo >> 16, 1.2005 + module_.version_info.file_version_lo & 0xffff); 1.2006 + version = version_string; 1.2007 + } 1.2008 + 1.2009 + // TODO(mmentovai): possibly support other struct types in place of 1.2010 + // the one used with MD_VSFIXEDFILEINFO_SIGNATURE. We can possibly use 1.2011 + // a different structure that better represents versioning facilities on 1.2012 + // Mac OS X and Linux, instead of forcing them to adhere to the dotted 1.2013 + // quad of 16-bit ints that Windows uses. 1.2014 + 1.2015 + BPLOG_IF(INFO, version.empty()) << "MinidumpModule could not determine " 1.2016 + "version for " << *name_; 1.2017 + 1.2018 + return version; 1.2019 +} 1.2020 + 1.2021 + 1.2022 +const CodeModule* MinidumpModule::Copy() const { 1.2023 + return new BasicCodeModule(this); 1.2024 +} 1.2025 + 1.2026 + 1.2027 +const uint8_t* MinidumpModule::GetCVRecord(uint32_t* size) { 1.2028 + if (!module_valid_) { 1.2029 + BPLOG(ERROR) << "Invalid MinidumpModule for GetCVRecord"; 1.2030 + return NULL; 1.2031 + } 1.2032 + 1.2033 + if (!cv_record_) { 1.2034 + // This just guards against 0-sized CodeView records; more specific checks 1.2035 + // are used when the signature is checked against various structure types. 1.2036 + if (module_.cv_record.data_size == 0) { 1.2037 + return NULL; 1.2038 + } 1.2039 + 1.2040 + if (!minidump_->SeekSet(module_.cv_record.rva)) { 1.2041 + BPLOG(ERROR) << "MinidumpModule could not seek to CodeView record"; 1.2042 + return NULL; 1.2043 + } 1.2044 + 1.2045 + if (module_.cv_record.data_size > max_cv_bytes_) { 1.2046 + BPLOG(ERROR) << "MinidumpModule CodeView record size " << 1.2047 + module_.cv_record.data_size << " exceeds maximum " << 1.2048 + max_cv_bytes_; 1.2049 + return NULL; 1.2050 + } 1.2051 + 1.2052 + // Allocating something that will be accessed as MDCVInfoPDB70 or 1.2053 + // MDCVInfoPDB20 but is allocated as uint8_t[] can cause alignment 1.2054 + // problems. x86 and ppc are able to cope, though. This allocation 1.2055 + // style is needed because the MDCVInfoPDB70 or MDCVInfoPDB20 are 1.2056 + // variable-sized due to their pdb_file_name fields; these structures 1.2057 + // are not MDCVInfoPDB70_minsize or MDCVInfoPDB20_minsize and treating 1.2058 + // them as such would result in incomplete structures or overruns. 1.2059 + scoped_ptr< vector<uint8_t> > cv_record( 1.2060 + new vector<uint8_t>(module_.cv_record.data_size)); 1.2061 + 1.2062 + if (!minidump_->ReadBytes(&(*cv_record)[0], module_.cv_record.data_size)) { 1.2063 + BPLOG(ERROR) << "MinidumpModule could not read CodeView record"; 1.2064 + return NULL; 1.2065 + } 1.2066 + 1.2067 + uint32_t signature = MD_CVINFOUNKNOWN_SIGNATURE; 1.2068 + if (module_.cv_record.data_size > sizeof(signature)) { 1.2069 + MDCVInfoPDB70* cv_record_signature = 1.2070 + reinterpret_cast<MDCVInfoPDB70*>(&(*cv_record)[0]); 1.2071 + signature = cv_record_signature->cv_signature; 1.2072 + if (minidump_->swap()) 1.2073 + Swap(&signature); 1.2074 + } 1.2075 + 1.2076 + if (signature == MD_CVINFOPDB70_SIGNATURE) { 1.2077 + // Now that the structure type is known, recheck the size. 1.2078 + if (MDCVInfoPDB70_minsize > module_.cv_record.data_size) { 1.2079 + BPLOG(ERROR) << "MinidumpModule CodeView7 record size mismatch, " << 1.2080 + MDCVInfoPDB70_minsize << " > " << 1.2081 + module_.cv_record.data_size; 1.2082 + return NULL; 1.2083 + } 1.2084 + 1.2085 + if (minidump_->swap()) { 1.2086 + MDCVInfoPDB70* cv_record_70 = 1.2087 + reinterpret_cast<MDCVInfoPDB70*>(&(*cv_record)[0]); 1.2088 + Swap(&cv_record_70->cv_signature); 1.2089 + Swap(&cv_record_70->signature); 1.2090 + Swap(&cv_record_70->age); 1.2091 + // Don't swap cv_record_70.pdb_file_name because it's an array of 8-bit 1.2092 + // quantities. (It's a path, is it UTF-8?) 1.2093 + } 1.2094 + 1.2095 + // The last field of either structure is null-terminated 8-bit character 1.2096 + // data. Ensure that it's null-terminated. 1.2097 + if ((*cv_record)[module_.cv_record.data_size - 1] != '\0') { 1.2098 + BPLOG(ERROR) << "MinidumpModule CodeView7 record string is not " 1.2099 + "0-terminated"; 1.2100 + return NULL; 1.2101 + } 1.2102 + } else if (signature == MD_CVINFOPDB20_SIGNATURE) { 1.2103 + // Now that the structure type is known, recheck the size. 1.2104 + if (MDCVInfoPDB20_minsize > module_.cv_record.data_size) { 1.2105 + BPLOG(ERROR) << "MinidumpModule CodeView2 record size mismatch, " << 1.2106 + MDCVInfoPDB20_minsize << " > " << 1.2107 + module_.cv_record.data_size; 1.2108 + return NULL; 1.2109 + } 1.2110 + if (minidump_->swap()) { 1.2111 + MDCVInfoPDB20* cv_record_20 = 1.2112 + reinterpret_cast<MDCVInfoPDB20*>(&(*cv_record)[0]); 1.2113 + Swap(&cv_record_20->cv_header.signature); 1.2114 + Swap(&cv_record_20->cv_header.offset); 1.2115 + Swap(&cv_record_20->signature); 1.2116 + Swap(&cv_record_20->age); 1.2117 + // Don't swap cv_record_20.pdb_file_name because it's an array of 8-bit 1.2118 + // quantities. (It's a path, is it UTF-8?) 1.2119 + } 1.2120 + 1.2121 + // The last field of either structure is null-terminated 8-bit character 1.2122 + // data. Ensure that it's null-terminated. 1.2123 + if ((*cv_record)[module_.cv_record.data_size - 1] != '\0') { 1.2124 + BPLOG(ERROR) << "MindumpModule CodeView2 record string is not " 1.2125 + "0-terminated"; 1.2126 + return NULL; 1.2127 + } 1.2128 + } 1.2129 + 1.2130 + // If the signature doesn't match something above, it's not something 1.2131 + // that Breakpad can presently handle directly. Because some modules in 1.2132 + // the wild contain such CodeView records as MD_CVINFOCV50_SIGNATURE, 1.2133 + // don't bail out here - allow the data to be returned to the user, 1.2134 + // although byte-swapping can't be done. 1.2135 + 1.2136 + // Store the vector type because that's how storage was allocated, but 1.2137 + // return it casted to uint8_t*. 1.2138 + cv_record_ = cv_record.release(); 1.2139 + cv_record_signature_ = signature; 1.2140 + } 1.2141 + 1.2142 + if (size) 1.2143 + *size = module_.cv_record.data_size; 1.2144 + 1.2145 + return &(*cv_record_)[0]; 1.2146 +} 1.2147 + 1.2148 + 1.2149 +const MDImageDebugMisc* MinidumpModule::GetMiscRecord(uint32_t* size) { 1.2150 + if (!module_valid_) { 1.2151 + BPLOG(ERROR) << "Invalid MinidumpModule for GetMiscRecord"; 1.2152 + return NULL; 1.2153 + } 1.2154 + 1.2155 + if (!misc_record_) { 1.2156 + if (module_.misc_record.data_size == 0) { 1.2157 + return NULL; 1.2158 + } 1.2159 + 1.2160 + if (MDImageDebugMisc_minsize > module_.misc_record.data_size) { 1.2161 + BPLOG(ERROR) << "MinidumpModule miscellaneous debugging record " 1.2162 + "size mismatch, " << MDImageDebugMisc_minsize << " > " << 1.2163 + module_.misc_record.data_size; 1.2164 + return NULL; 1.2165 + } 1.2166 + 1.2167 + if (!minidump_->SeekSet(module_.misc_record.rva)) { 1.2168 + BPLOG(ERROR) << "MinidumpModule could not seek to miscellaneous " 1.2169 + "debugging record"; 1.2170 + return NULL; 1.2171 + } 1.2172 + 1.2173 + if (module_.misc_record.data_size > max_misc_bytes_) { 1.2174 + BPLOG(ERROR) << "MinidumpModule miscellaneous debugging record size " << 1.2175 + module_.misc_record.data_size << " exceeds maximum " << 1.2176 + max_misc_bytes_; 1.2177 + return NULL; 1.2178 + } 1.2179 + 1.2180 + // Allocating something that will be accessed as MDImageDebugMisc but 1.2181 + // is allocated as uint8_t[] can cause alignment problems. x86 and 1.2182 + // ppc are able to cope, though. This allocation style is needed 1.2183 + // because the MDImageDebugMisc is variable-sized due to its data field; 1.2184 + // this structure is not MDImageDebugMisc_minsize and treating it as such 1.2185 + // would result in an incomplete structure or an overrun. 1.2186 + scoped_ptr< vector<uint8_t> > misc_record_mem( 1.2187 + new vector<uint8_t>(module_.misc_record.data_size)); 1.2188 + MDImageDebugMisc* misc_record = 1.2189 + reinterpret_cast<MDImageDebugMisc*>(&(*misc_record_mem)[0]); 1.2190 + 1.2191 + if (!minidump_->ReadBytes(misc_record, module_.misc_record.data_size)) { 1.2192 + BPLOG(ERROR) << "MinidumpModule could not read miscellaneous debugging " 1.2193 + "record"; 1.2194 + return NULL; 1.2195 + } 1.2196 + 1.2197 + if (minidump_->swap()) { 1.2198 + Swap(&misc_record->data_type); 1.2199 + Swap(&misc_record->length); 1.2200 + // Don't swap misc_record.unicode because it's an 8-bit quantity. 1.2201 + // Don't swap the reserved fields for the same reason, and because 1.2202 + // they don't contain any valid data. 1.2203 + if (misc_record->unicode) { 1.2204 + // There is a potential alignment problem, but shouldn't be a problem 1.2205 + // in practice due to the layout of MDImageDebugMisc. 1.2206 + uint16_t* data16 = reinterpret_cast<uint16_t*>(&(misc_record->data)); 1.2207 + unsigned int dataBytes = module_.misc_record.data_size - 1.2208 + MDImageDebugMisc_minsize; 1.2209 + unsigned int dataLength = dataBytes / 2; 1.2210 + for (unsigned int characterIndex = 0; 1.2211 + characterIndex < dataLength; 1.2212 + ++characterIndex) { 1.2213 + Swap(&data16[characterIndex]); 1.2214 + } 1.2215 + } 1.2216 + } 1.2217 + 1.2218 + if (module_.misc_record.data_size != misc_record->length) { 1.2219 + BPLOG(ERROR) << "MinidumpModule miscellaneous debugging record data " 1.2220 + "size mismatch, " << module_.misc_record.data_size << 1.2221 + " != " << misc_record->length; 1.2222 + return NULL; 1.2223 + } 1.2224 + 1.2225 + // Store the vector type because that's how storage was allocated, but 1.2226 + // return it casted to MDImageDebugMisc*. 1.2227 + misc_record_ = misc_record_mem.release(); 1.2228 + } 1.2229 + 1.2230 + if (size) 1.2231 + *size = module_.misc_record.data_size; 1.2232 + 1.2233 + return reinterpret_cast<MDImageDebugMisc*>(&(*misc_record_)[0]); 1.2234 +} 1.2235 + 1.2236 + 1.2237 +void MinidumpModule::Print() { 1.2238 + if (!valid_) { 1.2239 + BPLOG(ERROR) << "MinidumpModule cannot print invalid data"; 1.2240 + return; 1.2241 + } 1.2242 + 1.2243 + printf("MDRawModule\n"); 1.2244 + printf(" base_of_image = 0x%" PRIx64 "\n", 1.2245 + module_.base_of_image); 1.2246 + printf(" size_of_image = 0x%x\n", 1.2247 + module_.size_of_image); 1.2248 + printf(" checksum = 0x%x\n", 1.2249 + module_.checksum); 1.2250 + printf(" time_date_stamp = 0x%x\n", 1.2251 + module_.time_date_stamp); 1.2252 + printf(" module_name_rva = 0x%x\n", 1.2253 + module_.module_name_rva); 1.2254 + printf(" version_info.signature = 0x%x\n", 1.2255 + module_.version_info.signature); 1.2256 + printf(" version_info.struct_version = 0x%x\n", 1.2257 + module_.version_info.struct_version); 1.2258 + printf(" version_info.file_version = 0x%x:0x%x\n", 1.2259 + module_.version_info.file_version_hi, 1.2260 + module_.version_info.file_version_lo); 1.2261 + printf(" version_info.product_version = 0x%x:0x%x\n", 1.2262 + module_.version_info.product_version_hi, 1.2263 + module_.version_info.product_version_lo); 1.2264 + printf(" version_info.file_flags_mask = 0x%x\n", 1.2265 + module_.version_info.file_flags_mask); 1.2266 + printf(" version_info.file_flags = 0x%x\n", 1.2267 + module_.version_info.file_flags); 1.2268 + printf(" version_info.file_os = 0x%x\n", 1.2269 + module_.version_info.file_os); 1.2270 + printf(" version_info.file_type = 0x%x\n", 1.2271 + module_.version_info.file_type); 1.2272 + printf(" version_info.file_subtype = 0x%x\n", 1.2273 + module_.version_info.file_subtype); 1.2274 + printf(" version_info.file_date = 0x%x:0x%x\n", 1.2275 + module_.version_info.file_date_hi, 1.2276 + module_.version_info.file_date_lo); 1.2277 + printf(" cv_record.data_size = %d\n", 1.2278 + module_.cv_record.data_size); 1.2279 + printf(" cv_record.rva = 0x%x\n", 1.2280 + module_.cv_record.rva); 1.2281 + printf(" misc_record.data_size = %d\n", 1.2282 + module_.misc_record.data_size); 1.2283 + printf(" misc_record.rva = 0x%x\n", 1.2284 + module_.misc_record.rva); 1.2285 + 1.2286 + printf(" (code_file) = \"%s\"\n", code_file().c_str()); 1.2287 + printf(" (code_identifier) = \"%s\"\n", 1.2288 + code_identifier().c_str()); 1.2289 + 1.2290 + uint32_t cv_record_size; 1.2291 + const uint8_t *cv_record = GetCVRecord(&cv_record_size); 1.2292 + if (cv_record) { 1.2293 + if (cv_record_signature_ == MD_CVINFOPDB70_SIGNATURE) { 1.2294 + const MDCVInfoPDB70* cv_record_70 = 1.2295 + reinterpret_cast<const MDCVInfoPDB70*>(cv_record); 1.2296 + assert(cv_record_70->cv_signature == MD_CVINFOPDB70_SIGNATURE); 1.2297 + 1.2298 + printf(" (cv_record).cv_signature = 0x%x\n", 1.2299 + cv_record_70->cv_signature); 1.2300 + printf(" (cv_record).signature = %08x-%04x-%04x-%02x%02x-", 1.2301 + cv_record_70->signature.data1, 1.2302 + cv_record_70->signature.data2, 1.2303 + cv_record_70->signature.data3, 1.2304 + cv_record_70->signature.data4[0], 1.2305 + cv_record_70->signature.data4[1]); 1.2306 + for (unsigned int guidIndex = 2; 1.2307 + guidIndex < 8; 1.2308 + ++guidIndex) { 1.2309 + printf("%02x", cv_record_70->signature.data4[guidIndex]); 1.2310 + } 1.2311 + printf("\n"); 1.2312 + printf(" (cv_record).age = %d\n", 1.2313 + cv_record_70->age); 1.2314 + printf(" (cv_record).pdb_file_name = \"%s\"\n", 1.2315 + cv_record_70->pdb_file_name); 1.2316 + } else if (cv_record_signature_ == MD_CVINFOPDB20_SIGNATURE) { 1.2317 + const MDCVInfoPDB20* cv_record_20 = 1.2318 + reinterpret_cast<const MDCVInfoPDB20*>(cv_record); 1.2319 + assert(cv_record_20->cv_header.signature == MD_CVINFOPDB20_SIGNATURE); 1.2320 + 1.2321 + printf(" (cv_record).cv_header.signature = 0x%x\n", 1.2322 + cv_record_20->cv_header.signature); 1.2323 + printf(" (cv_record).cv_header.offset = 0x%x\n", 1.2324 + cv_record_20->cv_header.offset); 1.2325 + printf(" (cv_record).signature = 0x%x\n", 1.2326 + cv_record_20->signature); 1.2327 + printf(" (cv_record).age = %d\n", 1.2328 + cv_record_20->age); 1.2329 + printf(" (cv_record).pdb_file_name = \"%s\"\n", 1.2330 + cv_record_20->pdb_file_name); 1.2331 + } else { 1.2332 + printf(" (cv_record) = "); 1.2333 + for (unsigned int cv_byte_index = 0; 1.2334 + cv_byte_index < cv_record_size; 1.2335 + ++cv_byte_index) { 1.2336 + printf("%02x", cv_record[cv_byte_index]); 1.2337 + } 1.2338 + printf("\n"); 1.2339 + } 1.2340 + } else { 1.2341 + printf(" (cv_record) = (null)\n"); 1.2342 + } 1.2343 + 1.2344 + const MDImageDebugMisc* misc_record = GetMiscRecord(NULL); 1.2345 + if (misc_record) { 1.2346 + printf(" (misc_record).data_type = 0x%x\n", 1.2347 + misc_record->data_type); 1.2348 + printf(" (misc_record).length = 0x%x\n", 1.2349 + misc_record->length); 1.2350 + printf(" (misc_record).unicode = %d\n", 1.2351 + misc_record->unicode); 1.2352 + // Don't bother printing the UTF-16, we don't really even expect to ever 1.2353 + // see this misc_record anyway. 1.2354 + if (misc_record->unicode) 1.2355 + printf(" (misc_record).data = \"%s\"\n", 1.2356 + misc_record->data); 1.2357 + else 1.2358 + printf(" (misc_record).data = (UTF-16)\n"); 1.2359 + } else { 1.2360 + printf(" (misc_record) = (null)\n"); 1.2361 + } 1.2362 + 1.2363 + printf(" (debug_file) = \"%s\"\n", debug_file().c_str()); 1.2364 + printf(" (debug_identifier) = \"%s\"\n", 1.2365 + debug_identifier().c_str()); 1.2366 + printf(" (version) = \"%s\"\n", version().c_str()); 1.2367 + printf("\n"); 1.2368 +} 1.2369 + 1.2370 + 1.2371 +// 1.2372 +// MinidumpModuleList 1.2373 +// 1.2374 + 1.2375 + 1.2376 +uint32_t MinidumpModuleList::max_modules_ = 1024; 1.2377 + 1.2378 + 1.2379 +MinidumpModuleList::MinidumpModuleList(Minidump* minidump) 1.2380 + : MinidumpStream(minidump), 1.2381 + range_map_(new RangeMap<uint64_t, unsigned int>()), 1.2382 + modules_(NULL), 1.2383 + module_count_(0) { 1.2384 +} 1.2385 + 1.2386 + 1.2387 +MinidumpModuleList::~MinidumpModuleList() { 1.2388 + delete range_map_; 1.2389 + delete modules_; 1.2390 +} 1.2391 + 1.2392 + 1.2393 +bool MinidumpModuleList::Read(uint32_t expected_size) { 1.2394 + // Invalidate cached data. 1.2395 + range_map_->Clear(); 1.2396 + delete modules_; 1.2397 + modules_ = NULL; 1.2398 + module_count_ = 0; 1.2399 + 1.2400 + valid_ = false; 1.2401 + 1.2402 + uint32_t module_count; 1.2403 + if (expected_size < sizeof(module_count)) { 1.2404 + BPLOG(ERROR) << "MinidumpModuleList count size mismatch, " << 1.2405 + expected_size << " < " << sizeof(module_count); 1.2406 + return false; 1.2407 + } 1.2408 + if (!minidump_->ReadBytes(&module_count, sizeof(module_count))) { 1.2409 + BPLOG(ERROR) << "MinidumpModuleList could not read module count"; 1.2410 + return false; 1.2411 + } 1.2412 + 1.2413 + if (minidump_->swap()) 1.2414 + Swap(&module_count); 1.2415 + 1.2416 + if (module_count > numeric_limits<uint32_t>::max() / MD_MODULE_SIZE) { 1.2417 + BPLOG(ERROR) << "MinidumpModuleList module count " << module_count << 1.2418 + " would cause multiplication overflow"; 1.2419 + return false; 1.2420 + } 1.2421 + 1.2422 + if (expected_size != sizeof(module_count) + 1.2423 + module_count * MD_MODULE_SIZE) { 1.2424 + // may be padded with 4 bytes on 64bit ABIs for alignment 1.2425 + if (expected_size == sizeof(module_count) + 4 + 1.2426 + module_count * MD_MODULE_SIZE) { 1.2427 + uint32_t useless; 1.2428 + if (!minidump_->ReadBytes(&useless, 4)) { 1.2429 + BPLOG(ERROR) << "MinidumpModuleList cannot read modulelist padded bytes"; 1.2430 + return false; 1.2431 + } 1.2432 + } else { 1.2433 + BPLOG(ERROR) << "MinidumpModuleList size mismatch, " << expected_size << 1.2434 + " != " << sizeof(module_count) + 1.2435 + module_count * MD_MODULE_SIZE; 1.2436 + return false; 1.2437 + } 1.2438 + } 1.2439 + 1.2440 + if (module_count > max_modules_) { 1.2441 + BPLOG(ERROR) << "MinidumpModuleList count " << module_count_ << 1.2442 + " exceeds maximum " << max_modules_; 1.2443 + return false; 1.2444 + } 1.2445 + 1.2446 + if (module_count != 0) { 1.2447 + scoped_ptr<MinidumpModules> modules( 1.2448 + new MinidumpModules(module_count, MinidumpModule(minidump_))); 1.2449 + 1.2450 + for (unsigned int module_index = 0; 1.2451 + module_index < module_count; 1.2452 + ++module_index) { 1.2453 + MinidumpModule* module = &(*modules)[module_index]; 1.2454 + 1.2455 + // Assume that the file offset is correct after the last read. 1.2456 + if (!module->Read()) { 1.2457 + BPLOG(ERROR) << "MinidumpModuleList could not read module " << 1.2458 + module_index << "/" << module_count; 1.2459 + return false; 1.2460 + } 1.2461 + } 1.2462 + 1.2463 + // Loop through the module list once more to read additional data and 1.2464 + // build the range map. This is done in a second pass because 1.2465 + // MinidumpModule::ReadAuxiliaryData seeks around, and if it were 1.2466 + // included in the loop above, additional seeks would be needed where 1.2467 + // none are now to read contiguous data. 1.2468 + for (unsigned int module_index = 0; 1.2469 + module_index < module_count; 1.2470 + ++module_index) { 1.2471 + MinidumpModule* module = &(*modules)[module_index]; 1.2472 + 1.2473 + // ReadAuxiliaryData fails if any data that the module indicates should 1.2474 + // exist is missing, but we treat some such cases as valid anyway. See 1.2475 + // issue #222: if a debugging record is of a format that's too large to 1.2476 + // handle, it shouldn't render the entire dump invalid. Check module 1.2477 + // validity before giving up. 1.2478 + if (!module->ReadAuxiliaryData() && !module->valid()) { 1.2479 + BPLOG(ERROR) << "MinidumpModuleList could not read required module " 1.2480 + "auxiliary data for module " << 1.2481 + module_index << "/" << module_count; 1.2482 + return false; 1.2483 + } 1.2484 + 1.2485 + // It is safe to use module->code_file() after successfully calling 1.2486 + // module->ReadAuxiliaryData or noting that the module is valid. 1.2487 + 1.2488 + uint64_t base_address = module->base_address(); 1.2489 + uint64_t module_size = module->size(); 1.2490 + if (base_address == static_cast<uint64_t>(-1)) { 1.2491 + BPLOG(ERROR) << "MinidumpModuleList found bad base address " 1.2492 + "for module " << module_index << "/" << module_count << 1.2493 + ", " << module->code_file(); 1.2494 + return false; 1.2495 + } 1.2496 + 1.2497 + if (!range_map_->StoreRange(base_address, module_size, module_index)) { 1.2498 + BPLOG(ERROR) << "MinidumpModuleList could not store module " << 1.2499 + module_index << "/" << module_count << ", " << 1.2500 + module->code_file() << ", " << 1.2501 + HexString(base_address) << "+" << 1.2502 + HexString(module_size); 1.2503 + return false; 1.2504 + } 1.2505 + } 1.2506 + 1.2507 + modules_ = modules.release(); 1.2508 + } 1.2509 + 1.2510 + module_count_ = module_count; 1.2511 + 1.2512 + valid_ = true; 1.2513 + return true; 1.2514 +} 1.2515 + 1.2516 + 1.2517 +const MinidumpModule* MinidumpModuleList::GetModuleForAddress( 1.2518 + uint64_t address) const { 1.2519 + if (!valid_) { 1.2520 + BPLOG(ERROR) << "Invalid MinidumpModuleList for GetModuleForAddress"; 1.2521 + return NULL; 1.2522 + } 1.2523 + 1.2524 + unsigned int module_index; 1.2525 + if (!range_map_->RetrieveRange(address, &module_index, NULL, NULL)) { 1.2526 + BPLOG(INFO) << "MinidumpModuleList has no module at " << 1.2527 + HexString(address); 1.2528 + return NULL; 1.2529 + } 1.2530 + 1.2531 + return GetModuleAtIndex(module_index); 1.2532 +} 1.2533 + 1.2534 + 1.2535 +const MinidumpModule* MinidumpModuleList::GetMainModule() const { 1.2536 + if (!valid_) { 1.2537 + BPLOG(ERROR) << "Invalid MinidumpModuleList for GetMainModule"; 1.2538 + return NULL; 1.2539 + } 1.2540 + 1.2541 + // The main code module is the first one present in a minidump file's 1.2542 + // MDRawModuleList. 1.2543 + return GetModuleAtIndex(0); 1.2544 +} 1.2545 + 1.2546 + 1.2547 +const MinidumpModule* MinidumpModuleList::GetModuleAtSequence( 1.2548 + unsigned int sequence) const { 1.2549 + if (!valid_) { 1.2550 + BPLOG(ERROR) << "Invalid MinidumpModuleList for GetModuleAtSequence"; 1.2551 + return NULL; 1.2552 + } 1.2553 + 1.2554 + if (sequence >= module_count_) { 1.2555 + BPLOG(ERROR) << "MinidumpModuleList sequence out of range: " << 1.2556 + sequence << "/" << module_count_; 1.2557 + return NULL; 1.2558 + } 1.2559 + 1.2560 + unsigned int module_index; 1.2561 + if (!range_map_->RetrieveRangeAtIndex(sequence, &module_index, NULL, NULL)) { 1.2562 + BPLOG(ERROR) << "MinidumpModuleList has no module at sequence " << sequence; 1.2563 + return NULL; 1.2564 + } 1.2565 + 1.2566 + return GetModuleAtIndex(module_index); 1.2567 +} 1.2568 + 1.2569 + 1.2570 +const MinidumpModule* MinidumpModuleList::GetModuleAtIndex( 1.2571 + unsigned int index) const { 1.2572 + if (!valid_) { 1.2573 + BPLOG(ERROR) << "Invalid MinidumpModuleList for GetModuleAtIndex"; 1.2574 + return NULL; 1.2575 + } 1.2576 + 1.2577 + if (index >= module_count_) { 1.2578 + BPLOG(ERROR) << "MinidumpModuleList index out of range: " << 1.2579 + index << "/" << module_count_; 1.2580 + return NULL; 1.2581 + } 1.2582 + 1.2583 + return &(*modules_)[index]; 1.2584 +} 1.2585 + 1.2586 + 1.2587 +const CodeModules* MinidumpModuleList::Copy() const { 1.2588 + return new BasicCodeModules(this); 1.2589 +} 1.2590 + 1.2591 + 1.2592 +void MinidumpModuleList::Print() { 1.2593 + if (!valid_) { 1.2594 + BPLOG(ERROR) << "MinidumpModuleList cannot print invalid data"; 1.2595 + return; 1.2596 + } 1.2597 + 1.2598 + printf("MinidumpModuleList\n"); 1.2599 + printf(" module_count = %d\n", module_count_); 1.2600 + printf("\n"); 1.2601 + 1.2602 + for (unsigned int module_index = 0; 1.2603 + module_index < module_count_; 1.2604 + ++module_index) { 1.2605 + printf("module[%d]\n", module_index); 1.2606 + 1.2607 + (*modules_)[module_index].Print(); 1.2608 + } 1.2609 +} 1.2610 + 1.2611 + 1.2612 +// 1.2613 +// MinidumpMemoryList 1.2614 +// 1.2615 + 1.2616 + 1.2617 +uint32_t MinidumpMemoryList::max_regions_ = 4096; 1.2618 + 1.2619 + 1.2620 +MinidumpMemoryList::MinidumpMemoryList(Minidump* minidump) 1.2621 + : MinidumpStream(minidump), 1.2622 + range_map_(new RangeMap<uint64_t, unsigned int>()), 1.2623 + descriptors_(NULL), 1.2624 + regions_(NULL), 1.2625 + region_count_(0) { 1.2626 +} 1.2627 + 1.2628 + 1.2629 +MinidumpMemoryList::~MinidumpMemoryList() { 1.2630 + delete range_map_; 1.2631 + delete descriptors_; 1.2632 + delete regions_; 1.2633 +} 1.2634 + 1.2635 + 1.2636 +bool MinidumpMemoryList::Read(uint32_t expected_size) { 1.2637 + // Invalidate cached data. 1.2638 + delete descriptors_; 1.2639 + descriptors_ = NULL; 1.2640 + delete regions_; 1.2641 + regions_ = NULL; 1.2642 + range_map_->Clear(); 1.2643 + region_count_ = 0; 1.2644 + 1.2645 + valid_ = false; 1.2646 + 1.2647 + uint32_t region_count; 1.2648 + if (expected_size < sizeof(region_count)) { 1.2649 + BPLOG(ERROR) << "MinidumpMemoryList count size mismatch, " << 1.2650 + expected_size << " < " << sizeof(region_count); 1.2651 + return false; 1.2652 + } 1.2653 + if (!minidump_->ReadBytes(®ion_count, sizeof(region_count))) { 1.2654 + BPLOG(ERROR) << "MinidumpMemoryList could not read memory region count"; 1.2655 + return false; 1.2656 + } 1.2657 + 1.2658 + if (minidump_->swap()) 1.2659 + Swap(®ion_count); 1.2660 + 1.2661 + if (region_count > 1.2662 + numeric_limits<uint32_t>::max() / sizeof(MDMemoryDescriptor)) { 1.2663 + BPLOG(ERROR) << "MinidumpMemoryList region count " << region_count << 1.2664 + " would cause multiplication overflow"; 1.2665 + return false; 1.2666 + } 1.2667 + 1.2668 + if (expected_size != sizeof(region_count) + 1.2669 + region_count * sizeof(MDMemoryDescriptor)) { 1.2670 + // may be padded with 4 bytes on 64bit ABIs for alignment 1.2671 + if (expected_size == sizeof(region_count) + 4 + 1.2672 + region_count * sizeof(MDMemoryDescriptor)) { 1.2673 + uint32_t useless; 1.2674 + if (!minidump_->ReadBytes(&useless, 4)) { 1.2675 + BPLOG(ERROR) << "MinidumpMemoryList cannot read memorylist padded bytes"; 1.2676 + return false; 1.2677 + } 1.2678 + } else { 1.2679 + BPLOG(ERROR) << "MinidumpMemoryList size mismatch, " << expected_size << 1.2680 + " != " << sizeof(region_count) + 1.2681 + region_count * sizeof(MDMemoryDescriptor); 1.2682 + return false; 1.2683 + } 1.2684 + } 1.2685 + 1.2686 + if (region_count > max_regions_) { 1.2687 + BPLOG(ERROR) << "MinidumpMemoryList count " << region_count << 1.2688 + " exceeds maximum " << max_regions_; 1.2689 + return false; 1.2690 + } 1.2691 + 1.2692 + if (region_count != 0) { 1.2693 + scoped_ptr<MemoryDescriptors> descriptors( 1.2694 + new MemoryDescriptors(region_count)); 1.2695 + 1.2696 + // Read the entire array in one fell swoop, instead of reading one entry 1.2697 + // at a time in the loop. 1.2698 + if (!minidump_->ReadBytes(&(*descriptors)[0], 1.2699 + sizeof(MDMemoryDescriptor) * region_count)) { 1.2700 + BPLOG(ERROR) << "MinidumpMemoryList could not read memory region list"; 1.2701 + return false; 1.2702 + } 1.2703 + 1.2704 + scoped_ptr<MemoryRegions> regions( 1.2705 + new MemoryRegions(region_count, MinidumpMemoryRegion(minidump_))); 1.2706 + 1.2707 + for (unsigned int region_index = 0; 1.2708 + region_index < region_count; 1.2709 + ++region_index) { 1.2710 + MDMemoryDescriptor* descriptor = &(*descriptors)[region_index]; 1.2711 + 1.2712 + if (minidump_->swap()) 1.2713 + Swap(descriptor); 1.2714 + 1.2715 + uint64_t base_address = descriptor->start_of_memory_range; 1.2716 + uint32_t region_size = descriptor->memory.data_size; 1.2717 + 1.2718 + // Check for base + size overflow or undersize. 1.2719 + if (region_size == 0 || 1.2720 + region_size > numeric_limits<uint64_t>::max() - base_address) { 1.2721 + BPLOG(ERROR) << "MinidumpMemoryList has a memory region problem, " << 1.2722 + " region " << region_index << "/" << region_count << 1.2723 + ", " << HexString(base_address) << "+" << 1.2724 + HexString(region_size); 1.2725 + return false; 1.2726 + } 1.2727 + 1.2728 + if (!range_map_->StoreRange(base_address, region_size, region_index)) { 1.2729 + BPLOG(ERROR) << "MinidumpMemoryList could not store memory region " << 1.2730 + region_index << "/" << region_count << ", " << 1.2731 + HexString(base_address) << "+" << 1.2732 + HexString(region_size); 1.2733 + return false; 1.2734 + } 1.2735 + 1.2736 + (*regions)[region_index].SetDescriptor(descriptor); 1.2737 + } 1.2738 + 1.2739 + descriptors_ = descriptors.release(); 1.2740 + regions_ = regions.release(); 1.2741 + } 1.2742 + 1.2743 + region_count_ = region_count; 1.2744 + 1.2745 + valid_ = true; 1.2746 + return true; 1.2747 +} 1.2748 + 1.2749 + 1.2750 +MinidumpMemoryRegion* MinidumpMemoryList::GetMemoryRegionAtIndex( 1.2751 + unsigned int index) { 1.2752 + if (!valid_) { 1.2753 + BPLOG(ERROR) << "Invalid MinidumpMemoryList for GetMemoryRegionAtIndex"; 1.2754 + return NULL; 1.2755 + } 1.2756 + 1.2757 + if (index >= region_count_) { 1.2758 + BPLOG(ERROR) << "MinidumpMemoryList index out of range: " << 1.2759 + index << "/" << region_count_; 1.2760 + return NULL; 1.2761 + } 1.2762 + 1.2763 + return &(*regions_)[index]; 1.2764 +} 1.2765 + 1.2766 + 1.2767 +MinidumpMemoryRegion* MinidumpMemoryList::GetMemoryRegionForAddress( 1.2768 + uint64_t address) { 1.2769 + if (!valid_) { 1.2770 + BPLOG(ERROR) << "Invalid MinidumpMemoryList for GetMemoryRegionForAddress"; 1.2771 + return NULL; 1.2772 + } 1.2773 + 1.2774 + unsigned int region_index; 1.2775 + if (!range_map_->RetrieveRange(address, ®ion_index, NULL, NULL)) { 1.2776 + BPLOG(INFO) << "MinidumpMemoryList has no memory region at " << 1.2777 + HexString(address); 1.2778 + return NULL; 1.2779 + } 1.2780 + 1.2781 + return GetMemoryRegionAtIndex(region_index); 1.2782 +} 1.2783 + 1.2784 + 1.2785 +void MinidumpMemoryList::Print() { 1.2786 + if (!valid_) { 1.2787 + BPLOG(ERROR) << "MinidumpMemoryList cannot print invalid data"; 1.2788 + return; 1.2789 + } 1.2790 + 1.2791 + printf("MinidumpMemoryList\n"); 1.2792 + printf(" region_count = %d\n", region_count_); 1.2793 + printf("\n"); 1.2794 + 1.2795 + for (unsigned int region_index = 0; 1.2796 + region_index < region_count_; 1.2797 + ++region_index) { 1.2798 + MDMemoryDescriptor* descriptor = &(*descriptors_)[region_index]; 1.2799 + printf("region[%d]\n", region_index); 1.2800 + printf("MDMemoryDescriptor\n"); 1.2801 + printf(" start_of_memory_range = 0x%" PRIx64 "\n", 1.2802 + descriptor->start_of_memory_range); 1.2803 + printf(" memory.data_size = 0x%x\n", descriptor->memory.data_size); 1.2804 + printf(" memory.rva = 0x%x\n", descriptor->memory.rva); 1.2805 + MinidumpMemoryRegion* region = GetMemoryRegionAtIndex(region_index); 1.2806 + if (region) { 1.2807 + printf("Memory\n"); 1.2808 + region->Print(); 1.2809 + } else { 1.2810 + printf("No memory\n"); 1.2811 + } 1.2812 + printf("\n"); 1.2813 + } 1.2814 +} 1.2815 + 1.2816 + 1.2817 +// 1.2818 +// MinidumpException 1.2819 +// 1.2820 + 1.2821 + 1.2822 +MinidumpException::MinidumpException(Minidump* minidump) 1.2823 + : MinidumpStream(minidump), 1.2824 + exception_(), 1.2825 + context_(NULL) { 1.2826 +} 1.2827 + 1.2828 + 1.2829 +MinidumpException::~MinidumpException() { 1.2830 + delete context_; 1.2831 +} 1.2832 + 1.2833 + 1.2834 +bool MinidumpException::Read(uint32_t expected_size) { 1.2835 + // Invalidate cached data. 1.2836 + delete context_; 1.2837 + context_ = NULL; 1.2838 + 1.2839 + valid_ = false; 1.2840 + 1.2841 + if (expected_size != sizeof(exception_)) { 1.2842 + BPLOG(ERROR) << "MinidumpException size mismatch, " << expected_size << 1.2843 + " != " << sizeof(exception_); 1.2844 + return false; 1.2845 + } 1.2846 + 1.2847 + if (!minidump_->ReadBytes(&exception_, sizeof(exception_))) { 1.2848 + BPLOG(ERROR) << "MinidumpException cannot read exception"; 1.2849 + return false; 1.2850 + } 1.2851 + 1.2852 + if (minidump_->swap()) { 1.2853 + Swap(&exception_.thread_id); 1.2854 + // exception_.__align is for alignment only and does not need to be 1.2855 + // swapped. 1.2856 + Swap(&exception_.exception_record.exception_code); 1.2857 + Swap(&exception_.exception_record.exception_flags); 1.2858 + Swap(&exception_.exception_record.exception_record); 1.2859 + Swap(&exception_.exception_record.exception_address); 1.2860 + Swap(&exception_.exception_record.number_parameters); 1.2861 + // exception_.exception_record.__align is for alignment only and does not 1.2862 + // need to be swapped. 1.2863 + for (unsigned int parameter_index = 0; 1.2864 + parameter_index < MD_EXCEPTION_MAXIMUM_PARAMETERS; 1.2865 + ++parameter_index) { 1.2866 + Swap(&exception_.exception_record.exception_information[parameter_index]); 1.2867 + } 1.2868 + Swap(&exception_.thread_context); 1.2869 + } 1.2870 + 1.2871 + valid_ = true; 1.2872 + return true; 1.2873 +} 1.2874 + 1.2875 + 1.2876 +bool MinidumpException::GetThreadID(uint32_t *thread_id) const { 1.2877 + BPLOG_IF(ERROR, !thread_id) << "MinidumpException::GetThreadID requires " 1.2878 + "|thread_id|"; 1.2879 + assert(thread_id); 1.2880 + *thread_id = 0; 1.2881 + 1.2882 + if (!valid_) { 1.2883 + BPLOG(ERROR) << "Invalid MinidumpException for GetThreadID"; 1.2884 + return false; 1.2885 + } 1.2886 + 1.2887 + *thread_id = exception_.thread_id; 1.2888 + return true; 1.2889 +} 1.2890 + 1.2891 + 1.2892 +MinidumpContext* MinidumpException::GetContext() { 1.2893 + if (!valid_) { 1.2894 + BPLOG(ERROR) << "Invalid MinidumpException for GetContext"; 1.2895 + return NULL; 1.2896 + } 1.2897 + 1.2898 + if (!context_) { 1.2899 + if (!minidump_->SeekSet(exception_.thread_context.rva)) { 1.2900 + BPLOG(ERROR) << "MinidumpException cannot seek to context"; 1.2901 + return NULL; 1.2902 + } 1.2903 + 1.2904 + scoped_ptr<MinidumpContext> context(new MinidumpContext(minidump_)); 1.2905 + 1.2906 + // Don't log as an error if we can still fall back on the thread's context 1.2907 + // (which must be possible if we got this far.) 1.2908 + if (!context->Read(exception_.thread_context.data_size)) { 1.2909 + BPLOG(INFO) << "MinidumpException cannot read context"; 1.2910 + return NULL; 1.2911 + } 1.2912 + 1.2913 + context_ = context.release(); 1.2914 + } 1.2915 + 1.2916 + return context_; 1.2917 +} 1.2918 + 1.2919 + 1.2920 +void MinidumpException::Print() { 1.2921 + if (!valid_) { 1.2922 + BPLOG(ERROR) << "MinidumpException cannot print invalid data"; 1.2923 + return; 1.2924 + } 1.2925 + 1.2926 + printf("MDException\n"); 1.2927 + printf(" thread_id = 0x%x\n", 1.2928 + exception_.thread_id); 1.2929 + printf(" exception_record.exception_code = 0x%x\n", 1.2930 + exception_.exception_record.exception_code); 1.2931 + printf(" exception_record.exception_flags = 0x%x\n", 1.2932 + exception_.exception_record.exception_flags); 1.2933 + printf(" exception_record.exception_record = 0x%" PRIx64 "\n", 1.2934 + exception_.exception_record.exception_record); 1.2935 + printf(" exception_record.exception_address = 0x%" PRIx64 "\n", 1.2936 + exception_.exception_record.exception_address); 1.2937 + printf(" exception_record.number_parameters = %d\n", 1.2938 + exception_.exception_record.number_parameters); 1.2939 + for (unsigned int parameterIndex = 0; 1.2940 + parameterIndex < exception_.exception_record.number_parameters; 1.2941 + ++parameterIndex) { 1.2942 + printf(" exception_record.exception_information[%2d] = 0x%" PRIx64 "\n", 1.2943 + parameterIndex, 1.2944 + exception_.exception_record.exception_information[parameterIndex]); 1.2945 + } 1.2946 + printf(" thread_context.data_size = %d\n", 1.2947 + exception_.thread_context.data_size); 1.2948 + printf(" thread_context.rva = 0x%x\n", 1.2949 + exception_.thread_context.rva); 1.2950 + MinidumpContext* context = GetContext(); 1.2951 + if (context) { 1.2952 + printf("\n"); 1.2953 + context->Print(); 1.2954 + } else { 1.2955 + printf(" (no context)\n"); 1.2956 + printf("\n"); 1.2957 + } 1.2958 +} 1.2959 + 1.2960 +// 1.2961 +// MinidumpAssertion 1.2962 +// 1.2963 + 1.2964 + 1.2965 +MinidumpAssertion::MinidumpAssertion(Minidump* minidump) 1.2966 + : MinidumpStream(minidump), 1.2967 + assertion_(), 1.2968 + expression_(), 1.2969 + function_(), 1.2970 + file_() { 1.2971 +} 1.2972 + 1.2973 + 1.2974 +MinidumpAssertion::~MinidumpAssertion() { 1.2975 +} 1.2976 + 1.2977 + 1.2978 +bool MinidumpAssertion::Read(uint32_t expected_size) { 1.2979 + // Invalidate cached data. 1.2980 + valid_ = false; 1.2981 + 1.2982 + if (expected_size != sizeof(assertion_)) { 1.2983 + BPLOG(ERROR) << "MinidumpAssertion size mismatch, " << expected_size << 1.2984 + " != " << sizeof(assertion_); 1.2985 + return false; 1.2986 + } 1.2987 + 1.2988 + if (!minidump_->ReadBytes(&assertion_, sizeof(assertion_))) { 1.2989 + BPLOG(ERROR) << "MinidumpAssertion cannot read assertion"; 1.2990 + return false; 1.2991 + } 1.2992 + 1.2993 + // Each of {expression, function, file} is a UTF-16 string, 1.2994 + // we'll convert them to UTF-8 for ease of use. 1.2995 + // expression 1.2996 + // Since we don't have an explicit byte length for each string, 1.2997 + // we use UTF16codeunits to calculate word length, then derive byte 1.2998 + // length from that. 1.2999 + uint32_t word_length = UTF16codeunits(assertion_.expression, 1.3000 + sizeof(assertion_.expression)); 1.3001 + if (word_length > 0) { 1.3002 + uint32_t byte_length = word_length * 2; 1.3003 + vector<uint16_t> expression_utf16(word_length); 1.3004 + memcpy(&expression_utf16[0], &assertion_.expression[0], byte_length); 1.3005 + 1.3006 + scoped_ptr<string> new_expression(UTF16ToUTF8(expression_utf16, 1.3007 + minidump_->swap())); 1.3008 + if (new_expression.get()) 1.3009 + expression_ = *new_expression; 1.3010 + } 1.3011 + 1.3012 + // assertion 1.3013 + word_length = UTF16codeunits(assertion_.function, 1.3014 + sizeof(assertion_.function)); 1.3015 + if (word_length) { 1.3016 + uint32_t byte_length = word_length * 2; 1.3017 + vector<uint16_t> function_utf16(word_length); 1.3018 + memcpy(&function_utf16[0], &assertion_.function[0], byte_length); 1.3019 + scoped_ptr<string> new_function(UTF16ToUTF8(function_utf16, 1.3020 + minidump_->swap())); 1.3021 + if (new_function.get()) 1.3022 + function_ = *new_function; 1.3023 + } 1.3024 + 1.3025 + // file 1.3026 + word_length = UTF16codeunits(assertion_.file, 1.3027 + sizeof(assertion_.file)); 1.3028 + if (word_length > 0) { 1.3029 + uint32_t byte_length = word_length * 2; 1.3030 + vector<uint16_t> file_utf16(word_length); 1.3031 + memcpy(&file_utf16[0], &assertion_.file[0], byte_length); 1.3032 + scoped_ptr<string> new_file(UTF16ToUTF8(file_utf16, 1.3033 + minidump_->swap())); 1.3034 + if (new_file.get()) 1.3035 + file_ = *new_file; 1.3036 + } 1.3037 + 1.3038 + if (minidump_->swap()) { 1.3039 + Swap(&assertion_.line); 1.3040 + Swap(&assertion_.type); 1.3041 + } 1.3042 + 1.3043 + valid_ = true; 1.3044 + return true; 1.3045 +} 1.3046 + 1.3047 +void MinidumpAssertion::Print() { 1.3048 + if (!valid_) { 1.3049 + BPLOG(ERROR) << "MinidumpAssertion cannot print invalid data"; 1.3050 + return; 1.3051 + } 1.3052 + 1.3053 + printf("MDAssertion\n"); 1.3054 + printf(" expression = %s\n", 1.3055 + expression_.c_str()); 1.3056 + printf(" function = %s\n", 1.3057 + function_.c_str()); 1.3058 + printf(" file = %s\n", 1.3059 + file_.c_str()); 1.3060 + printf(" line = %u\n", 1.3061 + assertion_.line); 1.3062 + printf(" type = %u\n", 1.3063 + assertion_.type); 1.3064 + printf("\n"); 1.3065 +} 1.3066 + 1.3067 +// 1.3068 +// MinidumpSystemInfo 1.3069 +// 1.3070 + 1.3071 + 1.3072 +MinidumpSystemInfo::MinidumpSystemInfo(Minidump* minidump) 1.3073 + : MinidumpStream(minidump), 1.3074 + system_info_(), 1.3075 + csd_version_(NULL), 1.3076 + cpu_vendor_(NULL) { 1.3077 +} 1.3078 + 1.3079 + 1.3080 +MinidumpSystemInfo::~MinidumpSystemInfo() { 1.3081 + delete csd_version_; 1.3082 + delete cpu_vendor_; 1.3083 +} 1.3084 + 1.3085 + 1.3086 +bool MinidumpSystemInfo::Read(uint32_t expected_size) { 1.3087 + // Invalidate cached data. 1.3088 + delete csd_version_; 1.3089 + csd_version_ = NULL; 1.3090 + delete cpu_vendor_; 1.3091 + cpu_vendor_ = NULL; 1.3092 + 1.3093 + valid_ = false; 1.3094 + 1.3095 + if (expected_size != sizeof(system_info_)) { 1.3096 + BPLOG(ERROR) << "MinidumpSystemInfo size mismatch, " << expected_size << 1.3097 + " != " << sizeof(system_info_); 1.3098 + return false; 1.3099 + } 1.3100 + 1.3101 + if (!minidump_->ReadBytes(&system_info_, sizeof(system_info_))) { 1.3102 + BPLOG(ERROR) << "MinidumpSystemInfo cannot read system info"; 1.3103 + return false; 1.3104 + } 1.3105 + 1.3106 + if (minidump_->swap()) { 1.3107 + Swap(&system_info_.processor_architecture); 1.3108 + Swap(&system_info_.processor_level); 1.3109 + Swap(&system_info_.processor_revision); 1.3110 + // number_of_processors and product_type are 8-bit quantities and need no 1.3111 + // swapping. 1.3112 + Swap(&system_info_.major_version); 1.3113 + Swap(&system_info_.minor_version); 1.3114 + Swap(&system_info_.build_number); 1.3115 + Swap(&system_info_.platform_id); 1.3116 + Swap(&system_info_.csd_version_rva); 1.3117 + Swap(&system_info_.suite_mask); 1.3118 + // Don't swap the reserved2 field because its contents are unknown. 1.3119 + 1.3120 + if (system_info_.processor_architecture == MD_CPU_ARCHITECTURE_X86 || 1.3121 + system_info_.processor_architecture == MD_CPU_ARCHITECTURE_X86_WIN64) { 1.3122 + for (unsigned int i = 0; i < 3; ++i) 1.3123 + Swap(&system_info_.cpu.x86_cpu_info.vendor_id[i]); 1.3124 + Swap(&system_info_.cpu.x86_cpu_info.version_information); 1.3125 + Swap(&system_info_.cpu.x86_cpu_info.feature_information); 1.3126 + Swap(&system_info_.cpu.x86_cpu_info.amd_extended_cpu_features); 1.3127 + } else { 1.3128 + for (unsigned int i = 0; i < 2; ++i) 1.3129 + Swap(&system_info_.cpu.other_cpu_info.processor_features[i]); 1.3130 + } 1.3131 + } 1.3132 + 1.3133 + valid_ = true; 1.3134 + return true; 1.3135 +} 1.3136 + 1.3137 + 1.3138 +string MinidumpSystemInfo::GetOS() { 1.3139 + string os; 1.3140 + 1.3141 + if (!valid_) { 1.3142 + BPLOG(ERROR) << "Invalid MinidumpSystemInfo for GetOS"; 1.3143 + return os; 1.3144 + } 1.3145 + 1.3146 + switch (system_info_.platform_id) { 1.3147 + case MD_OS_WIN32_NT: 1.3148 + case MD_OS_WIN32_WINDOWS: 1.3149 + os = "windows"; 1.3150 + break; 1.3151 + 1.3152 + case MD_OS_MAC_OS_X: 1.3153 + os = "mac"; 1.3154 + break; 1.3155 + 1.3156 + case MD_OS_IOS: 1.3157 + os = "ios"; 1.3158 + break; 1.3159 + 1.3160 + case MD_OS_LINUX: 1.3161 + os = "linux"; 1.3162 + break; 1.3163 + 1.3164 + case MD_OS_SOLARIS: 1.3165 + os = "solaris"; 1.3166 + break; 1.3167 + 1.3168 + case MD_OS_ANDROID: 1.3169 + os = "android"; 1.3170 + break; 1.3171 + 1.3172 + default: 1.3173 + BPLOG(ERROR) << "MinidumpSystemInfo unknown OS for platform " << 1.3174 + HexString(system_info_.platform_id); 1.3175 + break; 1.3176 + } 1.3177 + 1.3178 + return os; 1.3179 +} 1.3180 + 1.3181 + 1.3182 +string MinidumpSystemInfo::GetCPU() { 1.3183 + if (!valid_) { 1.3184 + BPLOG(ERROR) << "Invalid MinidumpSystemInfo for GetCPU"; 1.3185 + return ""; 1.3186 + } 1.3187 + 1.3188 + string cpu; 1.3189 + 1.3190 + switch (system_info_.processor_architecture) { 1.3191 + case MD_CPU_ARCHITECTURE_X86: 1.3192 + case MD_CPU_ARCHITECTURE_X86_WIN64: 1.3193 + cpu = "x86"; 1.3194 + break; 1.3195 + 1.3196 + case MD_CPU_ARCHITECTURE_AMD64: 1.3197 + cpu = "x86-64"; 1.3198 + break; 1.3199 + 1.3200 + case MD_CPU_ARCHITECTURE_PPC: 1.3201 + cpu = "ppc"; 1.3202 + break; 1.3203 + 1.3204 + case MD_CPU_ARCHITECTURE_SPARC: 1.3205 + cpu = "sparc"; 1.3206 + break; 1.3207 + 1.3208 + case MD_CPU_ARCHITECTURE_ARM: 1.3209 + cpu = "arm"; 1.3210 + break; 1.3211 + 1.3212 + default: 1.3213 + BPLOG(ERROR) << "MinidumpSystemInfo unknown CPU for architecture " << 1.3214 + HexString(system_info_.processor_architecture); 1.3215 + break; 1.3216 + } 1.3217 + 1.3218 + return cpu; 1.3219 +} 1.3220 + 1.3221 + 1.3222 +const string* MinidumpSystemInfo::GetCSDVersion() { 1.3223 + if (!valid_) { 1.3224 + BPLOG(ERROR) << "Invalid MinidumpSystemInfo for GetCSDVersion"; 1.3225 + return NULL; 1.3226 + } 1.3227 + 1.3228 + if (!csd_version_) 1.3229 + csd_version_ = minidump_->ReadString(system_info_.csd_version_rva); 1.3230 + 1.3231 + BPLOG_IF(ERROR, !csd_version_) << "MinidumpSystemInfo could not read " 1.3232 + "CSD version"; 1.3233 + 1.3234 + return csd_version_; 1.3235 +} 1.3236 + 1.3237 + 1.3238 +const string* MinidumpSystemInfo::GetCPUVendor() { 1.3239 + if (!valid_) { 1.3240 + BPLOG(ERROR) << "Invalid MinidumpSystemInfo for GetCPUVendor"; 1.3241 + return NULL; 1.3242 + } 1.3243 + 1.3244 + // CPU vendor information can only be determined from x86 minidumps. 1.3245 + if (!cpu_vendor_ && 1.3246 + (system_info_.processor_architecture == MD_CPU_ARCHITECTURE_X86 || 1.3247 + system_info_.processor_architecture == MD_CPU_ARCHITECTURE_X86_WIN64)) { 1.3248 + char cpu_vendor_string[13]; 1.3249 + snprintf(cpu_vendor_string, sizeof(cpu_vendor_string), 1.3250 + "%c%c%c%c%c%c%c%c%c%c%c%c", 1.3251 + system_info_.cpu.x86_cpu_info.vendor_id[0] & 0xff, 1.3252 + (system_info_.cpu.x86_cpu_info.vendor_id[0] >> 8) & 0xff, 1.3253 + (system_info_.cpu.x86_cpu_info.vendor_id[0] >> 16) & 0xff, 1.3254 + (system_info_.cpu.x86_cpu_info.vendor_id[0] >> 24) & 0xff, 1.3255 + system_info_.cpu.x86_cpu_info.vendor_id[1] & 0xff, 1.3256 + (system_info_.cpu.x86_cpu_info.vendor_id[1] >> 8) & 0xff, 1.3257 + (system_info_.cpu.x86_cpu_info.vendor_id[1] >> 16) & 0xff, 1.3258 + (system_info_.cpu.x86_cpu_info.vendor_id[1] >> 24) & 0xff, 1.3259 + system_info_.cpu.x86_cpu_info.vendor_id[2] & 0xff, 1.3260 + (system_info_.cpu.x86_cpu_info.vendor_id[2] >> 8) & 0xff, 1.3261 + (system_info_.cpu.x86_cpu_info.vendor_id[2] >> 16) & 0xff, 1.3262 + (system_info_.cpu.x86_cpu_info.vendor_id[2] >> 24) & 0xff); 1.3263 + cpu_vendor_ = new string(cpu_vendor_string); 1.3264 + } 1.3265 + 1.3266 + return cpu_vendor_; 1.3267 +} 1.3268 + 1.3269 + 1.3270 +void MinidumpSystemInfo::Print() { 1.3271 + if (!valid_) { 1.3272 + BPLOG(ERROR) << "MinidumpSystemInfo cannot print invalid data"; 1.3273 + return; 1.3274 + } 1.3275 + 1.3276 + printf("MDRawSystemInfo\n"); 1.3277 + printf(" processor_architecture = %d\n", 1.3278 + system_info_.processor_architecture); 1.3279 + printf(" processor_level = %d\n", 1.3280 + system_info_.processor_level); 1.3281 + printf(" processor_revision = 0x%x\n", 1.3282 + system_info_.processor_revision); 1.3283 + printf(" number_of_processors = %d\n", 1.3284 + system_info_.number_of_processors); 1.3285 + printf(" product_type = %d\n", 1.3286 + system_info_.product_type); 1.3287 + printf(" major_version = %d\n", 1.3288 + system_info_.major_version); 1.3289 + printf(" minor_version = %d\n", 1.3290 + system_info_.minor_version); 1.3291 + printf(" build_number = %d\n", 1.3292 + system_info_.build_number); 1.3293 + printf(" platform_id = %d\n", 1.3294 + system_info_.platform_id); 1.3295 + printf(" csd_version_rva = 0x%x\n", 1.3296 + system_info_.csd_version_rva); 1.3297 + printf(" suite_mask = 0x%x\n", 1.3298 + system_info_.suite_mask); 1.3299 + for (unsigned int i = 0; i < 3; ++i) { 1.3300 + printf(" cpu.x86_cpu_info.vendor_id[%d] = 0x%x\n", 1.3301 + i, system_info_.cpu.x86_cpu_info.vendor_id[i]); 1.3302 + } 1.3303 + printf(" cpu.x86_cpu_info.version_information = 0x%x\n", 1.3304 + system_info_.cpu.x86_cpu_info.version_information); 1.3305 + printf(" cpu.x86_cpu_info.feature_information = 0x%x\n", 1.3306 + system_info_.cpu.x86_cpu_info.feature_information); 1.3307 + printf(" cpu.x86_cpu_info.amd_extended_cpu_features = 0x%x\n", 1.3308 + system_info_.cpu.x86_cpu_info.amd_extended_cpu_features); 1.3309 + const string* csd_version = GetCSDVersion(); 1.3310 + if (csd_version) { 1.3311 + printf(" (csd_version) = \"%s\"\n", 1.3312 + csd_version->c_str()); 1.3313 + } else { 1.3314 + printf(" (csd_version) = (null)\n"); 1.3315 + } 1.3316 + const string* cpu_vendor = GetCPUVendor(); 1.3317 + if (cpu_vendor) { 1.3318 + printf(" (cpu_vendor) = \"%s\"\n", 1.3319 + cpu_vendor->c_str()); 1.3320 + } else { 1.3321 + printf(" (cpu_vendor) = (null)\n"); 1.3322 + } 1.3323 + printf("\n"); 1.3324 +} 1.3325 + 1.3326 + 1.3327 +// 1.3328 +// MinidumpMiscInfo 1.3329 +// 1.3330 + 1.3331 + 1.3332 +MinidumpMiscInfo::MinidumpMiscInfo(Minidump* minidump) 1.3333 + : MinidumpStream(minidump), 1.3334 + misc_info_() { 1.3335 +} 1.3336 + 1.3337 + 1.3338 +bool MinidumpMiscInfo::Read(uint32_t expected_size) { 1.3339 + valid_ = false; 1.3340 + 1.3341 + if (expected_size != MD_MISCINFO_SIZE && 1.3342 + expected_size != MD_MISCINFO2_SIZE) { 1.3343 + BPLOG(ERROR) << "MinidumpMiscInfo size mismatch, " << expected_size << 1.3344 + " != " << MD_MISCINFO_SIZE << ", " << MD_MISCINFO2_SIZE << 1.3345 + ")"; 1.3346 + return false; 1.3347 + } 1.3348 + 1.3349 + if (!minidump_->ReadBytes(&misc_info_, expected_size)) { 1.3350 + BPLOG(ERROR) << "MinidumpMiscInfo cannot read miscellaneous info"; 1.3351 + return false; 1.3352 + } 1.3353 + 1.3354 + if (minidump_->swap()) { 1.3355 + Swap(&misc_info_.size_of_info); 1.3356 + Swap(&misc_info_.flags1); 1.3357 + Swap(&misc_info_.process_id); 1.3358 + Swap(&misc_info_.process_create_time); 1.3359 + Swap(&misc_info_.process_user_time); 1.3360 + Swap(&misc_info_.process_kernel_time); 1.3361 + if (misc_info_.size_of_info > MD_MISCINFO_SIZE) { 1.3362 + Swap(&misc_info_.processor_max_mhz); 1.3363 + Swap(&misc_info_.processor_current_mhz); 1.3364 + Swap(&misc_info_.processor_mhz_limit); 1.3365 + Swap(&misc_info_.processor_max_idle_state); 1.3366 + Swap(&misc_info_.processor_current_idle_state); 1.3367 + } 1.3368 + } 1.3369 + 1.3370 + if (expected_size != misc_info_.size_of_info) { 1.3371 + BPLOG(ERROR) << "MinidumpMiscInfo size mismatch, " << 1.3372 + expected_size << " != " << misc_info_.size_of_info; 1.3373 + return false; 1.3374 + } 1.3375 + 1.3376 + valid_ = true; 1.3377 + return true; 1.3378 +} 1.3379 + 1.3380 + 1.3381 +void MinidumpMiscInfo::Print() { 1.3382 + if (!valid_) { 1.3383 + BPLOG(ERROR) << "MinidumpMiscInfo cannot print invalid data"; 1.3384 + return; 1.3385 + } 1.3386 + 1.3387 + printf("MDRawMiscInfo\n"); 1.3388 + printf(" size_of_info = %d\n", misc_info_.size_of_info); 1.3389 + printf(" flags1 = 0x%x\n", misc_info_.flags1); 1.3390 + printf(" process_id = 0x%x\n", misc_info_.process_id); 1.3391 + printf(" process_create_time = 0x%x\n", 1.3392 + misc_info_.process_create_time); 1.3393 + printf(" process_user_time = 0x%x\n", 1.3394 + misc_info_.process_user_time); 1.3395 + printf(" process_kernel_time = 0x%x\n", 1.3396 + misc_info_.process_kernel_time); 1.3397 + if (misc_info_.size_of_info > MD_MISCINFO_SIZE) { 1.3398 + printf(" processor_max_mhz = %d\n", 1.3399 + misc_info_.processor_max_mhz); 1.3400 + printf(" processor_current_mhz = %d\n", 1.3401 + misc_info_.processor_current_mhz); 1.3402 + printf(" processor_mhz_limit = %d\n", 1.3403 + misc_info_.processor_mhz_limit); 1.3404 + printf(" processor_max_idle_state = 0x%x\n", 1.3405 + misc_info_.processor_max_idle_state); 1.3406 + printf(" processor_current_idle_state = 0x%x\n", 1.3407 + misc_info_.processor_current_idle_state); 1.3408 + } 1.3409 + printf("\n"); 1.3410 +} 1.3411 + 1.3412 + 1.3413 +// 1.3414 +// MinidumpBreakpadInfo 1.3415 +// 1.3416 + 1.3417 + 1.3418 +MinidumpBreakpadInfo::MinidumpBreakpadInfo(Minidump* minidump) 1.3419 + : MinidumpStream(minidump), 1.3420 + breakpad_info_() { 1.3421 +} 1.3422 + 1.3423 + 1.3424 +bool MinidumpBreakpadInfo::Read(uint32_t expected_size) { 1.3425 + valid_ = false; 1.3426 + 1.3427 + if (expected_size != sizeof(breakpad_info_)) { 1.3428 + BPLOG(ERROR) << "MinidumpBreakpadInfo size mismatch, " << expected_size << 1.3429 + " != " << sizeof(breakpad_info_); 1.3430 + return false; 1.3431 + } 1.3432 + 1.3433 + if (!minidump_->ReadBytes(&breakpad_info_, sizeof(breakpad_info_))) { 1.3434 + BPLOG(ERROR) << "MinidumpBreakpadInfo cannot read Breakpad info"; 1.3435 + return false; 1.3436 + } 1.3437 + 1.3438 + if (minidump_->swap()) { 1.3439 + Swap(&breakpad_info_.validity); 1.3440 + Swap(&breakpad_info_.dump_thread_id); 1.3441 + Swap(&breakpad_info_.requesting_thread_id); 1.3442 + } 1.3443 + 1.3444 + valid_ = true; 1.3445 + return true; 1.3446 +} 1.3447 + 1.3448 + 1.3449 +bool MinidumpBreakpadInfo::GetDumpThreadID(uint32_t *thread_id) const { 1.3450 + BPLOG_IF(ERROR, !thread_id) << "MinidumpBreakpadInfo::GetDumpThreadID " 1.3451 + "requires |thread_id|"; 1.3452 + assert(thread_id); 1.3453 + *thread_id = 0; 1.3454 + 1.3455 + if (!valid_) { 1.3456 + BPLOG(ERROR) << "Invalid MinidumpBreakpadInfo for GetDumpThreadID"; 1.3457 + return false; 1.3458 + } 1.3459 + 1.3460 + if (!(breakpad_info_.validity & MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID)) { 1.3461 + BPLOG(INFO) << "MinidumpBreakpadInfo has no dump thread"; 1.3462 + return false; 1.3463 + } 1.3464 + 1.3465 + *thread_id = breakpad_info_.dump_thread_id; 1.3466 + return true; 1.3467 +} 1.3468 + 1.3469 + 1.3470 +bool MinidumpBreakpadInfo::GetRequestingThreadID(uint32_t *thread_id) 1.3471 + const { 1.3472 + BPLOG_IF(ERROR, !thread_id) << "MinidumpBreakpadInfo::GetRequestingThreadID " 1.3473 + "requires |thread_id|"; 1.3474 + assert(thread_id); 1.3475 + *thread_id = 0; 1.3476 + 1.3477 + if (!thread_id || !valid_) { 1.3478 + BPLOG(ERROR) << "Invalid MinidumpBreakpadInfo for GetRequestingThreadID"; 1.3479 + return false; 1.3480 + } 1.3481 + 1.3482 + if (!(breakpad_info_.validity & 1.3483 + MD_BREAKPAD_INFO_VALID_REQUESTING_THREAD_ID)) { 1.3484 + BPLOG(INFO) << "MinidumpBreakpadInfo has no requesting thread"; 1.3485 + return false; 1.3486 + } 1.3487 + 1.3488 + *thread_id = breakpad_info_.requesting_thread_id; 1.3489 + return true; 1.3490 +} 1.3491 + 1.3492 + 1.3493 +void MinidumpBreakpadInfo::Print() { 1.3494 + if (!valid_) { 1.3495 + BPLOG(ERROR) << "MinidumpBreakpadInfo cannot print invalid data"; 1.3496 + return; 1.3497 + } 1.3498 + 1.3499 + printf("MDRawBreakpadInfo\n"); 1.3500 + printf(" validity = 0x%x\n", breakpad_info_.validity); 1.3501 + 1.3502 + if (breakpad_info_.validity & MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID) { 1.3503 + printf(" dump_thread_id = 0x%x\n", breakpad_info_.dump_thread_id); 1.3504 + } else { 1.3505 + printf(" dump_thread_id = (invalid)\n"); 1.3506 + } 1.3507 + 1.3508 + if (breakpad_info_.validity & MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID) { 1.3509 + printf(" requesting_thread_id = 0x%x\n", 1.3510 + breakpad_info_.requesting_thread_id); 1.3511 + } else { 1.3512 + printf(" requesting_thread_id = (invalid)\n"); 1.3513 + } 1.3514 + 1.3515 + printf("\n"); 1.3516 +} 1.3517 + 1.3518 + 1.3519 +// 1.3520 +// MinidumpMemoryInfo 1.3521 +// 1.3522 + 1.3523 + 1.3524 +MinidumpMemoryInfo::MinidumpMemoryInfo(Minidump* minidump) 1.3525 + : MinidumpObject(minidump), 1.3526 + memory_info_() { 1.3527 +} 1.3528 + 1.3529 + 1.3530 +bool MinidumpMemoryInfo::IsExecutable() const { 1.3531 + uint32_t protection = 1.3532 + memory_info_.protection & MD_MEMORY_PROTECTION_ACCESS_MASK; 1.3533 + return protection == MD_MEMORY_PROTECT_EXECUTE || 1.3534 + protection == MD_MEMORY_PROTECT_EXECUTE_READ || 1.3535 + protection == MD_MEMORY_PROTECT_EXECUTE_READWRITE; 1.3536 +} 1.3537 + 1.3538 + 1.3539 +bool MinidumpMemoryInfo::IsWritable() const { 1.3540 + uint32_t protection = 1.3541 + memory_info_.protection & MD_MEMORY_PROTECTION_ACCESS_MASK; 1.3542 + return protection == MD_MEMORY_PROTECT_READWRITE || 1.3543 + protection == MD_MEMORY_PROTECT_WRITECOPY || 1.3544 + protection == MD_MEMORY_PROTECT_EXECUTE_READWRITE || 1.3545 + protection == MD_MEMORY_PROTECT_EXECUTE_WRITECOPY; 1.3546 +} 1.3547 + 1.3548 + 1.3549 +bool MinidumpMemoryInfo::Read() { 1.3550 + valid_ = false; 1.3551 + 1.3552 + if (!minidump_->ReadBytes(&memory_info_, sizeof(memory_info_))) { 1.3553 + BPLOG(ERROR) << "MinidumpMemoryInfo cannot read memory info"; 1.3554 + return false; 1.3555 + } 1.3556 + 1.3557 + if (minidump_->swap()) { 1.3558 + Swap(&memory_info_.base_address); 1.3559 + Swap(&memory_info_.allocation_base); 1.3560 + Swap(&memory_info_.allocation_protection); 1.3561 + Swap(&memory_info_.region_size); 1.3562 + Swap(&memory_info_.state); 1.3563 + Swap(&memory_info_.protection); 1.3564 + Swap(&memory_info_.type); 1.3565 + } 1.3566 + 1.3567 + // Check for base + size overflow or undersize. 1.3568 + if (memory_info_.region_size == 0 || 1.3569 + memory_info_.region_size > numeric_limits<uint64_t>::max() - 1.3570 + memory_info_.base_address) { 1.3571 + BPLOG(ERROR) << "MinidumpMemoryInfo has a memory region problem, " << 1.3572 + HexString(memory_info_.base_address) << "+" << 1.3573 + HexString(memory_info_.region_size); 1.3574 + return false; 1.3575 + } 1.3576 + 1.3577 + valid_ = true; 1.3578 + return true; 1.3579 +} 1.3580 + 1.3581 + 1.3582 +void MinidumpMemoryInfo::Print() { 1.3583 + if (!valid_) { 1.3584 + BPLOG(ERROR) << "MinidumpMemoryInfo cannot print invalid data"; 1.3585 + return; 1.3586 + } 1.3587 + 1.3588 + printf("MDRawMemoryInfo\n"); 1.3589 + printf(" base_address = 0x%" PRIx64 "\n", 1.3590 + memory_info_.base_address); 1.3591 + printf(" allocation_base = 0x%" PRIx64 "\n", 1.3592 + memory_info_.allocation_base); 1.3593 + printf(" allocation_protection = 0x%x\n", 1.3594 + memory_info_.allocation_protection); 1.3595 + printf(" region_size = 0x%" PRIx64 "\n", memory_info_.region_size); 1.3596 + printf(" state = 0x%x\n", memory_info_.state); 1.3597 + printf(" protection = 0x%x\n", memory_info_.protection); 1.3598 + printf(" type = 0x%x\n", memory_info_.type); 1.3599 +} 1.3600 + 1.3601 + 1.3602 +// 1.3603 +// MinidumpMemoryInfoList 1.3604 +// 1.3605 + 1.3606 + 1.3607 +MinidumpMemoryInfoList::MinidumpMemoryInfoList(Minidump* minidump) 1.3608 + : MinidumpStream(minidump), 1.3609 + range_map_(new RangeMap<uint64_t, unsigned int>()), 1.3610 + infos_(NULL), 1.3611 + info_count_(0) { 1.3612 +} 1.3613 + 1.3614 + 1.3615 +MinidumpMemoryInfoList::~MinidumpMemoryInfoList() { 1.3616 + delete range_map_; 1.3617 + delete infos_; 1.3618 +} 1.3619 + 1.3620 + 1.3621 +bool MinidumpMemoryInfoList::Read(uint32_t expected_size) { 1.3622 + // Invalidate cached data. 1.3623 + delete infos_; 1.3624 + infos_ = NULL; 1.3625 + range_map_->Clear(); 1.3626 + info_count_ = 0; 1.3627 + 1.3628 + valid_ = false; 1.3629 + 1.3630 + MDRawMemoryInfoList header; 1.3631 + if (expected_size < sizeof(MDRawMemoryInfoList)) { 1.3632 + BPLOG(ERROR) << "MinidumpMemoryInfoList header size mismatch, " << 1.3633 + expected_size << " < " << sizeof(MDRawMemoryInfoList); 1.3634 + return false; 1.3635 + } 1.3636 + if (!minidump_->ReadBytes(&header, sizeof(header))) { 1.3637 + BPLOG(ERROR) << "MinidumpMemoryInfoList could not read header"; 1.3638 + return false; 1.3639 + } 1.3640 + 1.3641 + if (minidump_->swap()) { 1.3642 + Swap(&header.size_of_header); 1.3643 + Swap(&header.size_of_entry); 1.3644 + Swap(&header.number_of_entries); 1.3645 + } 1.3646 + 1.3647 + // Sanity check that the header is the expected size. 1.3648 + //TODO(ted): could possibly handle this more gracefully, assuming 1.3649 + // that future versions of the structs would be backwards-compatible. 1.3650 + if (header.size_of_header != sizeof(MDRawMemoryInfoList)) { 1.3651 + BPLOG(ERROR) << "MinidumpMemoryInfoList header size mismatch, " << 1.3652 + header.size_of_header << " != " << 1.3653 + sizeof(MDRawMemoryInfoList); 1.3654 + return false; 1.3655 + } 1.3656 + 1.3657 + // Sanity check that the entries are the expected size. 1.3658 + if (header.size_of_entry != sizeof(MDRawMemoryInfo)) { 1.3659 + BPLOG(ERROR) << "MinidumpMemoryInfoList entry size mismatch, " << 1.3660 + header.size_of_entry << " != " << 1.3661 + sizeof(MDRawMemoryInfo); 1.3662 + return false; 1.3663 + } 1.3664 + 1.3665 + if (header.number_of_entries > 1.3666 + numeric_limits<uint32_t>::max() / sizeof(MDRawMemoryInfo)) { 1.3667 + BPLOG(ERROR) << "MinidumpMemoryInfoList info count " << 1.3668 + header.number_of_entries << 1.3669 + " would cause multiplication overflow"; 1.3670 + return false; 1.3671 + } 1.3672 + 1.3673 + if (expected_size != sizeof(MDRawMemoryInfoList) + 1.3674 + header.number_of_entries * sizeof(MDRawMemoryInfo)) { 1.3675 + BPLOG(ERROR) << "MinidumpMemoryInfoList size mismatch, " << expected_size << 1.3676 + " != " << sizeof(MDRawMemoryInfoList) + 1.3677 + header.number_of_entries * sizeof(MDRawMemoryInfo); 1.3678 + return false; 1.3679 + } 1.3680 + 1.3681 + if (header.number_of_entries != 0) { 1.3682 + scoped_ptr<MinidumpMemoryInfos> infos( 1.3683 + new MinidumpMemoryInfos(header.number_of_entries, 1.3684 + MinidumpMemoryInfo(minidump_))); 1.3685 + 1.3686 + for (unsigned int index = 0; 1.3687 + index < header.number_of_entries; 1.3688 + ++index) { 1.3689 + MinidumpMemoryInfo* info = &(*infos)[index]; 1.3690 + 1.3691 + // Assume that the file offset is correct after the last read. 1.3692 + if (!info->Read()) { 1.3693 + BPLOG(ERROR) << "MinidumpMemoryInfoList cannot read info " << 1.3694 + index << "/" << header.number_of_entries; 1.3695 + return false; 1.3696 + } 1.3697 + 1.3698 + uint64_t base_address = info->GetBase(); 1.3699 + uint32_t region_size = info->GetSize(); 1.3700 + 1.3701 + if (!range_map_->StoreRange(base_address, region_size, index)) { 1.3702 + BPLOG(ERROR) << "MinidumpMemoryInfoList could not store" 1.3703 + " memory region " << 1.3704 + index << "/" << header.number_of_entries << ", " << 1.3705 + HexString(base_address) << "+" << 1.3706 + HexString(region_size); 1.3707 + return false; 1.3708 + } 1.3709 + } 1.3710 + 1.3711 + infos_ = infos.release(); 1.3712 + } 1.3713 + 1.3714 + info_count_ = header.number_of_entries; 1.3715 + 1.3716 + valid_ = true; 1.3717 + return true; 1.3718 +} 1.3719 + 1.3720 + 1.3721 +const MinidumpMemoryInfo* MinidumpMemoryInfoList::GetMemoryInfoAtIndex( 1.3722 + unsigned int index) const { 1.3723 + if (!valid_) { 1.3724 + BPLOG(ERROR) << "Invalid MinidumpMemoryInfoList for GetMemoryInfoAtIndex"; 1.3725 + return NULL; 1.3726 + } 1.3727 + 1.3728 + if (index >= info_count_) { 1.3729 + BPLOG(ERROR) << "MinidumpMemoryInfoList index out of range: " << 1.3730 + index << "/" << info_count_; 1.3731 + return NULL; 1.3732 + } 1.3733 + 1.3734 + return &(*infos_)[index]; 1.3735 +} 1.3736 + 1.3737 + 1.3738 +const MinidumpMemoryInfo* MinidumpMemoryInfoList::GetMemoryInfoForAddress( 1.3739 + uint64_t address) const { 1.3740 + if (!valid_) { 1.3741 + BPLOG(ERROR) << "Invalid MinidumpMemoryInfoList for" 1.3742 + " GetMemoryInfoForAddress"; 1.3743 + return NULL; 1.3744 + } 1.3745 + 1.3746 + unsigned int info_index; 1.3747 + if (!range_map_->RetrieveRange(address, &info_index, NULL, NULL)) { 1.3748 + BPLOG(INFO) << "MinidumpMemoryInfoList has no memory info at " << 1.3749 + HexString(address); 1.3750 + return NULL; 1.3751 + } 1.3752 + 1.3753 + return GetMemoryInfoAtIndex(info_index); 1.3754 +} 1.3755 + 1.3756 + 1.3757 +void MinidumpMemoryInfoList::Print() { 1.3758 + if (!valid_) { 1.3759 + BPLOG(ERROR) << "MinidumpMemoryInfoList cannot print invalid data"; 1.3760 + return; 1.3761 + } 1.3762 + 1.3763 + printf("MinidumpMemoryInfoList\n"); 1.3764 + printf(" info_count = %d\n", info_count_); 1.3765 + printf("\n"); 1.3766 + 1.3767 + for (unsigned int info_index = 0; 1.3768 + info_index < info_count_; 1.3769 + ++info_index) { 1.3770 + printf("info[%d]\n", info_index); 1.3771 + (*infos_)[info_index].Print(); 1.3772 + printf("\n"); 1.3773 + } 1.3774 +} 1.3775 + 1.3776 + 1.3777 +// 1.3778 +// Minidump 1.3779 +// 1.3780 + 1.3781 + 1.3782 +uint32_t Minidump::max_streams_ = 128; 1.3783 +unsigned int Minidump::max_string_length_ = 1024; 1.3784 + 1.3785 + 1.3786 +Minidump::Minidump(const string& path) 1.3787 + : header_(), 1.3788 + directory_(NULL), 1.3789 + stream_map_(new MinidumpStreamMap()), 1.3790 + path_(path), 1.3791 + stream_(NULL), 1.3792 + swap_(false), 1.3793 + valid_(false) { 1.3794 +} 1.3795 + 1.3796 +Minidump::Minidump(istream& stream) 1.3797 + : header_(), 1.3798 + directory_(NULL), 1.3799 + stream_map_(new MinidumpStreamMap()), 1.3800 + path_(), 1.3801 + stream_(&stream), 1.3802 + swap_(false), 1.3803 + valid_(false) { 1.3804 +} 1.3805 + 1.3806 +Minidump::~Minidump() { 1.3807 + if (stream_) { 1.3808 + BPLOG(INFO) << "Minidump closing minidump"; 1.3809 + } 1.3810 + if (!path_.empty()) { 1.3811 + delete stream_; 1.3812 + } 1.3813 + delete directory_; 1.3814 + delete stream_map_; 1.3815 +} 1.3816 + 1.3817 + 1.3818 +bool Minidump::Open() { 1.3819 + if (stream_ != NULL) { 1.3820 + BPLOG(INFO) << "Minidump reopening minidump " << path_; 1.3821 + 1.3822 + // The file is already open. Seek to the beginning, which is the position 1.3823 + // the file would be at if it were opened anew. 1.3824 + return SeekSet(0); 1.3825 + } 1.3826 + 1.3827 + stream_ = new ifstream(path_.c_str(), std::ios::in | std::ios::binary); 1.3828 + if (!stream_ || !stream_->good()) { 1.3829 + string error_string; 1.3830 + int error_code = ErrnoString(&error_string); 1.3831 + BPLOG(ERROR) << "Minidump could not open minidump " << path_ << 1.3832 + ", error " << error_code << ": " << error_string; 1.3833 + return false; 1.3834 + } 1.3835 + 1.3836 + BPLOG(INFO) << "Minidump opened minidump " << path_; 1.3837 + return true; 1.3838 +} 1.3839 + 1.3840 +bool Minidump::GetContextCPUFlagsFromSystemInfo(uint32_t *context_cpu_flags) { 1.3841 + // Initialize output parameters 1.3842 + *context_cpu_flags = 0; 1.3843 + 1.3844 + // Save the current stream position 1.3845 + off_t saved_position = Tell(); 1.3846 + if (saved_position == -1) { 1.3847 + // Failed to save the current stream position. 1.3848 + // Returns true because the current position of the stream is preserved. 1.3849 + return true; 1.3850 + } 1.3851 + 1.3852 + const MDRawSystemInfo* system_info = 1.3853 + GetSystemInfo() ? GetSystemInfo()->system_info() : NULL; 1.3854 + 1.3855 + if (system_info != NULL) { 1.3856 + switch (system_info->processor_architecture) { 1.3857 + case MD_CPU_ARCHITECTURE_X86: 1.3858 + *context_cpu_flags = MD_CONTEXT_X86; 1.3859 + break; 1.3860 + case MD_CPU_ARCHITECTURE_MIPS: 1.3861 + *context_cpu_flags = MD_CONTEXT_MIPS; 1.3862 + break; 1.3863 + case MD_CPU_ARCHITECTURE_ALPHA: 1.3864 + *context_cpu_flags = MD_CONTEXT_ALPHA; 1.3865 + break; 1.3866 + case MD_CPU_ARCHITECTURE_PPC: 1.3867 + *context_cpu_flags = MD_CONTEXT_PPC; 1.3868 + break; 1.3869 + case MD_CPU_ARCHITECTURE_SHX: 1.3870 + *context_cpu_flags = MD_CONTEXT_SHX; 1.3871 + break; 1.3872 + case MD_CPU_ARCHITECTURE_ARM: 1.3873 + *context_cpu_flags = MD_CONTEXT_ARM; 1.3874 + break; 1.3875 + case MD_CPU_ARCHITECTURE_IA64: 1.3876 + *context_cpu_flags = MD_CONTEXT_IA64; 1.3877 + break; 1.3878 + case MD_CPU_ARCHITECTURE_ALPHA64: 1.3879 + *context_cpu_flags = 0; 1.3880 + break; 1.3881 + case MD_CPU_ARCHITECTURE_MSIL: 1.3882 + *context_cpu_flags = 0; 1.3883 + break; 1.3884 + case MD_CPU_ARCHITECTURE_AMD64: 1.3885 + *context_cpu_flags = MD_CONTEXT_AMD64; 1.3886 + break; 1.3887 + case MD_CPU_ARCHITECTURE_X86_WIN64: 1.3888 + *context_cpu_flags = 0; 1.3889 + break; 1.3890 + case MD_CPU_ARCHITECTURE_SPARC: 1.3891 + *context_cpu_flags = MD_CONTEXT_SPARC; 1.3892 + break; 1.3893 + case MD_CPU_ARCHITECTURE_UNKNOWN: 1.3894 + *context_cpu_flags = 0; 1.3895 + break; 1.3896 + default: 1.3897 + *context_cpu_flags = 0; 1.3898 + break; 1.3899 + } 1.3900 + } 1.3901 + 1.3902 + // Restore position and return 1.3903 + return SeekSet(saved_position); 1.3904 +} 1.3905 + 1.3906 + 1.3907 +bool Minidump::Read() { 1.3908 + // Invalidate cached data. 1.3909 + delete directory_; 1.3910 + directory_ = NULL; 1.3911 + stream_map_->clear(); 1.3912 + 1.3913 + valid_ = false; 1.3914 + 1.3915 + if (!Open()) { 1.3916 + BPLOG(ERROR) << "Minidump cannot open minidump"; 1.3917 + return false; 1.3918 + } 1.3919 + 1.3920 + if (!ReadBytes(&header_, sizeof(MDRawHeader))) { 1.3921 + BPLOG(ERROR) << "Minidump cannot read header"; 1.3922 + return false; 1.3923 + } 1.3924 + 1.3925 + if (header_.signature != MD_HEADER_SIGNATURE) { 1.3926 + // The file may be byte-swapped. Under the present architecture, these 1.3927 + // classes don't know or need to know what CPU (or endianness) the 1.3928 + // minidump was produced on in order to parse it. Use the signature as 1.3929 + // a byte order marker. 1.3930 + uint32_t signature_swapped = header_.signature; 1.3931 + Swap(&signature_swapped); 1.3932 + if (signature_swapped != MD_HEADER_SIGNATURE) { 1.3933 + // This isn't a minidump or a byte-swapped minidump. 1.3934 + BPLOG(ERROR) << "Minidump header signature mismatch: (" << 1.3935 + HexString(header_.signature) << ", " << 1.3936 + HexString(signature_swapped) << ") != " << 1.3937 + HexString(MD_HEADER_SIGNATURE); 1.3938 + return false; 1.3939 + } 1.3940 + swap_ = true; 1.3941 + } else { 1.3942 + // The file is not byte-swapped. Set swap_ false (it may have been true 1.3943 + // if the object is being reused?) 1.3944 + swap_ = false; 1.3945 + } 1.3946 + 1.3947 + BPLOG(INFO) << "Minidump " << (swap_ ? "" : "not ") << 1.3948 + "byte-swapping minidump"; 1.3949 + 1.3950 + if (swap_) { 1.3951 + Swap(&header_.signature); 1.3952 + Swap(&header_.version); 1.3953 + Swap(&header_.stream_count); 1.3954 + Swap(&header_.stream_directory_rva); 1.3955 + Swap(&header_.checksum); 1.3956 + Swap(&header_.time_date_stamp); 1.3957 + Swap(&header_.flags); 1.3958 + } 1.3959 + 1.3960 + // Version check. The high 16 bits of header_.version contain something 1.3961 + // else "implementation specific." 1.3962 + if ((header_.version & 0x0000ffff) != MD_HEADER_VERSION) { 1.3963 + BPLOG(ERROR) << "Minidump version mismatch: " << 1.3964 + HexString(header_.version & 0x0000ffff) << " != " << 1.3965 + HexString(MD_HEADER_VERSION); 1.3966 + return false; 1.3967 + } 1.3968 + 1.3969 + if (!SeekSet(header_.stream_directory_rva)) { 1.3970 + BPLOG(ERROR) << "Minidump cannot seek to stream directory"; 1.3971 + return false; 1.3972 + } 1.3973 + 1.3974 + if (header_.stream_count > max_streams_) { 1.3975 + BPLOG(ERROR) << "Minidump stream count " << header_.stream_count << 1.3976 + " exceeds maximum " << max_streams_; 1.3977 + return false; 1.3978 + } 1.3979 + 1.3980 + if (header_.stream_count != 0) { 1.3981 + scoped_ptr<MinidumpDirectoryEntries> directory( 1.3982 + new MinidumpDirectoryEntries(header_.stream_count)); 1.3983 + 1.3984 + // Read the entire array in one fell swoop, instead of reading one entry 1.3985 + // at a time in the loop. 1.3986 + if (!ReadBytes(&(*directory)[0], 1.3987 + sizeof(MDRawDirectory) * header_.stream_count)) { 1.3988 + BPLOG(ERROR) << "Minidump cannot read stream directory"; 1.3989 + return false; 1.3990 + } 1.3991 + 1.3992 + for (unsigned int stream_index = 0; 1.3993 + stream_index < header_.stream_count; 1.3994 + ++stream_index) { 1.3995 + MDRawDirectory* directory_entry = &(*directory)[stream_index]; 1.3996 + 1.3997 + if (swap_) { 1.3998 + Swap(&directory_entry->stream_type); 1.3999 + Swap(&directory_entry->location); 1.4000 + } 1.4001 + 1.4002 + // Initialize the stream_map_ map, which speeds locating a stream by 1.4003 + // type. 1.4004 + unsigned int stream_type = directory_entry->stream_type; 1.4005 + switch (stream_type) { 1.4006 + case MD_THREAD_LIST_STREAM: 1.4007 + case MD_MODULE_LIST_STREAM: 1.4008 + case MD_MEMORY_LIST_STREAM: 1.4009 + case MD_EXCEPTION_STREAM: 1.4010 + case MD_SYSTEM_INFO_STREAM: 1.4011 + case MD_MISC_INFO_STREAM: 1.4012 + case MD_BREAKPAD_INFO_STREAM: { 1.4013 + if (stream_map_->find(stream_type) != stream_map_->end()) { 1.4014 + // Another stream with this type was already found. A minidump 1.4015 + // file should contain at most one of each of these stream types. 1.4016 + BPLOG(ERROR) << "Minidump found multiple streams of type " << 1.4017 + stream_type << ", but can only deal with one"; 1.4018 + return false; 1.4019 + } 1.4020 + // Fall through to default 1.4021 + } 1.4022 + 1.4023 + default: { 1.4024 + // Overwrites for stream types other than those above, but it's 1.4025 + // expected to be the user's burden in that case. 1.4026 + (*stream_map_)[stream_type].stream_index = stream_index; 1.4027 + } 1.4028 + } 1.4029 + } 1.4030 + 1.4031 + directory_ = directory.release(); 1.4032 + } 1.4033 + 1.4034 + valid_ = true; 1.4035 + return true; 1.4036 +} 1.4037 + 1.4038 + 1.4039 +MinidumpThreadList* Minidump::GetThreadList() { 1.4040 + MinidumpThreadList* thread_list; 1.4041 + return GetStream(&thread_list); 1.4042 +} 1.4043 + 1.4044 + 1.4045 +MinidumpModuleList* Minidump::GetModuleList() { 1.4046 + MinidumpModuleList* module_list; 1.4047 + return GetStream(&module_list); 1.4048 +} 1.4049 + 1.4050 + 1.4051 +MinidumpMemoryList* Minidump::GetMemoryList() { 1.4052 + MinidumpMemoryList* memory_list; 1.4053 + return GetStream(&memory_list); 1.4054 +} 1.4055 + 1.4056 + 1.4057 +MinidumpException* Minidump::GetException() { 1.4058 + MinidumpException* exception; 1.4059 + return GetStream(&exception); 1.4060 +} 1.4061 + 1.4062 +MinidumpAssertion* Minidump::GetAssertion() { 1.4063 + MinidumpAssertion* assertion; 1.4064 + return GetStream(&assertion); 1.4065 +} 1.4066 + 1.4067 + 1.4068 +MinidumpSystemInfo* Minidump::GetSystemInfo() { 1.4069 + MinidumpSystemInfo* system_info; 1.4070 + return GetStream(&system_info); 1.4071 +} 1.4072 + 1.4073 + 1.4074 +MinidumpMiscInfo* Minidump::GetMiscInfo() { 1.4075 + MinidumpMiscInfo* misc_info; 1.4076 + return GetStream(&misc_info); 1.4077 +} 1.4078 + 1.4079 + 1.4080 +MinidumpBreakpadInfo* Minidump::GetBreakpadInfo() { 1.4081 + MinidumpBreakpadInfo* breakpad_info; 1.4082 + return GetStream(&breakpad_info); 1.4083 +} 1.4084 + 1.4085 +MinidumpMemoryInfoList* Minidump::GetMemoryInfoList() { 1.4086 + MinidumpMemoryInfoList* memory_info_list; 1.4087 + return GetStream(&memory_info_list); 1.4088 +} 1.4089 + 1.4090 + 1.4091 +void Minidump::Print() { 1.4092 + if (!valid_) { 1.4093 + BPLOG(ERROR) << "Minidump cannot print invalid data"; 1.4094 + return; 1.4095 + } 1.4096 + 1.4097 + printf("MDRawHeader\n"); 1.4098 + printf(" signature = 0x%x\n", header_.signature); 1.4099 + printf(" version = 0x%x\n", header_.version); 1.4100 + printf(" stream_count = %d\n", header_.stream_count); 1.4101 + printf(" stream_directory_rva = 0x%x\n", header_.stream_directory_rva); 1.4102 + printf(" checksum = 0x%x\n", header_.checksum); 1.4103 + struct tm timestruct; 1.4104 +#ifdef _WIN32 1.4105 + gmtime_s(×truct, reinterpret_cast<time_t*>(&header_.time_date_stamp)); 1.4106 +#else 1.4107 + gmtime_r(reinterpret_cast<time_t*>(&header_.time_date_stamp), ×truct); 1.4108 +#endif 1.4109 + char timestr[20]; 1.4110 + strftime(timestr, 20, "%Y-%m-%d %H:%M:%S", ×truct); 1.4111 + printf(" time_date_stamp = 0x%x %s\n", header_.time_date_stamp, 1.4112 + timestr); 1.4113 + printf(" flags = 0x%" PRIx64 "\n", header_.flags); 1.4114 + printf("\n"); 1.4115 + 1.4116 + for (unsigned int stream_index = 0; 1.4117 + stream_index < header_.stream_count; 1.4118 + ++stream_index) { 1.4119 + MDRawDirectory* directory_entry = &(*directory_)[stream_index]; 1.4120 + 1.4121 + printf("mDirectory[%d]\n", stream_index); 1.4122 + printf("MDRawDirectory\n"); 1.4123 + printf(" stream_type = %d\n", directory_entry->stream_type); 1.4124 + printf(" location.data_size = %d\n", 1.4125 + directory_entry->location.data_size); 1.4126 + printf(" location.rva = 0x%x\n", directory_entry->location.rva); 1.4127 + printf("\n"); 1.4128 + } 1.4129 + 1.4130 + printf("Streams:\n"); 1.4131 + for (MinidumpStreamMap::const_iterator iterator = stream_map_->begin(); 1.4132 + iterator != stream_map_->end(); 1.4133 + ++iterator) { 1.4134 + uint32_t stream_type = iterator->first; 1.4135 + MinidumpStreamInfo info = iterator->second; 1.4136 + printf(" stream type 0x%x at index %d\n", stream_type, info.stream_index); 1.4137 + } 1.4138 + printf("\n"); 1.4139 +} 1.4140 + 1.4141 + 1.4142 +const MDRawDirectory* Minidump::GetDirectoryEntryAtIndex(unsigned int index) 1.4143 + const { 1.4144 + if (!valid_) { 1.4145 + BPLOG(ERROR) << "Invalid Minidump for GetDirectoryEntryAtIndex"; 1.4146 + return NULL; 1.4147 + } 1.4148 + 1.4149 + if (index >= header_.stream_count) { 1.4150 + BPLOG(ERROR) << "Minidump stream directory index out of range: " << 1.4151 + index << "/" << header_.stream_count; 1.4152 + return NULL; 1.4153 + } 1.4154 + 1.4155 + return &(*directory_)[index]; 1.4156 +} 1.4157 + 1.4158 + 1.4159 +bool Minidump::ReadBytes(void* bytes, size_t count) { 1.4160 + // Can't check valid_ because Read needs to call this method before 1.4161 + // validity can be determined. 1.4162 + if (!stream_) { 1.4163 + return false; 1.4164 + } 1.4165 + stream_->read(static_cast<char*>(bytes), count); 1.4166 + size_t bytes_read = stream_->gcount(); 1.4167 + if (bytes_read != count) { 1.4168 + if (bytes_read == size_t(-1)) { 1.4169 + string error_string; 1.4170 + int error_code = ErrnoString(&error_string); 1.4171 + BPLOG(ERROR) << "ReadBytes: error " << error_code << ": " << error_string; 1.4172 + } else { 1.4173 + BPLOG(ERROR) << "ReadBytes: read " << bytes_read << "/" << count; 1.4174 + } 1.4175 + return false; 1.4176 + } 1.4177 + return true; 1.4178 +} 1.4179 + 1.4180 + 1.4181 +bool Minidump::SeekSet(off_t offset) { 1.4182 + // Can't check valid_ because Read needs to call this method before 1.4183 + // validity can be determined. 1.4184 + if (!stream_) { 1.4185 + return false; 1.4186 + } 1.4187 + stream_->seekg(offset, std::ios_base::beg); 1.4188 + if (!stream_->good()) { 1.4189 + string error_string; 1.4190 + int error_code = ErrnoString(&error_string); 1.4191 + BPLOG(ERROR) << "SeekSet: error " << error_code << ": " << error_string; 1.4192 + return false; 1.4193 + } 1.4194 + return true; 1.4195 +} 1.4196 + 1.4197 +off_t Minidump::Tell() { 1.4198 + if (!valid_ || !stream_) { 1.4199 + return (off_t)-1; 1.4200 + } 1.4201 + 1.4202 + return stream_->tellg(); 1.4203 +} 1.4204 + 1.4205 + 1.4206 +string* Minidump::ReadString(off_t offset) { 1.4207 + if (!valid_) { 1.4208 + BPLOG(ERROR) << "Invalid Minidump for ReadString"; 1.4209 + return NULL; 1.4210 + } 1.4211 + if (!SeekSet(offset)) { 1.4212 + BPLOG(ERROR) << "ReadString could not seek to string at offset " << offset; 1.4213 + return NULL; 1.4214 + } 1.4215 + 1.4216 + uint32_t bytes; 1.4217 + if (!ReadBytes(&bytes, sizeof(bytes))) { 1.4218 + BPLOG(ERROR) << "ReadString could not read string size at offset " << 1.4219 + offset; 1.4220 + return NULL; 1.4221 + } 1.4222 + if (swap_) 1.4223 + Swap(&bytes); 1.4224 + 1.4225 + if (bytes % 2 != 0) { 1.4226 + BPLOG(ERROR) << "ReadString found odd-sized " << bytes << 1.4227 + "-byte string at offset " << offset; 1.4228 + return NULL; 1.4229 + } 1.4230 + unsigned int utf16_words = bytes / 2; 1.4231 + 1.4232 + if (utf16_words > max_string_length_) { 1.4233 + BPLOG(ERROR) << "ReadString string length " << utf16_words << 1.4234 + " exceeds maximum " << max_string_length_ << 1.4235 + " at offset " << offset; 1.4236 + return NULL; 1.4237 + } 1.4238 + 1.4239 + vector<uint16_t> string_utf16(utf16_words); 1.4240 + 1.4241 + if (utf16_words) { 1.4242 + if (!ReadBytes(&string_utf16[0], bytes)) { 1.4243 + BPLOG(ERROR) << "ReadString could not read " << bytes << 1.4244 + "-byte string at offset " << offset; 1.4245 + return NULL; 1.4246 + } 1.4247 + } 1.4248 + 1.4249 + return UTF16ToUTF8(string_utf16, swap_); 1.4250 +} 1.4251 + 1.4252 + 1.4253 +bool Minidump::SeekToStreamType(uint32_t stream_type, 1.4254 + uint32_t* stream_length) { 1.4255 + BPLOG_IF(ERROR, !stream_length) << "Minidump::SeekToStreamType requires " 1.4256 + "|stream_length|"; 1.4257 + assert(stream_length); 1.4258 + *stream_length = 0; 1.4259 + 1.4260 + if (!valid_) { 1.4261 + BPLOG(ERROR) << "Invalid Mindump for SeekToStreamType"; 1.4262 + return false; 1.4263 + } 1.4264 + 1.4265 + MinidumpStreamMap::const_iterator iterator = stream_map_->find(stream_type); 1.4266 + if (iterator == stream_map_->end()) { 1.4267 + // This stream type didn't exist in the directory. 1.4268 + BPLOG(INFO) << "SeekToStreamType: type " << stream_type << " not present"; 1.4269 + return false; 1.4270 + } 1.4271 + 1.4272 + MinidumpStreamInfo info = iterator->second; 1.4273 + if (info.stream_index >= header_.stream_count) { 1.4274 + BPLOG(ERROR) << "SeekToStreamType: type " << stream_type << 1.4275 + " out of range: " << 1.4276 + info.stream_index << "/" << header_.stream_count; 1.4277 + return false; 1.4278 + } 1.4279 + 1.4280 + MDRawDirectory* directory_entry = &(*directory_)[info.stream_index]; 1.4281 + if (!SeekSet(directory_entry->location.rva)) { 1.4282 + BPLOG(ERROR) << "SeekToStreamType could not seek to stream type " << 1.4283 + stream_type; 1.4284 + return false; 1.4285 + } 1.4286 + 1.4287 + *stream_length = directory_entry->location.data_size; 1.4288 + 1.4289 + return true; 1.4290 +} 1.4291 + 1.4292 + 1.4293 +template<typename T> 1.4294 +T* Minidump::GetStream(T** stream) { 1.4295 + // stream is a garbage parameter that's present only to account for C++'s 1.4296 + // inability to overload a method based solely on its return type. 1.4297 + 1.4298 + const uint32_t stream_type = T::kStreamType; 1.4299 + 1.4300 + BPLOG_IF(ERROR, !stream) << "Minidump::GetStream type " << stream_type << 1.4301 + " requires |stream|"; 1.4302 + assert(stream); 1.4303 + *stream = NULL; 1.4304 + 1.4305 + if (!valid_) { 1.4306 + BPLOG(ERROR) << "Invalid Minidump for GetStream type " << stream_type; 1.4307 + return NULL; 1.4308 + } 1.4309 + 1.4310 + MinidumpStreamMap::iterator iterator = stream_map_->find(stream_type); 1.4311 + if (iterator == stream_map_->end()) { 1.4312 + // This stream type didn't exist in the directory. 1.4313 + BPLOG(INFO) << "GetStream: type " << stream_type << " not present"; 1.4314 + return NULL; 1.4315 + } 1.4316 + 1.4317 + // Get a pointer so that the stored stream field can be altered. 1.4318 + MinidumpStreamInfo* info = &iterator->second; 1.4319 + 1.4320 + if (info->stream) { 1.4321 + // This cast is safe because info.stream is only populated by this 1.4322 + // method, and there is a direct correlation between T and stream_type. 1.4323 + *stream = static_cast<T*>(info->stream); 1.4324 + return *stream; 1.4325 + } 1.4326 + 1.4327 + uint32_t stream_length; 1.4328 + if (!SeekToStreamType(stream_type, &stream_length)) { 1.4329 + BPLOG(ERROR) << "GetStream could not seek to stream type " << stream_type; 1.4330 + return NULL; 1.4331 + } 1.4332 + 1.4333 + scoped_ptr<T> new_stream(new T(this)); 1.4334 + 1.4335 + if (!new_stream->Read(stream_length)) { 1.4336 + BPLOG(ERROR) << "GetStream could not read stream type " << stream_type; 1.4337 + return NULL; 1.4338 + } 1.4339 + 1.4340 + *stream = new_stream.release(); 1.4341 + info->stream = *stream; 1.4342 + return *stream; 1.4343 +} 1.4344 + 1.4345 + 1.4346 +} // namespace google_breakpad