xref: /aosp_15_r20/external/google-breakpad/src/processor/minidump.cc (revision 9712c20fc9bbfbac4935993a2ca0b3958c5adad2)
1*9712c20fSFrederick Mayle // Copyright 2010 Google LLC
2*9712c20fSFrederick Mayle //
3*9712c20fSFrederick Mayle // Redistribution and use in source and binary forms, with or without
4*9712c20fSFrederick Mayle // modification, are permitted provided that the following conditions are
5*9712c20fSFrederick Mayle // met:
6*9712c20fSFrederick Mayle //
7*9712c20fSFrederick Mayle //     * Redistributions of source code must retain the above copyright
8*9712c20fSFrederick Mayle // notice, this list of conditions and the following disclaimer.
9*9712c20fSFrederick Mayle //     * Redistributions in binary form must reproduce the above
10*9712c20fSFrederick Mayle // copyright notice, this list of conditions and the following disclaimer
11*9712c20fSFrederick Mayle // in the documentation and/or other materials provided with the
12*9712c20fSFrederick Mayle // distribution.
13*9712c20fSFrederick Mayle //     * Neither the name of Google LLC nor the names of its
14*9712c20fSFrederick Mayle // contributors may be used to endorse or promote products derived from
15*9712c20fSFrederick Mayle // this software without specific prior written permission.
16*9712c20fSFrederick Mayle //
17*9712c20fSFrederick Mayle // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18*9712c20fSFrederick Mayle // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19*9712c20fSFrederick Mayle // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20*9712c20fSFrederick Mayle // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21*9712c20fSFrederick Mayle // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22*9712c20fSFrederick Mayle // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23*9712c20fSFrederick Mayle // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24*9712c20fSFrederick Mayle // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25*9712c20fSFrederick Mayle // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26*9712c20fSFrederick Mayle // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27*9712c20fSFrederick Mayle // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28*9712c20fSFrederick Mayle 
29*9712c20fSFrederick Mayle // minidump.cc: A minidump reader.
30*9712c20fSFrederick Mayle //
31*9712c20fSFrederick Mayle // See minidump.h for documentation.
32*9712c20fSFrederick Mayle //
33*9712c20fSFrederick Mayle // Author: Mark Mentovai
34*9712c20fSFrederick Mayle 
35*9712c20fSFrederick Mayle #ifdef HAVE_CONFIG_H
36*9712c20fSFrederick Mayle #include <config.h>  // Must come first
37*9712c20fSFrederick Mayle #endif
38*9712c20fSFrederick Mayle 
39*9712c20fSFrederick Mayle #include "google_breakpad/processor/minidump.h"
40*9712c20fSFrederick Mayle 
41*9712c20fSFrederick Mayle #include <assert.h>
42*9712c20fSFrederick Mayle #include <fcntl.h>
43*9712c20fSFrederick Mayle #include <inttypes.h>
44*9712c20fSFrederick Mayle #include <stddef.h>
45*9712c20fSFrederick Mayle #include <string.h>
46*9712c20fSFrederick Mayle #include <time.h>
47*9712c20fSFrederick Mayle 
48*9712c20fSFrederick Mayle #ifdef _WIN32
49*9712c20fSFrederick Mayle #include <io.h>
50*9712c20fSFrederick Mayle #else  // _WIN32
51*9712c20fSFrederick Mayle #include <unistd.h>
52*9712c20fSFrederick Mayle #endif  // _WIN32
53*9712c20fSFrederick Mayle 
54*9712c20fSFrederick Mayle #include <algorithm>
55*9712c20fSFrederick Mayle #include <fstream>
56*9712c20fSFrederick Mayle #include <limits>
57*9712c20fSFrederick Mayle #include <utility>
58*9712c20fSFrederick Mayle 
59*9712c20fSFrederick Mayle #include "processor/range_map-inl.h"
60*9712c20fSFrederick Mayle 
61*9712c20fSFrederick Mayle #include "common/macros.h"
62*9712c20fSFrederick Mayle #include "common/scoped_ptr.h"
63*9712c20fSFrederick Mayle #include "common/stdio_wrapper.h"
64*9712c20fSFrederick Mayle #include "google_breakpad/processor/dump_context.h"
65*9712c20fSFrederick Mayle #include "processor/basic_code_module.h"
66*9712c20fSFrederick Mayle #include "processor/basic_code_modules.h"
67*9712c20fSFrederick Mayle #include "processor/convert_old_arm64_context.h"
68*9712c20fSFrederick Mayle #include "processor/logging.h"
69*9712c20fSFrederick Mayle 
70*9712c20fSFrederick Mayle namespace google_breakpad {
71*9712c20fSFrederick Mayle 
72*9712c20fSFrederick Mayle using std::istream;
73*9712c20fSFrederick Mayle using std::ifstream;
74*9712c20fSFrederick Mayle using std::numeric_limits;
75*9712c20fSFrederick Mayle using std::vector;
76*9712c20fSFrederick Mayle 
77*9712c20fSFrederick Mayle namespace {
78*9712c20fSFrederick Mayle 
79*9712c20fSFrederick Mayle // Limit arrived at by adding up possible states in Intel Ch. 13.5 X-SAVE
80*9712c20fSFrederick Mayle // MANAGED STATE
81*9712c20fSFrederick Mayle // (~ 3680 bytes) plus some extra for the future.
82*9712c20fSFrederick Mayle const uint32_t kMaxXSaveAreaSize = 16384;
83*9712c20fSFrederick Mayle 
84*9712c20fSFrederick Mayle // Returns true iff |context_size| matches exactly one of the sizes of the
85*9712c20fSFrederick Mayle // various MDRawContext* types.
86*9712c20fSFrederick Mayle // TODO(blundell): This function can be removed once
87*9712c20fSFrederick Mayle // https://bugs.chromium.org/p/google-breakpad/issues/detail?id=550 is fixed.
IsContextSizeUnique(uint32_t context_size)88*9712c20fSFrederick Mayle bool IsContextSizeUnique(uint32_t context_size) {
89*9712c20fSFrederick Mayle   int num_matching_contexts = 0;
90*9712c20fSFrederick Mayle   if (context_size == sizeof(MDRawContextX86))
91*9712c20fSFrederick Mayle     num_matching_contexts++;
92*9712c20fSFrederick Mayle   if (context_size == sizeof(MDRawContextPPC))
93*9712c20fSFrederick Mayle     num_matching_contexts++;
94*9712c20fSFrederick Mayle   if (context_size == sizeof(MDRawContextPPC64))
95*9712c20fSFrederick Mayle     num_matching_contexts++;
96*9712c20fSFrederick Mayle   if (context_size == sizeof(MDRawContextAMD64))
97*9712c20fSFrederick Mayle     num_matching_contexts++;
98*9712c20fSFrederick Mayle   if (context_size == sizeof(MDRawContextSPARC))
99*9712c20fSFrederick Mayle     num_matching_contexts++;
100*9712c20fSFrederick Mayle   if (context_size == sizeof(MDRawContextARM))
101*9712c20fSFrederick Mayle     num_matching_contexts++;
102*9712c20fSFrederick Mayle   if (context_size == sizeof(MDRawContextARM64))
103*9712c20fSFrederick Mayle     num_matching_contexts++;
104*9712c20fSFrederick Mayle   if (context_size == sizeof(MDRawContextARM64_Old))
105*9712c20fSFrederick Mayle     num_matching_contexts++;
106*9712c20fSFrederick Mayle   if (context_size == sizeof(MDRawContextMIPS))
107*9712c20fSFrederick Mayle     num_matching_contexts++;
108*9712c20fSFrederick Mayle   if (context_size == sizeof(MDRawContextRISCV))
109*9712c20fSFrederick Mayle     num_matching_contexts++;
110*9712c20fSFrederick Mayle   if (context_size == sizeof(MDRawContextRISCV64))
111*9712c20fSFrederick Mayle     num_matching_contexts++;
112*9712c20fSFrederick Mayle   return num_matching_contexts == 1;
113*9712c20fSFrederick Mayle }
114*9712c20fSFrederick Mayle 
115*9712c20fSFrederick Mayle //
116*9712c20fSFrederick Mayle // Swapping routines
117*9712c20fSFrederick Mayle //
118*9712c20fSFrederick Mayle // Inlining these doesn't increase code size significantly, and it saves
119*9712c20fSFrederick Mayle // a whole lot of unnecessary jumping back and forth.
120*9712c20fSFrederick Mayle //
121*9712c20fSFrederick Mayle 
122*9712c20fSFrederick Mayle 
123*9712c20fSFrederick Mayle // Swapping an 8-bit quantity is a no-op.  This function is only provided
124*9712c20fSFrederick Mayle // to account for certain templatized operations that require swapping for
125*9712c20fSFrederick Mayle // wider types but handle uint8_t too
126*9712c20fSFrederick Mayle // (MinidumpMemoryRegion::GetMemoryAtAddressInternal).
Swap(uint8_t * value)127*9712c20fSFrederick Mayle inline void Swap(uint8_t* value) {}
128*9712c20fSFrederick Mayle 
129*9712c20fSFrederick Mayle // Optimization: don't need to AND the furthest right shift, because we're
130*9712c20fSFrederick Mayle // shifting an unsigned quantity.  The standard requires zero-filling in this
131*9712c20fSFrederick Mayle // case.  If the quantities were signed, a bitmask whould be needed for this
132*9712c20fSFrederick Mayle // right shift to avoid an arithmetic shift (which retains the sign bit).
133*9712c20fSFrederick Mayle // The furthest left shift never needs to be ANDed bitmask.
134*9712c20fSFrederick Mayle 
Swap(uint16_t * value)135*9712c20fSFrederick Mayle inline void Swap(uint16_t* value) {
136*9712c20fSFrederick Mayle   *value = (*value >> 8) | (*value << 8);
137*9712c20fSFrederick Mayle }
138*9712c20fSFrederick Mayle 
Swap(uint32_t * value)139*9712c20fSFrederick Mayle inline void Swap(uint32_t* value) {
140*9712c20fSFrederick Mayle   *value =  (*value >> 24) |
141*9712c20fSFrederick Mayle            ((*value >> 8)  & 0x0000ff00) |
142*9712c20fSFrederick Mayle            ((*value << 8)  & 0x00ff0000) |
143*9712c20fSFrederick Mayle             (*value << 24);
144*9712c20fSFrederick Mayle }
145*9712c20fSFrederick Mayle 
Swap(uint64_t * value)146*9712c20fSFrederick Mayle inline void Swap(uint64_t* value) {
147*9712c20fSFrederick Mayle   uint32_t* value32 = reinterpret_cast<uint32_t*>(value);
148*9712c20fSFrederick Mayle   Swap(&value32[0]);
149*9712c20fSFrederick Mayle   Swap(&value32[1]);
150*9712c20fSFrederick Mayle   uint32_t temp = value32[0];
151*9712c20fSFrederick Mayle   value32[0] = value32[1];
152*9712c20fSFrederick Mayle   value32[1] = temp;
153*9712c20fSFrederick Mayle }
154*9712c20fSFrederick Mayle 
155*9712c20fSFrederick Mayle 
156*9712c20fSFrederick Mayle // Given a pointer to a 128-bit int in the minidump data, set the "low"
157*9712c20fSFrederick Mayle // and "high" fields appropriately.
Normalize128(uint128_struct * value,bool is_big_endian)158*9712c20fSFrederick Mayle void Normalize128(uint128_struct* value, bool is_big_endian) {
159*9712c20fSFrederick Mayle   // The struct format is [high, low], so if the format is big-endian,
160*9712c20fSFrederick Mayle   // the most significant bytes will already be in the high field.
161*9712c20fSFrederick Mayle   if (!is_big_endian) {
162*9712c20fSFrederick Mayle     uint64_t temp = value->low;
163*9712c20fSFrederick Mayle     value->low = value->high;
164*9712c20fSFrederick Mayle     value->high = temp;
165*9712c20fSFrederick Mayle   }
166*9712c20fSFrederick Mayle }
167*9712c20fSFrederick Mayle 
168*9712c20fSFrederick Mayle // This just swaps each int64 half of the 128-bit value.
169*9712c20fSFrederick Mayle // The value should also be normalized by calling Normalize128().
Swap(uint128_struct * value)170*9712c20fSFrederick Mayle void Swap(uint128_struct* value) {
171*9712c20fSFrederick Mayle   Swap(&value->low);
172*9712c20fSFrederick Mayle   Swap(&value->high);
173*9712c20fSFrederick Mayle }
174*9712c20fSFrederick Mayle 
175*9712c20fSFrederick Mayle // Swapping signed integers
Swap(int32_t * value)176*9712c20fSFrederick Mayle inline void Swap(int32_t* value) {
177*9712c20fSFrederick Mayle   Swap(reinterpret_cast<uint32_t*>(value));
178*9712c20fSFrederick Mayle }
179*9712c20fSFrederick Mayle 
Swap(MDLocationDescriptor * location_descriptor)180*9712c20fSFrederick Mayle inline void Swap(MDLocationDescriptor* location_descriptor) {
181*9712c20fSFrederick Mayle   Swap(&location_descriptor->data_size);
182*9712c20fSFrederick Mayle   Swap(&location_descriptor->rva);
183*9712c20fSFrederick Mayle }
184*9712c20fSFrederick Mayle 
Swap(MDMemoryDescriptor * memory_descriptor)185*9712c20fSFrederick Mayle inline void Swap(MDMemoryDescriptor* memory_descriptor) {
186*9712c20fSFrederick Mayle   Swap(&memory_descriptor->start_of_memory_range);
187*9712c20fSFrederick Mayle   Swap(&memory_descriptor->memory);
188*9712c20fSFrederick Mayle }
189*9712c20fSFrederick Mayle 
Swap(MDGUID * guid)190*9712c20fSFrederick Mayle inline void Swap(MDGUID* guid) {
191*9712c20fSFrederick Mayle   Swap(&guid->data1);
192*9712c20fSFrederick Mayle   Swap(&guid->data2);
193*9712c20fSFrederick Mayle   Swap(&guid->data3);
194*9712c20fSFrederick Mayle   // Don't swap guid->data4[] because it contains 8-bit quantities.
195*9712c20fSFrederick Mayle }
196*9712c20fSFrederick Mayle 
Swap(MDSystemTime * system_time)197*9712c20fSFrederick Mayle inline void Swap(MDSystemTime* system_time) {
198*9712c20fSFrederick Mayle   Swap(&system_time->year);
199*9712c20fSFrederick Mayle   Swap(&system_time->month);
200*9712c20fSFrederick Mayle   Swap(&system_time->day_of_week);
201*9712c20fSFrederick Mayle   Swap(&system_time->day);
202*9712c20fSFrederick Mayle   Swap(&system_time->hour);
203*9712c20fSFrederick Mayle   Swap(&system_time->minute);
204*9712c20fSFrederick Mayle   Swap(&system_time->second);
205*9712c20fSFrederick Mayle   Swap(&system_time->milliseconds);
206*9712c20fSFrederick Mayle }
207*9712c20fSFrederick Mayle 
Swap(MDXStateFeature * xstate_feature)208*9712c20fSFrederick Mayle inline void Swap(MDXStateFeature* xstate_feature) {
209*9712c20fSFrederick Mayle   Swap(&xstate_feature->offset);
210*9712c20fSFrederick Mayle   Swap(&xstate_feature->size);
211*9712c20fSFrederick Mayle }
212*9712c20fSFrederick Mayle 
Swap(MDXStateConfigFeatureMscInfo * xstate_feature_info)213*9712c20fSFrederick Mayle inline void Swap(MDXStateConfigFeatureMscInfo* xstate_feature_info) {
214*9712c20fSFrederick Mayle   Swap(&xstate_feature_info->size_of_info);
215*9712c20fSFrederick Mayle   Swap(&xstate_feature_info->context_size);
216*9712c20fSFrederick Mayle   Swap(&xstate_feature_info->enabled_features);
217*9712c20fSFrederick Mayle 
218*9712c20fSFrederick Mayle   for (size_t i = 0; i < MD_MAXIMUM_XSTATE_FEATURES; i++) {
219*9712c20fSFrederick Mayle     Swap(&xstate_feature_info->features[i]);
220*9712c20fSFrederick Mayle   }
221*9712c20fSFrederick Mayle }
222*9712c20fSFrederick Mayle 
Swap(MDRawSimpleStringDictionaryEntry * entry)223*9712c20fSFrederick Mayle inline void Swap(MDRawSimpleStringDictionaryEntry* entry) {
224*9712c20fSFrederick Mayle   Swap(&entry->key);
225*9712c20fSFrederick Mayle   Swap(&entry->value);
226*9712c20fSFrederick Mayle }
227*9712c20fSFrederick Mayle 
Swap(MDRawCrashpadAnnotation * annotation)228*9712c20fSFrederick Mayle inline void Swap(MDRawCrashpadAnnotation* annotation) {
229*9712c20fSFrederick Mayle   Swap(&annotation->name);
230*9712c20fSFrederick Mayle   Swap(&annotation->type);
231*9712c20fSFrederick Mayle   Swap(&annotation->value);
232*9712c20fSFrederick Mayle }
233*9712c20fSFrederick Mayle 
Swap(uint16_t * data,size_t size_in_bytes)234*9712c20fSFrederick Mayle inline void Swap(uint16_t* data, size_t size_in_bytes) {
235*9712c20fSFrederick Mayle   size_t data_length = size_in_bytes / sizeof(data[0]);
236*9712c20fSFrederick Mayle   for (size_t i = 0; i < data_length; i++) {
237*9712c20fSFrederick Mayle     Swap(&data[i]);
238*9712c20fSFrederick Mayle   }
239*9712c20fSFrederick Mayle }
240*9712c20fSFrederick Mayle 
241*9712c20fSFrederick Mayle //
242*9712c20fSFrederick Mayle // Character conversion routines
243*9712c20fSFrederick Mayle //
244*9712c20fSFrederick Mayle 
245*9712c20fSFrederick Mayle 
246*9712c20fSFrederick Mayle // Standard wide-character conversion routines depend on the system's own
247*9712c20fSFrederick Mayle // idea of what width a wide character should be: some use 16 bits, and
248*9712c20fSFrederick Mayle // some use 32 bits.  For the purposes of a minidump, wide strings are
249*9712c20fSFrederick Mayle // always represented with 16-bit UTF-16 chracters.  iconv isn't available
250*9712c20fSFrederick Mayle // everywhere, and its interface varies where it is available.  iconv also
251*9712c20fSFrederick Mayle // deals purely with char* pointers, so in addition to considering the swap
252*9712c20fSFrederick Mayle // parameter, a converter that uses iconv would also need to take the host
253*9712c20fSFrederick Mayle // CPU's endianness into consideration.  It doesn't seems worth the trouble
254*9712c20fSFrederick Mayle // of making it a dependency when we don't care about anything but UTF-16.
UTF16ToUTF8(const vector<uint16_t> & in,bool swap)255*9712c20fSFrederick Mayle string* UTF16ToUTF8(const vector<uint16_t>& in, bool swap) {
256*9712c20fSFrederick Mayle   scoped_ptr<string> out(new string());
257*9712c20fSFrederick Mayle 
258*9712c20fSFrederick Mayle   // Set the string's initial capacity to the number of UTF-16 characters,
259*9712c20fSFrederick Mayle   // because the UTF-8 representation will always be at least this long.
260*9712c20fSFrederick Mayle   // If the UTF-8 representation is longer, the string will grow dynamically.
261*9712c20fSFrederick Mayle   out->reserve(in.size());
262*9712c20fSFrederick Mayle 
263*9712c20fSFrederick Mayle   for (vector<uint16_t>::const_iterator iterator = in.begin();
264*9712c20fSFrederick Mayle        iterator != in.end();
265*9712c20fSFrederick Mayle        ++iterator) {
266*9712c20fSFrederick Mayle     // Get a 16-bit value from the input
267*9712c20fSFrederick Mayle     uint16_t in_word = *iterator;
268*9712c20fSFrederick Mayle     if (swap)
269*9712c20fSFrederick Mayle       Swap(&in_word);
270*9712c20fSFrederick Mayle 
271*9712c20fSFrederick Mayle     // Convert the input value (in_word) into a Unicode code point (unichar).
272*9712c20fSFrederick Mayle     uint32_t unichar;
273*9712c20fSFrederick Mayle     if (in_word >= 0xdc00 && in_word <= 0xdcff) {
274*9712c20fSFrederick Mayle       BPLOG(ERROR) << "UTF16ToUTF8 found low surrogate " <<
275*9712c20fSFrederick Mayle                       HexString(in_word) << " without high";
276*9712c20fSFrederick Mayle       return NULL;
277*9712c20fSFrederick Mayle     } else if (in_word >= 0xd800 && in_word <= 0xdbff) {
278*9712c20fSFrederick Mayle       // High surrogate.
279*9712c20fSFrederick Mayle       unichar = (in_word - 0xd7c0) << 10;
280*9712c20fSFrederick Mayle       if (++iterator == in.end()) {
281*9712c20fSFrederick Mayle         BPLOG(ERROR) << "UTF16ToUTF8 found high surrogate " <<
282*9712c20fSFrederick Mayle                         HexString(in_word) << " at end of string";
283*9712c20fSFrederick Mayle         return NULL;
284*9712c20fSFrederick Mayle       }
285*9712c20fSFrederick Mayle       uint32_t high_word = in_word;
286*9712c20fSFrederick Mayle       in_word = *iterator;
287*9712c20fSFrederick Mayle       if (in_word < 0xdc00 || in_word > 0xdcff) {
288*9712c20fSFrederick Mayle         BPLOG(ERROR) << "UTF16ToUTF8 found high surrogate " <<
289*9712c20fSFrederick Mayle                         HexString(high_word) << " without low " <<
290*9712c20fSFrederick Mayle                         HexString(in_word);
291*9712c20fSFrederick Mayle         return NULL;
292*9712c20fSFrederick Mayle       }
293*9712c20fSFrederick Mayle       unichar |= in_word & 0x03ff;
294*9712c20fSFrederick Mayle     } else {
295*9712c20fSFrederick Mayle       // The ordinary case, a single non-surrogate Unicode character encoded
296*9712c20fSFrederick Mayle       // as a single 16-bit value.
297*9712c20fSFrederick Mayle       unichar = in_word;
298*9712c20fSFrederick Mayle     }
299*9712c20fSFrederick Mayle 
300*9712c20fSFrederick Mayle     // Convert the Unicode code point (unichar) into its UTF-8 representation,
301*9712c20fSFrederick Mayle     // appending it to the out string.
302*9712c20fSFrederick Mayle     if (unichar < 0x80) {
303*9712c20fSFrederick Mayle       (*out) += static_cast<char>(unichar);
304*9712c20fSFrederick Mayle     } else if (unichar < 0x800) {
305*9712c20fSFrederick Mayle       (*out) += 0xc0 | static_cast<char>(unichar >> 6);
306*9712c20fSFrederick Mayle       (*out) += 0x80 | static_cast<char>(unichar & 0x3f);
307*9712c20fSFrederick Mayle     } else if (unichar < 0x10000) {
308*9712c20fSFrederick Mayle       (*out) += 0xe0 | static_cast<char>(unichar >> 12);
309*9712c20fSFrederick Mayle       (*out) += 0x80 | static_cast<char>((unichar >> 6) & 0x3f);
310*9712c20fSFrederick Mayle       (*out) += 0x80 | static_cast<char>(unichar & 0x3f);
311*9712c20fSFrederick Mayle     } else if (unichar < 0x200000) {
312*9712c20fSFrederick Mayle       (*out) += 0xf0 | static_cast<char>(unichar >> 18);
313*9712c20fSFrederick Mayle       (*out) += 0x80 | static_cast<char>((unichar >> 12) & 0x3f);
314*9712c20fSFrederick Mayle       (*out) += 0x80 | static_cast<char>((unichar >> 6) & 0x3f);
315*9712c20fSFrederick Mayle       (*out) += 0x80 | static_cast<char>(unichar & 0x3f);
316*9712c20fSFrederick Mayle     } else {
317*9712c20fSFrederick Mayle       BPLOG(ERROR) << "UTF16ToUTF8 cannot represent high value " <<
318*9712c20fSFrederick Mayle                       HexString(unichar) << " in UTF-8";
319*9712c20fSFrederick Mayle       return NULL;
320*9712c20fSFrederick Mayle     }
321*9712c20fSFrederick Mayle   }
322*9712c20fSFrederick Mayle 
323*9712c20fSFrederick Mayle   return out.release();
324*9712c20fSFrederick Mayle }
325*9712c20fSFrederick Mayle 
326*9712c20fSFrederick Mayle // Return the smaller of the number of code units in the UTF-16 string,
327*9712c20fSFrederick Mayle // not including the terminating null word, or maxlen.
UTF16codeunits(const uint16_t * string,size_t maxlen)328*9712c20fSFrederick Mayle size_t UTF16codeunits(const uint16_t* string, size_t maxlen) {
329*9712c20fSFrederick Mayle   size_t count = 0;
330*9712c20fSFrederick Mayle   while (count < maxlen && string[count] != 0)
331*9712c20fSFrederick Mayle     count++;
332*9712c20fSFrederick Mayle   return count;
333*9712c20fSFrederick Mayle }
334*9712c20fSFrederick Mayle 
Swap(MDTimeZoneInformation * time_zone)335*9712c20fSFrederick Mayle inline void Swap(MDTimeZoneInformation* time_zone) {
336*9712c20fSFrederick Mayle   Swap(&time_zone->bias);
337*9712c20fSFrederick Mayle   // Skip time_zone->standard_name.  No need to swap UTF-16 fields.
338*9712c20fSFrederick Mayle   // The swap will be done as part of the conversion to UTF-8.
339*9712c20fSFrederick Mayle   Swap(&time_zone->standard_date);
340*9712c20fSFrederick Mayle   Swap(&time_zone->standard_bias);
341*9712c20fSFrederick Mayle   // Skip time_zone->daylight_name.  No need to swap UTF-16 fields.
342*9712c20fSFrederick Mayle   // The swap will be done as part of the conversion to UTF-8.
343*9712c20fSFrederick Mayle   Swap(&time_zone->daylight_date);
344*9712c20fSFrederick Mayle   Swap(&time_zone->daylight_bias);
345*9712c20fSFrederick Mayle }
346*9712c20fSFrederick Mayle 
ConvertUTF16BufferToUTF8String(const uint16_t * utf16_data,size_t max_length_in_bytes,string * utf8_result,bool swap)347*9712c20fSFrederick Mayle void ConvertUTF16BufferToUTF8String(const uint16_t* utf16_data,
348*9712c20fSFrederick Mayle                                     size_t max_length_in_bytes,
349*9712c20fSFrederick Mayle                                     string* utf8_result,
350*9712c20fSFrederick Mayle                                     bool swap) {
351*9712c20fSFrederick Mayle   // Since there is no explicit byte length for each string, use
352*9712c20fSFrederick Mayle   // UTF16codeunits to calculate word length, then derive byte
353*9712c20fSFrederick Mayle   // length from that.
354*9712c20fSFrederick Mayle   size_t max_word_length = max_length_in_bytes / sizeof(utf16_data[0]);
355*9712c20fSFrederick Mayle   size_t word_length = UTF16codeunits(utf16_data, max_word_length);
356*9712c20fSFrederick Mayle   if (word_length > 0) {
357*9712c20fSFrederick Mayle     size_t byte_length = word_length * sizeof(utf16_data[0]);
358*9712c20fSFrederick Mayle     vector<uint16_t> utf16_vector(word_length);
359*9712c20fSFrederick Mayle     memcpy(&utf16_vector[0], &utf16_data[0], byte_length);
360*9712c20fSFrederick Mayle     scoped_ptr<string> temp(UTF16ToUTF8(utf16_vector, swap));
361*9712c20fSFrederick Mayle     if (temp.get()) {
362*9712c20fSFrederick Mayle       utf8_result->assign(*temp);
363*9712c20fSFrederick Mayle     }
364*9712c20fSFrederick Mayle   } else {
365*9712c20fSFrederick Mayle     utf8_result->clear();
366*9712c20fSFrederick Mayle   }
367*9712c20fSFrederick Mayle }
368*9712c20fSFrederick Mayle 
369*9712c20fSFrederick Mayle 
370*9712c20fSFrederick Mayle // For fields that may or may not be valid, PrintValueOrInvalid will print the
371*9712c20fSFrederick Mayle // string "(invalid)" if the field is not valid, and will print the value if
372*9712c20fSFrederick Mayle // the field is valid. The value is printed as hexadecimal or decimal.
373*9712c20fSFrederick Mayle 
374*9712c20fSFrederick Mayle enum NumberFormat {
375*9712c20fSFrederick Mayle   kNumberFormatDecimal,
376*9712c20fSFrederick Mayle   kNumberFormatHexadecimal,
377*9712c20fSFrederick Mayle };
378*9712c20fSFrederick Mayle 
PrintValueOrInvalid(bool valid,NumberFormat number_format,uint32_t value)379*9712c20fSFrederick Mayle void PrintValueOrInvalid(bool valid,
380*9712c20fSFrederick Mayle                          NumberFormat number_format,
381*9712c20fSFrederick Mayle                          uint32_t value) {
382*9712c20fSFrederick Mayle   if (!valid) {
383*9712c20fSFrederick Mayle     printf("(invalid)\n");
384*9712c20fSFrederick Mayle   } else if (number_format == kNumberFormatDecimal) {
385*9712c20fSFrederick Mayle     printf("%d\n", value);
386*9712c20fSFrederick Mayle   } else {
387*9712c20fSFrederick Mayle     printf("0x%x\n", value);
388*9712c20fSFrederick Mayle   }
389*9712c20fSFrederick Mayle }
390*9712c20fSFrederick Mayle 
391*9712c20fSFrederick Mayle // Converts a time_t to a string showing the time in UTC.
TimeTToUTCString(time_t tt)392*9712c20fSFrederick Mayle string TimeTToUTCString(time_t tt) {
393*9712c20fSFrederick Mayle   struct tm timestruct;
394*9712c20fSFrederick Mayle #ifdef _WIN32
395*9712c20fSFrederick Mayle   gmtime_s(&timestruct, &tt);
396*9712c20fSFrederick Mayle #else
397*9712c20fSFrederick Mayle   gmtime_r(&tt, &timestruct);
398*9712c20fSFrederick Mayle #endif
399*9712c20fSFrederick Mayle 
400*9712c20fSFrederick Mayle   char timestr[20];
401*9712c20fSFrederick Mayle   size_t rv = strftime(timestr, 20, "%Y-%m-%d %H:%M:%S", &timestruct);
402*9712c20fSFrederick Mayle   if (rv == 0) {
403*9712c20fSFrederick Mayle     return string();
404*9712c20fSFrederick Mayle   }
405*9712c20fSFrederick Mayle 
406*9712c20fSFrederick Mayle   return string(timestr);
407*9712c20fSFrederick Mayle }
408*9712c20fSFrederick Mayle 
MDGUIDToString(const MDGUID & uuid)409*9712c20fSFrederick Mayle string MDGUIDToString(const MDGUID& uuid) {
410*9712c20fSFrederick Mayle   char buf[37];
411*9712c20fSFrederick Mayle   snprintf(buf, sizeof(buf), "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
412*9712c20fSFrederick Mayle            uuid.data1,
413*9712c20fSFrederick Mayle            uuid.data2,
414*9712c20fSFrederick Mayle            uuid.data3,
415*9712c20fSFrederick Mayle            uuid.data4[0],
416*9712c20fSFrederick Mayle            uuid.data4[1],
417*9712c20fSFrederick Mayle            uuid.data4[2],
418*9712c20fSFrederick Mayle            uuid.data4[3],
419*9712c20fSFrederick Mayle            uuid.data4[4],
420*9712c20fSFrederick Mayle            uuid.data4[5],
421*9712c20fSFrederick Mayle            uuid.data4[6],
422*9712c20fSFrederick Mayle            uuid.data4[7]);
423*9712c20fSFrederick Mayle   return std::string(buf);
424*9712c20fSFrederick Mayle }
425*9712c20fSFrederick Mayle 
IsDevAshmem(const string & filename)426*9712c20fSFrederick Mayle bool IsDevAshmem(const string& filename) {
427*9712c20fSFrederick Mayle   const string kDevAshmem("/dev/ashmem/");
428*9712c20fSFrederick Mayle   return filename.compare(0, kDevAshmem.length(), kDevAshmem) == 0;
429*9712c20fSFrederick Mayle }
430*9712c20fSFrederick Mayle 
431*9712c20fSFrederick Mayle }  // namespace
432*9712c20fSFrederick Mayle 
433*9712c20fSFrederick Mayle //
434*9712c20fSFrederick Mayle // MinidumpObject
435*9712c20fSFrederick Mayle //
436*9712c20fSFrederick Mayle 
437*9712c20fSFrederick Mayle 
MinidumpObject(Minidump * minidump)438*9712c20fSFrederick Mayle MinidumpObject::MinidumpObject(Minidump* minidump)
439*9712c20fSFrederick Mayle     : DumpObject(),
440*9712c20fSFrederick Mayle       minidump_(minidump) {
441*9712c20fSFrederick Mayle }
442*9712c20fSFrederick Mayle 
443*9712c20fSFrederick Mayle 
444*9712c20fSFrederick Mayle //
445*9712c20fSFrederick Mayle // MinidumpStream
446*9712c20fSFrederick Mayle //
447*9712c20fSFrederick Mayle 
448*9712c20fSFrederick Mayle 
MinidumpStream(Minidump * minidump)449*9712c20fSFrederick Mayle MinidumpStream::MinidumpStream(Minidump* minidump)
450*9712c20fSFrederick Mayle     : MinidumpObject(minidump) {
451*9712c20fSFrederick Mayle }
452*9712c20fSFrederick Mayle 
453*9712c20fSFrederick Mayle 
454*9712c20fSFrederick Mayle //
455*9712c20fSFrederick Mayle // MinidumpContext
456*9712c20fSFrederick Mayle //
457*9712c20fSFrederick Mayle 
458*9712c20fSFrederick Mayle 
MinidumpContext(Minidump * minidump)459*9712c20fSFrederick Mayle MinidumpContext::MinidumpContext(Minidump* minidump)
460*9712c20fSFrederick Mayle     : DumpContext(),
461*9712c20fSFrederick Mayle       minidump_(minidump) {
462*9712c20fSFrederick Mayle }
463*9712c20fSFrederick Mayle 
~MinidumpContext()464*9712c20fSFrederick Mayle MinidumpContext::~MinidumpContext() {
465*9712c20fSFrederick Mayle }
466*9712c20fSFrederick Mayle 
Read(uint32_t expected_size)467*9712c20fSFrederick Mayle bool MinidumpContext::Read(uint32_t expected_size) {
468*9712c20fSFrederick Mayle   valid_ = false;
469*9712c20fSFrederick Mayle 
470*9712c20fSFrederick Mayle   // Certain raw context types are currently assumed to have unique sizes.
471*9712c20fSFrederick Mayle   if (!IsContextSizeUnique(sizeof(MDRawContextAMD64))) {
472*9712c20fSFrederick Mayle     BPLOG(ERROR) << "sizeof(MDRawContextAMD64) cannot match the size of any "
473*9712c20fSFrederick Mayle                  << "other raw context";
474*9712c20fSFrederick Mayle     return false;
475*9712c20fSFrederick Mayle   }
476*9712c20fSFrederick Mayle   if (!IsContextSizeUnique(sizeof(MDRawContextPPC64))) {
477*9712c20fSFrederick Mayle     BPLOG(ERROR) << "sizeof(MDRawContextPPC64) cannot match the size of any "
478*9712c20fSFrederick Mayle                  << "other raw context";
479*9712c20fSFrederick Mayle     return false;
480*9712c20fSFrederick Mayle   }
481*9712c20fSFrederick Mayle   if (!IsContextSizeUnique(sizeof(MDRawContextARM64_Old))) {
482*9712c20fSFrederick Mayle     BPLOG(ERROR) << "sizeof(MDRawContextARM64_Old) cannot match the size of any "
483*9712c20fSFrederick Mayle                  << "other raw context";
484*9712c20fSFrederick Mayle     return false;
485*9712c20fSFrederick Mayle   }
486*9712c20fSFrederick Mayle 
487*9712c20fSFrederick Mayle   FreeContext();
488*9712c20fSFrederick Mayle 
489*9712c20fSFrederick Mayle   // First, figure out what type of CPU this context structure is for.
490*9712c20fSFrederick Mayle   // For some reason, the AMD64 Context doesn't have context_flags
491*9712c20fSFrederick Mayle   // at the beginning of the structure, so special case it here.
492*9712c20fSFrederick Mayle 
493*9712c20fSFrederick Mayle   uint32_t sysinfo_cpu_type = 0;
494*9712c20fSFrederick Mayle   if (!minidump_->GetContextCPUFlagsFromSystemInfo(&sysinfo_cpu_type)) {
495*9712c20fSFrederick Mayle     BPLOG(ERROR) << "Failed to preserve the current stream position";
496*9712c20fSFrederick Mayle     return false;
497*9712c20fSFrederick Mayle   }
498*9712c20fSFrederick Mayle 
499*9712c20fSFrederick Mayle   if (expected_size == sizeof(MDRawContextAMD64) ||
500*9712c20fSFrederick Mayle       (sysinfo_cpu_type == MD_CONTEXT_AMD64 &&
501*9712c20fSFrederick Mayle        expected_size >= sizeof(MDRawContextAMD64))) {
502*9712c20fSFrederick Mayle     BPLOG(INFO) << "MinidumpContext: looks like AMD64 context";
503*9712c20fSFrederick Mayle 
504*9712c20fSFrederick Mayle     scoped_ptr<MDRawContextAMD64> context_amd64(new MDRawContextAMD64());
505*9712c20fSFrederick Mayle     if (!minidump_->ReadBytes(context_amd64.get(),
506*9712c20fSFrederick Mayle                               sizeof(MDRawContextAMD64))) {
507*9712c20fSFrederick Mayle       BPLOG(ERROR) << "MinidumpContext could not read amd64 context";
508*9712c20fSFrederick Mayle       return false;
509*9712c20fSFrederick Mayle     }
510*9712c20fSFrederick Mayle 
511*9712c20fSFrederick Mayle     // Context may include xsave registers and so be larger than
512*9712c20fSFrederick Mayle     // sizeof(MDRawContextAMD64). For now we skip this extended data.
513*9712c20fSFrederick Mayle     if (expected_size > sizeof(MDRawContextAMD64)) {
514*9712c20fSFrederick Mayle       size_t bytes_left = expected_size - sizeof(MDRawContextAMD64);
515*9712c20fSFrederick Mayle       if (bytes_left > kMaxXSaveAreaSize) {
516*9712c20fSFrederick Mayle         BPLOG(ERROR) << "MinidumpContext oversized xstate area";
517*9712c20fSFrederick Mayle         return false;
518*9712c20fSFrederick Mayle       }
519*9712c20fSFrederick Mayle       std::vector<uint8_t> xstate(bytes_left);
520*9712c20fSFrederick Mayle       if (!minidump_->ReadBytes(xstate.data(),
521*9712c20fSFrederick Mayle                                 bytes_left)) {
522*9712c20fSFrederick Mayle         BPLOG(ERROR) << "MinidumpContext could not skip amd64 xstate";
523*9712c20fSFrederick Mayle         return false;
524*9712c20fSFrederick Mayle       }
525*9712c20fSFrederick Mayle     }
526*9712c20fSFrederick Mayle 
527*9712c20fSFrederick Mayle     if (minidump_->swap())
528*9712c20fSFrederick Mayle       Swap(&context_amd64->context_flags);
529*9712c20fSFrederick Mayle 
530*9712c20fSFrederick Mayle     uint32_t cpu_type = context_amd64->context_flags & MD_CONTEXT_CPU_MASK;
531*9712c20fSFrederick Mayle     if (cpu_type == 0) {
532*9712c20fSFrederick Mayle       context_amd64->context_flags |= sysinfo_cpu_type;
533*9712c20fSFrederick Mayle     }
534*9712c20fSFrederick Mayle 
535*9712c20fSFrederick Mayle     if (cpu_type != MD_CONTEXT_AMD64) {
536*9712c20fSFrederick Mayle       // TODO: Fall through to switch below.
537*9712c20fSFrederick Mayle       // https://bugs.chromium.org/p/google-breakpad/issues/detail?id=550
538*9712c20fSFrederick Mayle       BPLOG(ERROR) << "MinidumpContext not actually amd64 context";
539*9712c20fSFrederick Mayle       return false;
540*9712c20fSFrederick Mayle     }
541*9712c20fSFrederick Mayle 
542*9712c20fSFrederick Mayle     // Do this after reading the entire MDRawContext structure because
543*9712c20fSFrederick Mayle     // GetSystemInfo may seek minidump to a new position.
544*9712c20fSFrederick Mayle     if (!CheckAgainstSystemInfo(cpu_type)) {
545*9712c20fSFrederick Mayle       BPLOG(ERROR) << "MinidumpContext amd64 does not match system info";
546*9712c20fSFrederick Mayle       return false;
547*9712c20fSFrederick Mayle     }
548*9712c20fSFrederick Mayle 
549*9712c20fSFrederick Mayle     // Normalize the 128-bit types in the dump.
550*9712c20fSFrederick Mayle     // Since this is AMD64, by definition, the values are little-endian.
551*9712c20fSFrederick Mayle     for (unsigned int vr_index = 0;
552*9712c20fSFrederick Mayle          vr_index < MD_CONTEXT_AMD64_VR_COUNT;
553*9712c20fSFrederick Mayle          ++vr_index)
554*9712c20fSFrederick Mayle       Normalize128(&context_amd64->vector_register[vr_index], false);
555*9712c20fSFrederick Mayle 
556*9712c20fSFrederick Mayle     if (minidump_->swap()) {
557*9712c20fSFrederick Mayle       Swap(&context_amd64->p1_home);
558*9712c20fSFrederick Mayle       Swap(&context_amd64->p2_home);
559*9712c20fSFrederick Mayle       Swap(&context_amd64->p3_home);
560*9712c20fSFrederick Mayle       Swap(&context_amd64->p4_home);
561*9712c20fSFrederick Mayle       Swap(&context_amd64->p5_home);
562*9712c20fSFrederick Mayle       Swap(&context_amd64->p6_home);
563*9712c20fSFrederick Mayle       // context_flags is already swapped
564*9712c20fSFrederick Mayle       Swap(&context_amd64->mx_csr);
565*9712c20fSFrederick Mayle       Swap(&context_amd64->cs);
566*9712c20fSFrederick Mayle       Swap(&context_amd64->ds);
567*9712c20fSFrederick Mayle       Swap(&context_amd64->es);
568*9712c20fSFrederick Mayle       Swap(&context_amd64->fs);
569*9712c20fSFrederick Mayle       Swap(&context_amd64->ss);
570*9712c20fSFrederick Mayle       Swap(&context_amd64->eflags);
571*9712c20fSFrederick Mayle       Swap(&context_amd64->dr0);
572*9712c20fSFrederick Mayle       Swap(&context_amd64->dr1);
573*9712c20fSFrederick Mayle       Swap(&context_amd64->dr2);
574*9712c20fSFrederick Mayle       Swap(&context_amd64->dr3);
575*9712c20fSFrederick Mayle       Swap(&context_amd64->dr6);
576*9712c20fSFrederick Mayle       Swap(&context_amd64->dr7);
577*9712c20fSFrederick Mayle       Swap(&context_amd64->rax);
578*9712c20fSFrederick Mayle       Swap(&context_amd64->rcx);
579*9712c20fSFrederick Mayle       Swap(&context_amd64->rdx);
580*9712c20fSFrederick Mayle       Swap(&context_amd64->rbx);
581*9712c20fSFrederick Mayle       Swap(&context_amd64->rsp);
582*9712c20fSFrederick Mayle       Swap(&context_amd64->rbp);
583*9712c20fSFrederick Mayle       Swap(&context_amd64->rsi);
584*9712c20fSFrederick Mayle       Swap(&context_amd64->rdi);
585*9712c20fSFrederick Mayle       Swap(&context_amd64->r8);
586*9712c20fSFrederick Mayle       Swap(&context_amd64->r9);
587*9712c20fSFrederick Mayle       Swap(&context_amd64->r10);
588*9712c20fSFrederick Mayle       Swap(&context_amd64->r11);
589*9712c20fSFrederick Mayle       Swap(&context_amd64->r12);
590*9712c20fSFrederick Mayle       Swap(&context_amd64->r13);
591*9712c20fSFrederick Mayle       Swap(&context_amd64->r14);
592*9712c20fSFrederick Mayle       Swap(&context_amd64->r15);
593*9712c20fSFrederick Mayle       Swap(&context_amd64->rip);
594*9712c20fSFrederick Mayle       // FIXME: I'm not sure what actually determines
595*9712c20fSFrederick Mayle       // which member of the union {flt_save, sse_registers}
596*9712c20fSFrederick Mayle       // is valid.  We're not currently using either,
597*9712c20fSFrederick Mayle       // but it would be good to have them swapped properly.
598*9712c20fSFrederick Mayle 
599*9712c20fSFrederick Mayle       for (unsigned int vr_index = 0;
600*9712c20fSFrederick Mayle            vr_index < MD_CONTEXT_AMD64_VR_COUNT;
601*9712c20fSFrederick Mayle            ++vr_index)
602*9712c20fSFrederick Mayle         Swap(&context_amd64->vector_register[vr_index]);
603*9712c20fSFrederick Mayle       Swap(&context_amd64->vector_control);
604*9712c20fSFrederick Mayle       Swap(&context_amd64->debug_control);
605*9712c20fSFrederick Mayle       Swap(&context_amd64->last_branch_to_rip);
606*9712c20fSFrederick Mayle       Swap(&context_amd64->last_branch_from_rip);
607*9712c20fSFrederick Mayle       Swap(&context_amd64->last_exception_to_rip);
608*9712c20fSFrederick Mayle       Swap(&context_amd64->last_exception_from_rip);
609*9712c20fSFrederick Mayle     }
610*9712c20fSFrederick Mayle 
611*9712c20fSFrederick Mayle     SetContextFlags(context_amd64->context_flags);
612*9712c20fSFrederick Mayle 
613*9712c20fSFrederick Mayle     SetContextAMD64(context_amd64.release());
614*9712c20fSFrederick Mayle   } else if (expected_size == sizeof(MDRawContextPPC64)) {
615*9712c20fSFrederick Mayle     // |context_flags| of MDRawContextPPC64 is 64 bits, but other MDRawContext
616*9712c20fSFrederick Mayle     // in the else case have 32 bits |context_flags|, so special case it here.
617*9712c20fSFrederick Mayle     uint64_t context_flags;
618*9712c20fSFrederick Mayle     if (!minidump_->ReadBytes(&context_flags, sizeof(context_flags))) {
619*9712c20fSFrederick Mayle       BPLOG(ERROR) << "MinidumpContext could not read context flags";
620*9712c20fSFrederick Mayle       return false;
621*9712c20fSFrederick Mayle     }
622*9712c20fSFrederick Mayle     if (minidump_->swap())
623*9712c20fSFrederick Mayle       Swap(&context_flags);
624*9712c20fSFrederick Mayle 
625*9712c20fSFrederick Mayle     uint32_t cpu_type = context_flags & MD_CONTEXT_CPU_MASK;
626*9712c20fSFrederick Mayle     scoped_ptr<MDRawContextPPC64> context_ppc64(new MDRawContextPPC64());
627*9712c20fSFrederick Mayle 
628*9712c20fSFrederick Mayle     if (cpu_type == 0) {
629*9712c20fSFrederick Mayle       if (minidump_->GetContextCPUFlagsFromSystemInfo(&cpu_type)) {
630*9712c20fSFrederick Mayle         context_ppc64->context_flags |= cpu_type;
631*9712c20fSFrederick Mayle       } else {
632*9712c20fSFrederick Mayle         BPLOG(ERROR) << "Failed to preserve the current stream position";
633*9712c20fSFrederick Mayle         return false;
634*9712c20fSFrederick Mayle       }
635*9712c20fSFrederick Mayle     }
636*9712c20fSFrederick Mayle 
637*9712c20fSFrederick Mayle     if (cpu_type != MD_CONTEXT_PPC64) {
638*9712c20fSFrederick Mayle       // TODO: Fall through to switch below.
639*9712c20fSFrederick Mayle       // https://bugs.chromium.org/p/google-breakpad/issues/detail?id=550
640*9712c20fSFrederick Mayle       BPLOG(ERROR) << "MinidumpContext not actually ppc64 context";
641*9712c20fSFrederick Mayle       return false;
642*9712c20fSFrederick Mayle     }
643*9712c20fSFrederick Mayle 
644*9712c20fSFrederick Mayle     // Set the context_flags member, which has already been read, and
645*9712c20fSFrederick Mayle     // read the rest of the structure beginning with the first member
646*9712c20fSFrederick Mayle     // after context_flags.
647*9712c20fSFrederick Mayle     context_ppc64->context_flags = context_flags;
648*9712c20fSFrederick Mayle 
649*9712c20fSFrederick Mayle     size_t flags_size = sizeof(context_ppc64->context_flags);
650*9712c20fSFrederick Mayle     uint8_t* context_after_flags =
651*9712c20fSFrederick Mayle           reinterpret_cast<uint8_t*>(context_ppc64.get()) + flags_size;
652*9712c20fSFrederick Mayle     if (!minidump_->ReadBytes(context_after_flags,
653*9712c20fSFrederick Mayle                               sizeof(MDRawContextPPC64) - flags_size)) {
654*9712c20fSFrederick Mayle       BPLOG(ERROR) << "MinidumpContext could not read ppc64 context";
655*9712c20fSFrederick Mayle       return false;
656*9712c20fSFrederick Mayle     }
657*9712c20fSFrederick Mayle 
658*9712c20fSFrederick Mayle     // Do this after reading the entire MDRawContext structure because
659*9712c20fSFrederick Mayle     // GetSystemInfo may seek minidump to a new position.
660*9712c20fSFrederick Mayle     if (!CheckAgainstSystemInfo(cpu_type)) {
661*9712c20fSFrederick Mayle       BPLOG(ERROR) << "MinidumpContext ppc64 does not match system info";
662*9712c20fSFrederick Mayle       return false;
663*9712c20fSFrederick Mayle     }
664*9712c20fSFrederick Mayle     if (minidump_->swap()) {
665*9712c20fSFrederick Mayle       // context_ppc64->context_flags was already swapped.
666*9712c20fSFrederick Mayle       Swap(&context_ppc64->srr0);
667*9712c20fSFrederick Mayle       Swap(&context_ppc64->srr1);
668*9712c20fSFrederick Mayle       for (unsigned int gpr_index = 0;
669*9712c20fSFrederick Mayle            gpr_index < MD_CONTEXT_PPC64_GPR_COUNT;
670*9712c20fSFrederick Mayle            ++gpr_index) {
671*9712c20fSFrederick Mayle         Swap(&context_ppc64->gpr[gpr_index]);
672*9712c20fSFrederick Mayle       }
673*9712c20fSFrederick Mayle       Swap(&context_ppc64->cr);
674*9712c20fSFrederick Mayle       Swap(&context_ppc64->xer);
675*9712c20fSFrederick Mayle       Swap(&context_ppc64->lr);
676*9712c20fSFrederick Mayle       Swap(&context_ppc64->ctr);
677*9712c20fSFrederick Mayle       Swap(&context_ppc64->vrsave);
678*9712c20fSFrederick Mayle       for (unsigned int fpr_index = 0;
679*9712c20fSFrederick Mayle            fpr_index < MD_FLOATINGSAVEAREA_PPC_FPR_COUNT;
680*9712c20fSFrederick Mayle            ++fpr_index) {
681*9712c20fSFrederick Mayle         Swap(&context_ppc64->float_save.fpregs[fpr_index]);
682*9712c20fSFrederick Mayle       }
683*9712c20fSFrederick Mayle       // Don't swap context_ppc64->float_save.fpscr_pad because it is only
684*9712c20fSFrederick Mayle       // used for padding.
685*9712c20fSFrederick Mayle       Swap(&context_ppc64->float_save.fpscr);
686*9712c20fSFrederick Mayle       for (unsigned int vr_index = 0;
687*9712c20fSFrederick Mayle            vr_index < MD_VECTORSAVEAREA_PPC_VR_COUNT;
688*9712c20fSFrederick Mayle            ++vr_index) {
689*9712c20fSFrederick Mayle         Normalize128(&context_ppc64->vector_save.save_vr[vr_index], true);
690*9712c20fSFrederick Mayle         Swap(&context_ppc64->vector_save.save_vr[vr_index]);
691*9712c20fSFrederick Mayle       }
692*9712c20fSFrederick Mayle       Swap(&context_ppc64->vector_save.save_vscr);
693*9712c20fSFrederick Mayle       // Don't swap the padding fields in vector_save.
694*9712c20fSFrederick Mayle       Swap(&context_ppc64->vector_save.save_vrvalid);
695*9712c20fSFrederick Mayle     }
696*9712c20fSFrederick Mayle 
697*9712c20fSFrederick Mayle     SetContextFlags(static_cast<uint32_t>(context_ppc64->context_flags));
698*9712c20fSFrederick Mayle 
699*9712c20fSFrederick Mayle     // Check for data loss when converting context flags from uint64_t into
700*9712c20fSFrederick Mayle     // uint32_t
701*9712c20fSFrederick Mayle     if (static_cast<uint64_t>(GetContextFlags()) !=
702*9712c20fSFrederick Mayle         context_ppc64->context_flags) {
703*9712c20fSFrederick Mayle       BPLOG(ERROR) << "Data loss detected when converting PPC64 context_flags";
704*9712c20fSFrederick Mayle       return false;
705*9712c20fSFrederick Mayle     }
706*9712c20fSFrederick Mayle 
707*9712c20fSFrederick Mayle     SetContextPPC64(context_ppc64.release());
708*9712c20fSFrederick Mayle   } else if (expected_size == sizeof(MDRawContextARM64_Old)) {
709*9712c20fSFrederick Mayle     // |context_flags| of MDRawContextARM64_Old is 64 bits, but other MDRawContext
710*9712c20fSFrederick Mayle     // in the else case have 32 bits |context_flags|, so special case it here.
711*9712c20fSFrederick Mayle     uint64_t context_flags;
712*9712c20fSFrederick Mayle 
713*9712c20fSFrederick Mayle     BPLOG(INFO) << "MinidumpContext: looks like ARM64 context";
714*9712c20fSFrederick Mayle 
715*9712c20fSFrederick Mayle     if (!minidump_->ReadBytes(&context_flags, sizeof(context_flags))) {
716*9712c20fSFrederick Mayle       BPLOG(ERROR) << "MinidumpContext could not read context flags";
717*9712c20fSFrederick Mayle       return false;
718*9712c20fSFrederick Mayle     }
719*9712c20fSFrederick Mayle     if (minidump_->swap())
720*9712c20fSFrederick Mayle       Swap(&context_flags);
721*9712c20fSFrederick Mayle 
722*9712c20fSFrederick Mayle     scoped_ptr<MDRawContextARM64_Old> context_arm64(new MDRawContextARM64_Old());
723*9712c20fSFrederick Mayle 
724*9712c20fSFrederick Mayle     uint32_t cpu_type = context_flags & MD_CONTEXT_CPU_MASK;
725*9712c20fSFrederick Mayle     if (cpu_type == 0) {
726*9712c20fSFrederick Mayle       if (minidump_->GetContextCPUFlagsFromSystemInfo(&cpu_type)) {
727*9712c20fSFrederick Mayle         context_arm64->context_flags |= cpu_type;
728*9712c20fSFrederick Mayle       } else {
729*9712c20fSFrederick Mayle         BPLOG(ERROR) << "Failed to preserve the current stream position";
730*9712c20fSFrederick Mayle         return false;
731*9712c20fSFrederick Mayle       }
732*9712c20fSFrederick Mayle     }
733*9712c20fSFrederick Mayle 
734*9712c20fSFrederick Mayle     if (cpu_type != MD_CONTEXT_ARM64_OLD) {
735*9712c20fSFrederick Mayle       // TODO: Fall through to switch below.
736*9712c20fSFrederick Mayle       // https://bugs.chromium.org/p/google-breakpad/issues/detail?id=550
737*9712c20fSFrederick Mayle       BPLOG(ERROR) << "MinidumpContext not actually arm64 context";
738*9712c20fSFrederick Mayle       return false;
739*9712c20fSFrederick Mayle     }
740*9712c20fSFrederick Mayle 
741*9712c20fSFrederick Mayle     // Set the context_flags member, which has already been read, and
742*9712c20fSFrederick Mayle     // read the rest of the structure beginning with the first member
743*9712c20fSFrederick Mayle     // after context_flags.
744*9712c20fSFrederick Mayle     context_arm64->context_flags = context_flags;
745*9712c20fSFrederick Mayle 
746*9712c20fSFrederick Mayle     size_t flags_size = sizeof(context_arm64->context_flags);
747*9712c20fSFrederick Mayle     uint8_t* context_after_flags =
748*9712c20fSFrederick Mayle         reinterpret_cast<uint8_t*>(context_arm64.get()) + flags_size;
749*9712c20fSFrederick Mayle     if (!minidump_->ReadBytes(context_after_flags,
750*9712c20fSFrederick Mayle                               sizeof(MDRawContextARM64_Old) - flags_size)) {
751*9712c20fSFrederick Mayle       BPLOG(ERROR) << "MinidumpContext could not read arm64 context";
752*9712c20fSFrederick Mayle       return false;
753*9712c20fSFrederick Mayle     }
754*9712c20fSFrederick Mayle 
755*9712c20fSFrederick Mayle     // Do this after reading the entire MDRawContext structure because
756*9712c20fSFrederick Mayle     // GetSystemInfo may seek minidump to a new position.
757*9712c20fSFrederick Mayle     if (!CheckAgainstSystemInfo(cpu_type)) {
758*9712c20fSFrederick Mayle       BPLOG(ERROR) << "MinidumpContext arm64 does not match system info";
759*9712c20fSFrederick Mayle       return false;
760*9712c20fSFrederick Mayle     }
761*9712c20fSFrederick Mayle 
762*9712c20fSFrederick Mayle     if (minidump_->swap()) {
763*9712c20fSFrederick Mayle       // context_arm64->context_flags was already swapped.
764*9712c20fSFrederick Mayle       for (unsigned int ireg_index = 0;
765*9712c20fSFrederick Mayle            ireg_index < MD_CONTEXT_ARM64_GPR_COUNT;
766*9712c20fSFrederick Mayle            ++ireg_index) {
767*9712c20fSFrederick Mayle         Swap(&context_arm64->iregs[ireg_index]);
768*9712c20fSFrederick Mayle       }
769*9712c20fSFrederick Mayle       Swap(&context_arm64->cpsr);
770*9712c20fSFrederick Mayle       Swap(&context_arm64->float_save.fpsr);
771*9712c20fSFrederick Mayle       Swap(&context_arm64->float_save.fpcr);
772*9712c20fSFrederick Mayle       for (unsigned int fpr_index = 0;
773*9712c20fSFrederick Mayle            fpr_index < MD_FLOATINGSAVEAREA_ARM64_FPR_COUNT;
774*9712c20fSFrederick Mayle            ++fpr_index) {
775*9712c20fSFrederick Mayle         Normalize128(&context_arm64->float_save.regs[fpr_index],
776*9712c20fSFrederick Mayle                      minidump_->is_big_endian());
777*9712c20fSFrederick Mayle         Swap(&context_arm64->float_save.regs[fpr_index]);
778*9712c20fSFrederick Mayle       }
779*9712c20fSFrederick Mayle     }
780*9712c20fSFrederick Mayle 
781*9712c20fSFrederick Mayle     scoped_ptr<MDRawContextARM64> new_context(new MDRawContextARM64());
782*9712c20fSFrederick Mayle     ConvertOldARM64Context(*context_arm64.get(), new_context.get());
783*9712c20fSFrederick Mayle     SetContextFlags(new_context->context_flags);
784*9712c20fSFrederick Mayle     SetContextARM64(new_context.release());
785*9712c20fSFrederick Mayle   } else {
786*9712c20fSFrederick Mayle     uint32_t context_flags;
787*9712c20fSFrederick Mayle     if (!minidump_->ReadBytes(&context_flags, sizeof(context_flags))) {
788*9712c20fSFrederick Mayle       BPLOG(ERROR) << "MinidumpContext could not read context flags";
789*9712c20fSFrederick Mayle       return false;
790*9712c20fSFrederick Mayle     }
791*9712c20fSFrederick Mayle     if (minidump_->swap())
792*9712c20fSFrederick Mayle       Swap(&context_flags);
793*9712c20fSFrederick Mayle 
794*9712c20fSFrederick Mayle     uint32_t cpu_type = context_flags & MD_CONTEXT_CPU_MASK;
795*9712c20fSFrederick Mayle     if (cpu_type == 0) {
796*9712c20fSFrederick Mayle       // Unfortunately the flag for MD_CONTEXT_ARM that was taken
797*9712c20fSFrederick Mayle       // from a Windows CE SDK header conflicts in practice with
798*9712c20fSFrederick Mayle       // the CONTEXT_XSTATE flag. MD_CONTEXT_ARM has been renumbered,
799*9712c20fSFrederick Mayle       // but handle dumps with the legacy value gracefully here.
800*9712c20fSFrederick Mayle       if (context_flags & MD_CONTEXT_ARM_OLD) {
801*9712c20fSFrederick Mayle         context_flags |= MD_CONTEXT_ARM;
802*9712c20fSFrederick Mayle         context_flags &= ~MD_CONTEXT_ARM_OLD;
803*9712c20fSFrederick Mayle         cpu_type = MD_CONTEXT_ARM;
804*9712c20fSFrederick Mayle       }
805*9712c20fSFrederick Mayle     }
806*9712c20fSFrederick Mayle 
807*9712c20fSFrederick Mayle     // Fixup if we were not provided a cpu type.
808*9712c20fSFrederick Mayle     if (cpu_type == 0) {
809*9712c20fSFrederick Mayle       cpu_type = sysinfo_cpu_type;
810*9712c20fSFrederick Mayle       context_flags |= cpu_type;
811*9712c20fSFrederick Mayle     }
812*9712c20fSFrederick Mayle 
813*9712c20fSFrederick Mayle     // Allocate the context structure for the correct CPU and fill it.  The
814*9712c20fSFrederick Mayle     // casts are slightly unorthodox, but it seems better to do that than to
815*9712c20fSFrederick Mayle     // maintain a separate pointer for each type of CPU context structure
816*9712c20fSFrederick Mayle     // when only one of them will be used.
817*9712c20fSFrederick Mayle     switch (cpu_type) {
818*9712c20fSFrederick Mayle       case MD_CONTEXT_X86: {
819*9712c20fSFrederick Mayle         if (expected_size != sizeof(MDRawContextX86)) {
820*9712c20fSFrederick Mayle           BPLOG(ERROR) << "MinidumpContext x86 size mismatch, " <<
821*9712c20fSFrederick Mayle             expected_size << " != " << sizeof(MDRawContextX86);
822*9712c20fSFrederick Mayle           return false;
823*9712c20fSFrederick Mayle         }
824*9712c20fSFrederick Mayle 
825*9712c20fSFrederick Mayle         scoped_ptr<MDRawContextX86> context_x86(new MDRawContextX86());
826*9712c20fSFrederick Mayle 
827*9712c20fSFrederick Mayle         // Set the context_flags member, which has already been read, and
828*9712c20fSFrederick Mayle         // read the rest of the structure beginning with the first member
829*9712c20fSFrederick Mayle         // after context_flags.
830*9712c20fSFrederick Mayle         context_x86->context_flags = context_flags;
831*9712c20fSFrederick Mayle 
832*9712c20fSFrederick Mayle         size_t flags_size = sizeof(context_x86->context_flags);
833*9712c20fSFrederick Mayle         uint8_t* context_after_flags =
834*9712c20fSFrederick Mayle           reinterpret_cast<uint8_t*>(context_x86.get()) + flags_size;
835*9712c20fSFrederick Mayle         if (!minidump_->ReadBytes(context_after_flags,
836*9712c20fSFrederick Mayle                                   sizeof(MDRawContextX86) - flags_size)) {
837*9712c20fSFrederick Mayle           BPLOG(ERROR) << "MinidumpContext could not read x86 context";
838*9712c20fSFrederick Mayle           return false;
839*9712c20fSFrederick Mayle         }
840*9712c20fSFrederick Mayle 
841*9712c20fSFrederick Mayle         // Do this after reading the entire MDRawContext structure because
842*9712c20fSFrederick Mayle         // GetSystemInfo may seek minidump to a new position.
843*9712c20fSFrederick Mayle         if (!CheckAgainstSystemInfo(cpu_type)) {
844*9712c20fSFrederick Mayle           BPLOG(ERROR) << "MinidumpContext x86 does not match system info";
845*9712c20fSFrederick Mayle           return false;
846*9712c20fSFrederick Mayle         }
847*9712c20fSFrederick Mayle 
848*9712c20fSFrederick Mayle         if (minidump_->swap()) {
849*9712c20fSFrederick Mayle           // context_x86->context_flags was already swapped.
850*9712c20fSFrederick Mayle           Swap(&context_x86->dr0);
851*9712c20fSFrederick Mayle           Swap(&context_x86->dr1);
852*9712c20fSFrederick Mayle           Swap(&context_x86->dr2);
853*9712c20fSFrederick Mayle           Swap(&context_x86->dr3);
854*9712c20fSFrederick Mayle           Swap(&context_x86->dr6);
855*9712c20fSFrederick Mayle           Swap(&context_x86->dr7);
856*9712c20fSFrederick Mayle           Swap(&context_x86->float_save.control_word);
857*9712c20fSFrederick Mayle           Swap(&context_x86->float_save.status_word);
858*9712c20fSFrederick Mayle           Swap(&context_x86->float_save.tag_word);
859*9712c20fSFrederick Mayle           Swap(&context_x86->float_save.error_offset);
860*9712c20fSFrederick Mayle           Swap(&context_x86->float_save.error_selector);
861*9712c20fSFrederick Mayle           Swap(&context_x86->float_save.data_offset);
862*9712c20fSFrederick Mayle           Swap(&context_x86->float_save.data_selector);
863*9712c20fSFrederick Mayle           // context_x86->float_save.register_area[] contains 8-bit quantities
864*9712c20fSFrederick Mayle           // and does not need to be swapped.
865*9712c20fSFrederick Mayle           Swap(&context_x86->float_save.cr0_npx_state);
866*9712c20fSFrederick Mayle           Swap(&context_x86->gs);
867*9712c20fSFrederick Mayle           Swap(&context_x86->fs);
868*9712c20fSFrederick Mayle           Swap(&context_x86->es);
869*9712c20fSFrederick Mayle           Swap(&context_x86->ds);
870*9712c20fSFrederick Mayle           Swap(&context_x86->edi);
871*9712c20fSFrederick Mayle           Swap(&context_x86->esi);
872*9712c20fSFrederick Mayle           Swap(&context_x86->ebx);
873*9712c20fSFrederick Mayle           Swap(&context_x86->edx);
874*9712c20fSFrederick Mayle           Swap(&context_x86->ecx);
875*9712c20fSFrederick Mayle           Swap(&context_x86->eax);
876*9712c20fSFrederick Mayle           Swap(&context_x86->ebp);
877*9712c20fSFrederick Mayle           Swap(&context_x86->eip);
878*9712c20fSFrederick Mayle           Swap(&context_x86->cs);
879*9712c20fSFrederick Mayle           Swap(&context_x86->eflags);
880*9712c20fSFrederick Mayle           Swap(&context_x86->esp);
881*9712c20fSFrederick Mayle           Swap(&context_x86->ss);
882*9712c20fSFrederick Mayle           // context_x86->extended_registers[] contains 8-bit quantities and
883*9712c20fSFrederick Mayle           // does not need to be swapped.
884*9712c20fSFrederick Mayle         }
885*9712c20fSFrederick Mayle 
886*9712c20fSFrederick Mayle         SetContextX86(context_x86.release());
887*9712c20fSFrederick Mayle 
888*9712c20fSFrederick Mayle         break;
889*9712c20fSFrederick Mayle       }
890*9712c20fSFrederick Mayle 
891*9712c20fSFrederick Mayle       case MD_CONTEXT_PPC: {
892*9712c20fSFrederick Mayle         if (expected_size != sizeof(MDRawContextPPC)) {
893*9712c20fSFrederick Mayle           BPLOG(ERROR) << "MinidumpContext ppc size mismatch, " <<
894*9712c20fSFrederick Mayle             expected_size << " != " << sizeof(MDRawContextPPC);
895*9712c20fSFrederick Mayle           return false;
896*9712c20fSFrederick Mayle         }
897*9712c20fSFrederick Mayle 
898*9712c20fSFrederick Mayle         scoped_ptr<MDRawContextPPC> context_ppc(new MDRawContextPPC());
899*9712c20fSFrederick Mayle 
900*9712c20fSFrederick Mayle         // Set the context_flags member, which has already been read, and
901*9712c20fSFrederick Mayle         // read the rest of the structure beginning with the first member
902*9712c20fSFrederick Mayle         // after context_flags.
903*9712c20fSFrederick Mayle         context_ppc->context_flags = context_flags;
904*9712c20fSFrederick Mayle 
905*9712c20fSFrederick Mayle         size_t flags_size = sizeof(context_ppc->context_flags);
906*9712c20fSFrederick Mayle         uint8_t* context_after_flags =
907*9712c20fSFrederick Mayle           reinterpret_cast<uint8_t*>(context_ppc.get()) + flags_size;
908*9712c20fSFrederick Mayle         if (!minidump_->ReadBytes(context_after_flags,
909*9712c20fSFrederick Mayle                                   sizeof(MDRawContextPPC) - flags_size)) {
910*9712c20fSFrederick Mayle           BPLOG(ERROR) << "MinidumpContext could not read ppc context";
911*9712c20fSFrederick Mayle           return false;
912*9712c20fSFrederick Mayle         }
913*9712c20fSFrederick Mayle 
914*9712c20fSFrederick Mayle         // Do this after reading the entire MDRawContext structure because
915*9712c20fSFrederick Mayle         // GetSystemInfo may seek minidump to a new position.
916*9712c20fSFrederick Mayle         if (!CheckAgainstSystemInfo(cpu_type)) {
917*9712c20fSFrederick Mayle           BPLOG(ERROR) << "MinidumpContext ppc does not match system info";
918*9712c20fSFrederick Mayle           return false;
919*9712c20fSFrederick Mayle         }
920*9712c20fSFrederick Mayle 
921*9712c20fSFrederick Mayle         // Normalize the 128-bit types in the dump.
922*9712c20fSFrederick Mayle         // Since this is PowerPC, by definition, the values are big-endian.
923*9712c20fSFrederick Mayle         for (unsigned int vr_index = 0;
924*9712c20fSFrederick Mayle              vr_index < MD_VECTORSAVEAREA_PPC_VR_COUNT;
925*9712c20fSFrederick Mayle              ++vr_index) {
926*9712c20fSFrederick Mayle           Normalize128(&context_ppc->vector_save.save_vr[vr_index], true);
927*9712c20fSFrederick Mayle         }
928*9712c20fSFrederick Mayle 
929*9712c20fSFrederick Mayle         if (minidump_->swap()) {
930*9712c20fSFrederick Mayle           // context_ppc->context_flags was already swapped.
931*9712c20fSFrederick Mayle           Swap(&context_ppc->srr0);
932*9712c20fSFrederick Mayle           Swap(&context_ppc->srr1);
933*9712c20fSFrederick Mayle           for (unsigned int gpr_index = 0;
934*9712c20fSFrederick Mayle                gpr_index < MD_CONTEXT_PPC_GPR_COUNT;
935*9712c20fSFrederick Mayle                ++gpr_index) {
936*9712c20fSFrederick Mayle             Swap(&context_ppc->gpr[gpr_index]);
937*9712c20fSFrederick Mayle           }
938*9712c20fSFrederick Mayle           Swap(&context_ppc->cr);
939*9712c20fSFrederick Mayle           Swap(&context_ppc->xer);
940*9712c20fSFrederick Mayle           Swap(&context_ppc->lr);
941*9712c20fSFrederick Mayle           Swap(&context_ppc->ctr);
942*9712c20fSFrederick Mayle           Swap(&context_ppc->mq);
943*9712c20fSFrederick Mayle           Swap(&context_ppc->vrsave);
944*9712c20fSFrederick Mayle           for (unsigned int fpr_index = 0;
945*9712c20fSFrederick Mayle                fpr_index < MD_FLOATINGSAVEAREA_PPC_FPR_COUNT;
946*9712c20fSFrederick Mayle                ++fpr_index) {
947*9712c20fSFrederick Mayle             Swap(&context_ppc->float_save.fpregs[fpr_index]);
948*9712c20fSFrederick Mayle           }
949*9712c20fSFrederick Mayle           // Don't swap context_ppc->float_save.fpscr_pad because it is only
950*9712c20fSFrederick Mayle           // used for padding.
951*9712c20fSFrederick Mayle           Swap(&context_ppc->float_save.fpscr);
952*9712c20fSFrederick Mayle           for (unsigned int vr_index = 0;
953*9712c20fSFrederick Mayle                vr_index < MD_VECTORSAVEAREA_PPC_VR_COUNT;
954*9712c20fSFrederick Mayle                ++vr_index) {
955*9712c20fSFrederick Mayle             Swap(&context_ppc->vector_save.save_vr[vr_index]);
956*9712c20fSFrederick Mayle           }
957*9712c20fSFrederick Mayle           Swap(&context_ppc->vector_save.save_vscr);
958*9712c20fSFrederick Mayle           // Don't swap the padding fields in vector_save.
959*9712c20fSFrederick Mayle           Swap(&context_ppc->vector_save.save_vrvalid);
960*9712c20fSFrederick Mayle         }
961*9712c20fSFrederick Mayle 
962*9712c20fSFrederick Mayle         SetContextPPC(context_ppc.release());
963*9712c20fSFrederick Mayle 
964*9712c20fSFrederick Mayle         break;
965*9712c20fSFrederick Mayle       }
966*9712c20fSFrederick Mayle 
967*9712c20fSFrederick Mayle       case MD_CONTEXT_SPARC: {
968*9712c20fSFrederick Mayle         if (expected_size != sizeof(MDRawContextSPARC)) {
969*9712c20fSFrederick Mayle           BPLOG(ERROR) << "MinidumpContext sparc size mismatch, " <<
970*9712c20fSFrederick Mayle             expected_size << " != " << sizeof(MDRawContextSPARC);
971*9712c20fSFrederick Mayle           return false;
972*9712c20fSFrederick Mayle         }
973*9712c20fSFrederick Mayle 
974*9712c20fSFrederick Mayle         scoped_ptr<MDRawContextSPARC> context_sparc(new MDRawContextSPARC());
975*9712c20fSFrederick Mayle 
976*9712c20fSFrederick Mayle         // Set the context_flags member, which has already been read, and
977*9712c20fSFrederick Mayle         // read the rest of the structure beginning with the first member
978*9712c20fSFrederick Mayle         // after context_flags.
979*9712c20fSFrederick Mayle         context_sparc->context_flags = context_flags;
980*9712c20fSFrederick Mayle 
981*9712c20fSFrederick Mayle         size_t flags_size = sizeof(context_sparc->context_flags);
982*9712c20fSFrederick Mayle         uint8_t* context_after_flags =
983*9712c20fSFrederick Mayle             reinterpret_cast<uint8_t*>(context_sparc.get()) + flags_size;
984*9712c20fSFrederick Mayle         if (!minidump_->ReadBytes(context_after_flags,
985*9712c20fSFrederick Mayle                                   sizeof(MDRawContextSPARC) - flags_size)) {
986*9712c20fSFrederick Mayle           BPLOG(ERROR) << "MinidumpContext could not read sparc context";
987*9712c20fSFrederick Mayle           return false;
988*9712c20fSFrederick Mayle         }
989*9712c20fSFrederick Mayle 
990*9712c20fSFrederick Mayle         // Do this after reading the entire MDRawContext structure because
991*9712c20fSFrederick Mayle         // GetSystemInfo may seek minidump to a new position.
992*9712c20fSFrederick Mayle         if (!CheckAgainstSystemInfo(cpu_type)) {
993*9712c20fSFrederick Mayle           BPLOG(ERROR) << "MinidumpContext sparc does not match system info";
994*9712c20fSFrederick Mayle           return false;
995*9712c20fSFrederick Mayle         }
996*9712c20fSFrederick Mayle 
997*9712c20fSFrederick Mayle         if (minidump_->swap()) {
998*9712c20fSFrederick Mayle           // context_sparc->context_flags was already swapped.
999*9712c20fSFrederick Mayle           for (unsigned int gpr_index = 0;
1000*9712c20fSFrederick Mayle                gpr_index < MD_CONTEXT_SPARC_GPR_COUNT;
1001*9712c20fSFrederick Mayle                ++gpr_index) {
1002*9712c20fSFrederick Mayle             Swap(&context_sparc->g_r[gpr_index]);
1003*9712c20fSFrederick Mayle           }
1004*9712c20fSFrederick Mayle           Swap(&context_sparc->ccr);
1005*9712c20fSFrederick Mayle           Swap(&context_sparc->pc);
1006*9712c20fSFrederick Mayle           Swap(&context_sparc->npc);
1007*9712c20fSFrederick Mayle           Swap(&context_sparc->y);
1008*9712c20fSFrederick Mayle           Swap(&context_sparc->asi);
1009*9712c20fSFrederick Mayle           Swap(&context_sparc->fprs);
1010*9712c20fSFrederick Mayle           for (unsigned int fpr_index = 0;
1011*9712c20fSFrederick Mayle                fpr_index < MD_FLOATINGSAVEAREA_SPARC_FPR_COUNT;
1012*9712c20fSFrederick Mayle                ++fpr_index) {
1013*9712c20fSFrederick Mayle             Swap(&context_sparc->float_save.regs[fpr_index]);
1014*9712c20fSFrederick Mayle           }
1015*9712c20fSFrederick Mayle           Swap(&context_sparc->float_save.filler);
1016*9712c20fSFrederick Mayle           Swap(&context_sparc->float_save.fsr);
1017*9712c20fSFrederick Mayle         }
1018*9712c20fSFrederick Mayle         SetContextSPARC(context_sparc.release());
1019*9712c20fSFrederick Mayle 
1020*9712c20fSFrederick Mayle         break;
1021*9712c20fSFrederick Mayle       }
1022*9712c20fSFrederick Mayle 
1023*9712c20fSFrederick Mayle       case MD_CONTEXT_ARM: {
1024*9712c20fSFrederick Mayle         if (expected_size != sizeof(MDRawContextARM)) {
1025*9712c20fSFrederick Mayle           BPLOG(ERROR) << "MinidumpContext arm size mismatch, " <<
1026*9712c20fSFrederick Mayle             expected_size << " != " << sizeof(MDRawContextARM);
1027*9712c20fSFrederick Mayle           return false;
1028*9712c20fSFrederick Mayle         }
1029*9712c20fSFrederick Mayle 
1030*9712c20fSFrederick Mayle         scoped_ptr<MDRawContextARM> context_arm(new MDRawContextARM());
1031*9712c20fSFrederick Mayle 
1032*9712c20fSFrederick Mayle         // Set the context_flags member, which has already been read, and
1033*9712c20fSFrederick Mayle         // read the rest of the structure beginning with the first member
1034*9712c20fSFrederick Mayle         // after context_flags.
1035*9712c20fSFrederick Mayle         context_arm->context_flags = context_flags;
1036*9712c20fSFrederick Mayle 
1037*9712c20fSFrederick Mayle         size_t flags_size = sizeof(context_arm->context_flags);
1038*9712c20fSFrederick Mayle         uint8_t* context_after_flags =
1039*9712c20fSFrederick Mayle             reinterpret_cast<uint8_t*>(context_arm.get()) + flags_size;
1040*9712c20fSFrederick Mayle         if (!minidump_->ReadBytes(context_after_flags,
1041*9712c20fSFrederick Mayle                                   sizeof(MDRawContextARM) - flags_size)) {
1042*9712c20fSFrederick Mayle           BPLOG(ERROR) << "MinidumpContext could not read arm context";
1043*9712c20fSFrederick Mayle           return false;
1044*9712c20fSFrederick Mayle         }
1045*9712c20fSFrederick Mayle 
1046*9712c20fSFrederick Mayle         // Do this after reading the entire MDRawContext structure because
1047*9712c20fSFrederick Mayle         // GetSystemInfo may seek minidump to a new position.
1048*9712c20fSFrederick Mayle         if (!CheckAgainstSystemInfo(cpu_type)) {
1049*9712c20fSFrederick Mayle           BPLOG(ERROR) << "MinidumpContext arm does not match system info";
1050*9712c20fSFrederick Mayle           return false;
1051*9712c20fSFrederick Mayle         }
1052*9712c20fSFrederick Mayle 
1053*9712c20fSFrederick Mayle         if (minidump_->swap()) {
1054*9712c20fSFrederick Mayle           // context_arm->context_flags was already swapped.
1055*9712c20fSFrederick Mayle           for (unsigned int ireg_index = 0;
1056*9712c20fSFrederick Mayle                ireg_index < MD_CONTEXT_ARM_GPR_COUNT;
1057*9712c20fSFrederick Mayle                ++ireg_index) {
1058*9712c20fSFrederick Mayle             Swap(&context_arm->iregs[ireg_index]);
1059*9712c20fSFrederick Mayle           }
1060*9712c20fSFrederick Mayle           Swap(&context_arm->cpsr);
1061*9712c20fSFrederick Mayle           Swap(&context_arm->float_save.fpscr);
1062*9712c20fSFrederick Mayle           for (unsigned int fpr_index = 0;
1063*9712c20fSFrederick Mayle                fpr_index < MD_FLOATINGSAVEAREA_ARM_FPR_COUNT;
1064*9712c20fSFrederick Mayle                ++fpr_index) {
1065*9712c20fSFrederick Mayle             Swap(&context_arm->float_save.regs[fpr_index]);
1066*9712c20fSFrederick Mayle           }
1067*9712c20fSFrederick Mayle           for (unsigned int fpe_index = 0;
1068*9712c20fSFrederick Mayle                fpe_index < MD_FLOATINGSAVEAREA_ARM_FPEXTRA_COUNT;
1069*9712c20fSFrederick Mayle                ++fpe_index) {
1070*9712c20fSFrederick Mayle             Swap(&context_arm->float_save.extra[fpe_index]);
1071*9712c20fSFrederick Mayle           }
1072*9712c20fSFrederick Mayle         }
1073*9712c20fSFrederick Mayle         SetContextARM(context_arm.release());
1074*9712c20fSFrederick Mayle 
1075*9712c20fSFrederick Mayle         break;
1076*9712c20fSFrederick Mayle       }
1077*9712c20fSFrederick Mayle 
1078*9712c20fSFrederick Mayle       case MD_CONTEXT_ARM64: {
1079*9712c20fSFrederick Mayle         if (expected_size != sizeof(MDRawContextARM64)) {
1080*9712c20fSFrederick Mayle           BPLOG(ERROR) << "MinidumpContext arm64 size mismatch, " <<
1081*9712c20fSFrederick Mayle                        expected_size << " != " << sizeof(MDRawContextARM64);
1082*9712c20fSFrederick Mayle           return false;
1083*9712c20fSFrederick Mayle         }
1084*9712c20fSFrederick Mayle 
1085*9712c20fSFrederick Mayle         scoped_ptr<MDRawContextARM64> context_arm64(new MDRawContextARM64());
1086*9712c20fSFrederick Mayle 
1087*9712c20fSFrederick Mayle         // Set the context_flags member, which has already been read, and
1088*9712c20fSFrederick Mayle         // read the rest of the structure beginning with the first member
1089*9712c20fSFrederick Mayle         // after context_flags.
1090*9712c20fSFrederick Mayle         context_arm64->context_flags = context_flags;
1091*9712c20fSFrederick Mayle 
1092*9712c20fSFrederick Mayle         size_t flags_size = sizeof(context_arm64->context_flags);
1093*9712c20fSFrederick Mayle         uint8_t* context_after_flags =
1094*9712c20fSFrederick Mayle             reinterpret_cast<uint8_t*>(context_arm64.get()) + flags_size;
1095*9712c20fSFrederick Mayle         if (!minidump_->ReadBytes(context_after_flags,
1096*9712c20fSFrederick Mayle                                   sizeof(*context_arm64) - flags_size)) {
1097*9712c20fSFrederick Mayle           BPLOG(ERROR) << "MinidumpContext could not read arm64 context";
1098*9712c20fSFrederick Mayle           return false;
1099*9712c20fSFrederick Mayle         }
1100*9712c20fSFrederick Mayle 
1101*9712c20fSFrederick Mayle         // Do this after reading the entire MDRawContext structure because
1102*9712c20fSFrederick Mayle         // GetSystemInfo may seek minidump to a new position.
1103*9712c20fSFrederick Mayle         if (!CheckAgainstSystemInfo(cpu_type)) {
1104*9712c20fSFrederick Mayle           BPLOG(ERROR) << "MinidumpContext arm does not match system info";
1105*9712c20fSFrederick Mayle           return false;
1106*9712c20fSFrederick Mayle         }
1107*9712c20fSFrederick Mayle 
1108*9712c20fSFrederick Mayle         if (minidump_->swap()) {
1109*9712c20fSFrederick Mayle           // context_arm64->context_flags was already swapped.
1110*9712c20fSFrederick Mayle           for (unsigned int ireg_index = 0;
1111*9712c20fSFrederick Mayle                ireg_index < MD_CONTEXT_ARM64_GPR_COUNT;
1112*9712c20fSFrederick Mayle                ++ireg_index) {
1113*9712c20fSFrederick Mayle             Swap(&context_arm64->iregs[ireg_index]);
1114*9712c20fSFrederick Mayle           }
1115*9712c20fSFrederick Mayle           Swap(&context_arm64->cpsr);
1116*9712c20fSFrederick Mayle           Swap(&context_arm64->float_save.fpsr);
1117*9712c20fSFrederick Mayle           Swap(&context_arm64->float_save.fpcr);
1118*9712c20fSFrederick Mayle           for (unsigned int fpr_index = 0;
1119*9712c20fSFrederick Mayle                fpr_index < MD_FLOATINGSAVEAREA_ARM64_FPR_COUNT;
1120*9712c20fSFrederick Mayle                ++fpr_index) {
1121*9712c20fSFrederick Mayle             Normalize128(&context_arm64->float_save.regs[fpr_index],
1122*9712c20fSFrederick Mayle                          minidump_->is_big_endian());
1123*9712c20fSFrederick Mayle             Swap(&context_arm64->float_save.regs[fpr_index]);
1124*9712c20fSFrederick Mayle           }
1125*9712c20fSFrederick Mayle         }
1126*9712c20fSFrederick Mayle         SetContextARM64(context_arm64.release());
1127*9712c20fSFrederick Mayle         break;
1128*9712c20fSFrederick Mayle       }
1129*9712c20fSFrederick Mayle 
1130*9712c20fSFrederick Mayle       case MD_CONTEXT_MIPS:
1131*9712c20fSFrederick Mayle       case MD_CONTEXT_MIPS64: {
1132*9712c20fSFrederick Mayle         if (expected_size != sizeof(MDRawContextMIPS)) {
1133*9712c20fSFrederick Mayle           BPLOG(ERROR) << "MinidumpContext MIPS size mismatch, "
1134*9712c20fSFrederick Mayle                        << expected_size
1135*9712c20fSFrederick Mayle                        << " != "
1136*9712c20fSFrederick Mayle                        << sizeof(MDRawContextMIPS);
1137*9712c20fSFrederick Mayle           return false;
1138*9712c20fSFrederick Mayle         }
1139*9712c20fSFrederick Mayle 
1140*9712c20fSFrederick Mayle         scoped_ptr<MDRawContextMIPS> context_mips(new MDRawContextMIPS());
1141*9712c20fSFrederick Mayle 
1142*9712c20fSFrederick Mayle         // Set the context_flags member, which has already been read, and
1143*9712c20fSFrederick Mayle         // read the rest of the structure beginning with the first member
1144*9712c20fSFrederick Mayle         // after context_flags.
1145*9712c20fSFrederick Mayle         context_mips->context_flags = context_flags;
1146*9712c20fSFrederick Mayle 
1147*9712c20fSFrederick Mayle         size_t flags_size = sizeof(context_mips->context_flags);
1148*9712c20fSFrederick Mayle         uint8_t* context_after_flags =
1149*9712c20fSFrederick Mayle             reinterpret_cast<uint8_t*>(context_mips.get()) + flags_size;
1150*9712c20fSFrederick Mayle         if (!minidump_->ReadBytes(context_after_flags,
1151*9712c20fSFrederick Mayle                                   sizeof(MDRawContextMIPS) - flags_size)) {
1152*9712c20fSFrederick Mayle           BPLOG(ERROR) << "MinidumpContext could not read MIPS context";
1153*9712c20fSFrederick Mayle           return false;
1154*9712c20fSFrederick Mayle         }
1155*9712c20fSFrederick Mayle 
1156*9712c20fSFrederick Mayle         // Do this after reading the entire MDRawContext structure because
1157*9712c20fSFrederick Mayle         // GetSystemInfo may seek minidump to a new position.
1158*9712c20fSFrederick Mayle         if (!CheckAgainstSystemInfo(cpu_type)) {
1159*9712c20fSFrederick Mayle           BPLOG(ERROR) << "MinidumpContext MIPS does not match system info";
1160*9712c20fSFrederick Mayle           return false;
1161*9712c20fSFrederick Mayle         }
1162*9712c20fSFrederick Mayle 
1163*9712c20fSFrederick Mayle         if (minidump_->swap()) {
1164*9712c20fSFrederick Mayle           // context_mips->context_flags was already swapped.
1165*9712c20fSFrederick Mayle           for (int ireg_index = 0;
1166*9712c20fSFrederick Mayle                ireg_index < MD_CONTEXT_MIPS_GPR_COUNT;
1167*9712c20fSFrederick Mayle                ++ireg_index) {
1168*9712c20fSFrederick Mayle             Swap(&context_mips->iregs[ireg_index]);
1169*9712c20fSFrederick Mayle           }
1170*9712c20fSFrederick Mayle 	  Swap(&context_mips->mdhi);
1171*9712c20fSFrederick Mayle 	  Swap(&context_mips->mdlo);
1172*9712c20fSFrederick Mayle           for (int dsp_index = 0;
1173*9712c20fSFrederick Mayle                dsp_index < MD_CONTEXT_MIPS_DSP_COUNT;
1174*9712c20fSFrederick Mayle                ++dsp_index) {
1175*9712c20fSFrederick Mayle             Swap(&context_mips->hi[dsp_index]);
1176*9712c20fSFrederick Mayle             Swap(&context_mips->lo[dsp_index]);
1177*9712c20fSFrederick Mayle           }
1178*9712c20fSFrederick Mayle 	  Swap(&context_mips->dsp_control);
1179*9712c20fSFrederick Mayle           Swap(&context_mips->epc);
1180*9712c20fSFrederick Mayle           Swap(&context_mips->badvaddr);
1181*9712c20fSFrederick Mayle           Swap(&context_mips->status);
1182*9712c20fSFrederick Mayle           Swap(&context_mips->cause);
1183*9712c20fSFrederick Mayle           for (int fpr_index = 0;
1184*9712c20fSFrederick Mayle                fpr_index < MD_FLOATINGSAVEAREA_MIPS_FPR_COUNT;
1185*9712c20fSFrederick Mayle                ++fpr_index) {
1186*9712c20fSFrederick Mayle             Swap(&context_mips->float_save.regs[fpr_index]);
1187*9712c20fSFrederick Mayle           }
1188*9712c20fSFrederick Mayle           Swap(&context_mips->float_save.fpcsr);
1189*9712c20fSFrederick Mayle           Swap(&context_mips->float_save.fir);
1190*9712c20fSFrederick Mayle         }
1191*9712c20fSFrederick Mayle         SetContextMIPS(context_mips.release());
1192*9712c20fSFrederick Mayle 
1193*9712c20fSFrederick Mayle         break;
1194*9712c20fSFrederick Mayle       }
1195*9712c20fSFrederick Mayle 
1196*9712c20fSFrederick Mayle       case MD_CONTEXT_RISCV: {
1197*9712c20fSFrederick Mayle         if (expected_size != sizeof(MDRawContextRISCV)) {
1198*9712c20fSFrederick Mayle           BPLOG(ERROR) << "MinidumpContext RISCV size mismatch, "
1199*9712c20fSFrederick Mayle                        << expected_size
1200*9712c20fSFrederick Mayle                        << " != "
1201*9712c20fSFrederick Mayle                        << sizeof(MDRawContextRISCV);
1202*9712c20fSFrederick Mayle           return false;
1203*9712c20fSFrederick Mayle         }
1204*9712c20fSFrederick Mayle 
1205*9712c20fSFrederick Mayle         scoped_ptr<MDRawContextRISCV> context_riscv(new MDRawContextRISCV());
1206*9712c20fSFrederick Mayle 
1207*9712c20fSFrederick Mayle         // Set the context_flags member, which has already been read, and
1208*9712c20fSFrederick Mayle         // read the rest of the structure beginning with the first member
1209*9712c20fSFrederick Mayle         // after context_flags.
1210*9712c20fSFrederick Mayle         context_riscv->context_flags = context_flags;
1211*9712c20fSFrederick Mayle 
1212*9712c20fSFrederick Mayle         size_t flags_size = sizeof(context_riscv->context_flags);
1213*9712c20fSFrederick Mayle         uint8_t* context_after_flags =
1214*9712c20fSFrederick Mayle             reinterpret_cast<uint8_t*>(context_riscv.get()) + flags_size;
1215*9712c20fSFrederick Mayle         if (!minidump_->ReadBytes(context_after_flags,
1216*9712c20fSFrederick Mayle                                   sizeof(MDRawContextRISCV) - flags_size)) {
1217*9712c20fSFrederick Mayle           BPLOG(ERROR) << "MinidumpContext could not read RISCV context";
1218*9712c20fSFrederick Mayle           return false;
1219*9712c20fSFrederick Mayle         }
1220*9712c20fSFrederick Mayle 
1221*9712c20fSFrederick Mayle         // Do this after reading the entire MDRawContext structure because
1222*9712c20fSFrederick Mayle         // GetSystemInfo may seek minidump to a new position.
1223*9712c20fSFrederick Mayle         if (!CheckAgainstSystemInfo(cpu_type)) {
1224*9712c20fSFrederick Mayle           BPLOG(ERROR) << "MinidumpContext RISCV does not match system info";
1225*9712c20fSFrederick Mayle           return false;
1226*9712c20fSFrederick Mayle         }
1227*9712c20fSFrederick Mayle 
1228*9712c20fSFrederick Mayle         if (minidump_->swap()) {
1229*9712c20fSFrederick Mayle           Swap(&context_riscv->pc);
1230*9712c20fSFrederick Mayle           Swap(&context_riscv->ra);
1231*9712c20fSFrederick Mayle           Swap(&context_riscv->sp);
1232*9712c20fSFrederick Mayle           Swap(&context_riscv->gp);
1233*9712c20fSFrederick Mayle           Swap(&context_riscv->tp);
1234*9712c20fSFrederick Mayle           Swap(&context_riscv->t0);
1235*9712c20fSFrederick Mayle           Swap(&context_riscv->t1);
1236*9712c20fSFrederick Mayle           Swap(&context_riscv->t2);
1237*9712c20fSFrederick Mayle           Swap(&context_riscv->s0);
1238*9712c20fSFrederick Mayle           Swap(&context_riscv->s1);
1239*9712c20fSFrederick Mayle           Swap(&context_riscv->a0);
1240*9712c20fSFrederick Mayle           Swap(&context_riscv->a1);
1241*9712c20fSFrederick Mayle           Swap(&context_riscv->a2);
1242*9712c20fSFrederick Mayle           Swap(&context_riscv->a3);
1243*9712c20fSFrederick Mayle           Swap(&context_riscv->a4);
1244*9712c20fSFrederick Mayle           Swap(&context_riscv->a5);
1245*9712c20fSFrederick Mayle           Swap(&context_riscv->a6);
1246*9712c20fSFrederick Mayle           Swap(&context_riscv->a7);
1247*9712c20fSFrederick Mayle           Swap(&context_riscv->s2);
1248*9712c20fSFrederick Mayle           Swap(&context_riscv->s3);
1249*9712c20fSFrederick Mayle           Swap(&context_riscv->s4);
1250*9712c20fSFrederick Mayle           Swap(&context_riscv->s5);
1251*9712c20fSFrederick Mayle           Swap(&context_riscv->s6);
1252*9712c20fSFrederick Mayle           Swap(&context_riscv->s7);
1253*9712c20fSFrederick Mayle           Swap(&context_riscv->s8);
1254*9712c20fSFrederick Mayle           Swap(&context_riscv->s9);
1255*9712c20fSFrederick Mayle           Swap(&context_riscv->s10);
1256*9712c20fSFrederick Mayle           Swap(&context_riscv->s11);
1257*9712c20fSFrederick Mayle           Swap(&context_riscv->t3);
1258*9712c20fSFrederick Mayle           Swap(&context_riscv->t4);
1259*9712c20fSFrederick Mayle           Swap(&context_riscv->t5);
1260*9712c20fSFrederick Mayle           Swap(&context_riscv->t6);
1261*9712c20fSFrederick Mayle 
1262*9712c20fSFrederick Mayle           for (int fpr_index = 0; fpr_index < MD_CONTEXT_RISCV_FPR_COUNT;
1263*9712c20fSFrederick Mayle                ++fpr_index) {
1264*9712c20fSFrederick Mayle             Swap(&context_riscv->fpregs[fpr_index]);
1265*9712c20fSFrederick Mayle           }
1266*9712c20fSFrederick Mayle           Swap(&context_riscv->fcsr);
1267*9712c20fSFrederick Mayle         }
1268*9712c20fSFrederick Mayle         SetContextRISCV(context_riscv.release());
1269*9712c20fSFrederick Mayle 
1270*9712c20fSFrederick Mayle         break;
1271*9712c20fSFrederick Mayle       }
1272*9712c20fSFrederick Mayle 
1273*9712c20fSFrederick Mayle       case MD_CONTEXT_RISCV64: {
1274*9712c20fSFrederick Mayle         if (expected_size != sizeof(MDRawContextRISCV64)) {
1275*9712c20fSFrederick Mayle           BPLOG(ERROR) << "MinidumpContext RISCV64 size mismatch, "
1276*9712c20fSFrederick Mayle                        << expected_size
1277*9712c20fSFrederick Mayle                        << " != "
1278*9712c20fSFrederick Mayle                        << sizeof(MDRawContextRISCV64);
1279*9712c20fSFrederick Mayle           return false;
1280*9712c20fSFrederick Mayle         }
1281*9712c20fSFrederick Mayle 
1282*9712c20fSFrederick Mayle         scoped_ptr<MDRawContextRISCV64> context_riscv64(
1283*9712c20fSFrederick Mayle             new MDRawContextRISCV64());
1284*9712c20fSFrederick Mayle 
1285*9712c20fSFrederick Mayle         // Set the context_flags member, which has already been read, and
1286*9712c20fSFrederick Mayle         // read the rest of the structure beginning with the first member
1287*9712c20fSFrederick Mayle         // after context_flags.
1288*9712c20fSFrederick Mayle         context_riscv64->context_flags = context_flags;
1289*9712c20fSFrederick Mayle 
1290*9712c20fSFrederick Mayle         size_t flags_size = sizeof(context_riscv64->context_flags);
1291*9712c20fSFrederick Mayle         uint8_t* context_after_flags =
1292*9712c20fSFrederick Mayle             reinterpret_cast<uint8_t*>(context_riscv64.get()) + flags_size;
1293*9712c20fSFrederick Mayle         if (!minidump_->ReadBytes(context_after_flags,
1294*9712c20fSFrederick Mayle                                   sizeof(MDRawContextRISCV64) - flags_size)) {
1295*9712c20fSFrederick Mayle           BPLOG(ERROR) << "MinidumpContext could not read RISCV context";
1296*9712c20fSFrederick Mayle           return false;
1297*9712c20fSFrederick Mayle         }
1298*9712c20fSFrederick Mayle 
1299*9712c20fSFrederick Mayle         // Do this after reading the entire MDRawContext structure because
1300*9712c20fSFrederick Mayle         // GetSystemInfo may seek minidump to a new position.
1301*9712c20fSFrederick Mayle         if (!CheckAgainstSystemInfo(cpu_type)) {
1302*9712c20fSFrederick Mayle           BPLOG(ERROR) << "MinidumpContext RISCV does not match system info";
1303*9712c20fSFrederick Mayle           return false;
1304*9712c20fSFrederick Mayle         }
1305*9712c20fSFrederick Mayle 
1306*9712c20fSFrederick Mayle         if (minidump_->swap()) {
1307*9712c20fSFrederick Mayle           Swap(&context_riscv64->pc);
1308*9712c20fSFrederick Mayle           Swap(&context_riscv64->ra);
1309*9712c20fSFrederick Mayle           Swap(&context_riscv64->sp);
1310*9712c20fSFrederick Mayle           Swap(&context_riscv64->gp);
1311*9712c20fSFrederick Mayle           Swap(&context_riscv64->tp);
1312*9712c20fSFrederick Mayle           Swap(&context_riscv64->t0);
1313*9712c20fSFrederick Mayle           Swap(&context_riscv64->t1);
1314*9712c20fSFrederick Mayle           Swap(&context_riscv64->t2);
1315*9712c20fSFrederick Mayle           Swap(&context_riscv64->s0);
1316*9712c20fSFrederick Mayle           Swap(&context_riscv64->s1);
1317*9712c20fSFrederick Mayle           Swap(&context_riscv64->a0);
1318*9712c20fSFrederick Mayle           Swap(&context_riscv64->a1);
1319*9712c20fSFrederick Mayle           Swap(&context_riscv64->a2);
1320*9712c20fSFrederick Mayle           Swap(&context_riscv64->a3);
1321*9712c20fSFrederick Mayle           Swap(&context_riscv64->a4);
1322*9712c20fSFrederick Mayle           Swap(&context_riscv64->a5);
1323*9712c20fSFrederick Mayle           Swap(&context_riscv64->a6);
1324*9712c20fSFrederick Mayle           Swap(&context_riscv64->a7);
1325*9712c20fSFrederick Mayle           Swap(&context_riscv64->s2);
1326*9712c20fSFrederick Mayle           Swap(&context_riscv64->s3);
1327*9712c20fSFrederick Mayle           Swap(&context_riscv64->s4);
1328*9712c20fSFrederick Mayle           Swap(&context_riscv64->s5);
1329*9712c20fSFrederick Mayle           Swap(&context_riscv64->s6);
1330*9712c20fSFrederick Mayle           Swap(&context_riscv64->s7);
1331*9712c20fSFrederick Mayle           Swap(&context_riscv64->s8);
1332*9712c20fSFrederick Mayle           Swap(&context_riscv64->s9);
1333*9712c20fSFrederick Mayle           Swap(&context_riscv64->s10);
1334*9712c20fSFrederick Mayle           Swap(&context_riscv64->s11);
1335*9712c20fSFrederick Mayle           Swap(&context_riscv64->t3);
1336*9712c20fSFrederick Mayle           Swap(&context_riscv64->t4);
1337*9712c20fSFrederick Mayle           Swap(&context_riscv64->t5);
1338*9712c20fSFrederick Mayle           Swap(&context_riscv64->t6);
1339*9712c20fSFrederick Mayle 
1340*9712c20fSFrederick Mayle           for (int fpr_index = 0; fpr_index < MD_CONTEXT_RISCV_FPR_COUNT;
1341*9712c20fSFrederick Mayle                ++fpr_index) {
1342*9712c20fSFrederick Mayle             Swap(&context_riscv64->fpregs[fpr_index]);
1343*9712c20fSFrederick Mayle           }
1344*9712c20fSFrederick Mayle           Swap(&context_riscv64->fcsr);
1345*9712c20fSFrederick Mayle         }
1346*9712c20fSFrederick Mayle         SetContextRISCV64(context_riscv64.release());
1347*9712c20fSFrederick Mayle 
1348*9712c20fSFrederick Mayle         break;
1349*9712c20fSFrederick Mayle       }
1350*9712c20fSFrederick Mayle 
1351*9712c20fSFrederick Mayle       default: {
1352*9712c20fSFrederick Mayle         // Unknown context type - Don't log as an error yet. Let the
1353*9712c20fSFrederick Mayle         // caller work that out.
1354*9712c20fSFrederick Mayle         BPLOG(INFO) << "MinidumpContext unknown context type " <<
1355*9712c20fSFrederick Mayle           HexString(cpu_type);
1356*9712c20fSFrederick Mayle         return false;
1357*9712c20fSFrederick Mayle       }
1358*9712c20fSFrederick Mayle     }
1359*9712c20fSFrederick Mayle     SetContextFlags(context_flags);
1360*9712c20fSFrederick Mayle   }
1361*9712c20fSFrederick Mayle 
1362*9712c20fSFrederick Mayle   valid_ = true;
1363*9712c20fSFrederick Mayle   return true;
1364*9712c20fSFrederick Mayle }
1365*9712c20fSFrederick Mayle 
CheckAgainstSystemInfo(uint32_t context_cpu_type)1366*9712c20fSFrederick Mayle bool MinidumpContext::CheckAgainstSystemInfo(uint32_t context_cpu_type) {
1367*9712c20fSFrederick Mayle   // It's OK if the minidump doesn't contain an MD_SYSTEM_INFO_STREAM,
1368*9712c20fSFrederick Mayle   // as this function just implements a sanity check.
1369*9712c20fSFrederick Mayle   MinidumpSystemInfo* system_info = minidump_->GetSystemInfo();
1370*9712c20fSFrederick Mayle   if (!system_info) {
1371*9712c20fSFrederick Mayle     BPLOG(INFO) << "MinidumpContext could not be compared against "
1372*9712c20fSFrederick Mayle                    "MinidumpSystemInfo";
1373*9712c20fSFrederick Mayle     return true;
1374*9712c20fSFrederick Mayle   }
1375*9712c20fSFrederick Mayle 
1376*9712c20fSFrederick Mayle   // If there is an MD_SYSTEM_INFO_STREAM, it should contain valid system info.
1377*9712c20fSFrederick Mayle   const MDRawSystemInfo* raw_system_info = system_info->system_info();
1378*9712c20fSFrederick Mayle   if (!raw_system_info) {
1379*9712c20fSFrederick Mayle     BPLOG(INFO) << "MinidumpContext could not be compared against "
1380*9712c20fSFrederick Mayle                    "MDRawSystemInfo";
1381*9712c20fSFrederick Mayle     return false;
1382*9712c20fSFrederick Mayle   }
1383*9712c20fSFrederick Mayle 
1384*9712c20fSFrederick Mayle   MDCPUArchitecture system_info_cpu_type = static_cast<MDCPUArchitecture>(
1385*9712c20fSFrederick Mayle       raw_system_info->processor_architecture);
1386*9712c20fSFrederick Mayle 
1387*9712c20fSFrederick Mayle   // Compare the CPU type of the context record to the CPU type in the
1388*9712c20fSFrederick Mayle   // minidump's system info stream.
1389*9712c20fSFrederick Mayle   bool return_value = false;
1390*9712c20fSFrederick Mayle   switch (context_cpu_type) {
1391*9712c20fSFrederick Mayle     case MD_CONTEXT_X86:
1392*9712c20fSFrederick Mayle       if (system_info_cpu_type == MD_CPU_ARCHITECTURE_X86 ||
1393*9712c20fSFrederick Mayle           system_info_cpu_type == MD_CPU_ARCHITECTURE_X86_WIN64 ||
1394*9712c20fSFrederick Mayle           system_info_cpu_type == MD_CPU_ARCHITECTURE_AMD64) {
1395*9712c20fSFrederick Mayle         return_value = true;
1396*9712c20fSFrederick Mayle       }
1397*9712c20fSFrederick Mayle       break;
1398*9712c20fSFrederick Mayle 
1399*9712c20fSFrederick Mayle     case MD_CONTEXT_PPC:
1400*9712c20fSFrederick Mayle       if (system_info_cpu_type == MD_CPU_ARCHITECTURE_PPC)
1401*9712c20fSFrederick Mayle         return_value = true;
1402*9712c20fSFrederick Mayle       break;
1403*9712c20fSFrederick Mayle 
1404*9712c20fSFrederick Mayle     case MD_CONTEXT_PPC64:
1405*9712c20fSFrederick Mayle       if (system_info_cpu_type == MD_CPU_ARCHITECTURE_PPC64)
1406*9712c20fSFrederick Mayle         return_value = true;
1407*9712c20fSFrederick Mayle       break;
1408*9712c20fSFrederick Mayle 
1409*9712c20fSFrederick Mayle     case MD_CONTEXT_AMD64:
1410*9712c20fSFrederick Mayle       if (system_info_cpu_type == MD_CPU_ARCHITECTURE_AMD64)
1411*9712c20fSFrederick Mayle         return_value = true;
1412*9712c20fSFrederick Mayle       break;
1413*9712c20fSFrederick Mayle 
1414*9712c20fSFrederick Mayle     case MD_CONTEXT_SPARC:
1415*9712c20fSFrederick Mayle       if (system_info_cpu_type == MD_CPU_ARCHITECTURE_SPARC)
1416*9712c20fSFrederick Mayle         return_value = true;
1417*9712c20fSFrederick Mayle       break;
1418*9712c20fSFrederick Mayle 
1419*9712c20fSFrederick Mayle     case MD_CONTEXT_ARM:
1420*9712c20fSFrederick Mayle       if (system_info_cpu_type == MD_CPU_ARCHITECTURE_ARM)
1421*9712c20fSFrederick Mayle         return_value = true;
1422*9712c20fSFrederick Mayle       break;
1423*9712c20fSFrederick Mayle 
1424*9712c20fSFrederick Mayle     case MD_CONTEXT_ARM64:
1425*9712c20fSFrederick Mayle       if (system_info_cpu_type == MD_CPU_ARCHITECTURE_ARM64)
1426*9712c20fSFrederick Mayle         return_value = true;
1427*9712c20fSFrederick Mayle       break;
1428*9712c20fSFrederick Mayle 
1429*9712c20fSFrederick Mayle     case MD_CONTEXT_ARM64_OLD:
1430*9712c20fSFrederick Mayle       if (system_info_cpu_type == MD_CPU_ARCHITECTURE_ARM64_OLD)
1431*9712c20fSFrederick Mayle         return_value = true;
1432*9712c20fSFrederick Mayle       break;
1433*9712c20fSFrederick Mayle 
1434*9712c20fSFrederick Mayle     case MD_CONTEXT_MIPS:
1435*9712c20fSFrederick Mayle       if (system_info_cpu_type == MD_CPU_ARCHITECTURE_MIPS)
1436*9712c20fSFrederick Mayle         return_value = true;
1437*9712c20fSFrederick Mayle       break;
1438*9712c20fSFrederick Mayle 
1439*9712c20fSFrederick Mayle     case MD_CONTEXT_MIPS64:
1440*9712c20fSFrederick Mayle       if (system_info_cpu_type == MD_CPU_ARCHITECTURE_MIPS64)
1441*9712c20fSFrederick Mayle         return_value = true;
1442*9712c20fSFrederick Mayle       break;
1443*9712c20fSFrederick Mayle 
1444*9712c20fSFrederick Mayle     case MD_CONTEXT_RISCV:
1445*9712c20fSFrederick Mayle       if (system_info_cpu_type == MD_CPU_ARCHITECTURE_RISCV)
1446*9712c20fSFrederick Mayle        return_value = true;
1447*9712c20fSFrederick Mayle       break;
1448*9712c20fSFrederick Mayle 
1449*9712c20fSFrederick Mayle     case MD_CONTEXT_RISCV64:
1450*9712c20fSFrederick Mayle       if (system_info_cpu_type == MD_CPU_ARCHITECTURE_RISCV64)
1451*9712c20fSFrederick Mayle         return_value = true;
1452*9712c20fSFrederick Mayle       break;
1453*9712c20fSFrederick Mayle   }
1454*9712c20fSFrederick Mayle 
1455*9712c20fSFrederick Mayle   BPLOG_IF(ERROR, !return_value) << "MinidumpContext CPU " <<
1456*9712c20fSFrederick Mayle                                     HexString(context_cpu_type) <<
1457*9712c20fSFrederick Mayle                                     " wrong for MinidumpSystemInfo CPU " <<
1458*9712c20fSFrederick Mayle                                     HexString(system_info_cpu_type);
1459*9712c20fSFrederick Mayle 
1460*9712c20fSFrederick Mayle   return return_value;
1461*9712c20fSFrederick Mayle }
1462*9712c20fSFrederick Mayle 
1463*9712c20fSFrederick Mayle 
1464*9712c20fSFrederick Mayle //
1465*9712c20fSFrederick Mayle // MinidumpMemoryRegion
1466*9712c20fSFrederick Mayle //
1467*9712c20fSFrederick Mayle 
1468*9712c20fSFrederick Mayle 
1469*9712c20fSFrederick Mayle uint32_t MinidumpMemoryRegion::max_bytes_ = 64 * 1024 * 1024;  // 64MB
1470*9712c20fSFrederick Mayle 
1471*9712c20fSFrederick Mayle 
MinidumpMemoryRegion(Minidump * minidump)1472*9712c20fSFrederick Mayle MinidumpMemoryRegion::MinidumpMemoryRegion(Minidump* minidump)
1473*9712c20fSFrederick Mayle     : MinidumpObject(minidump),
1474*9712c20fSFrederick Mayle       descriptor_(NULL),
1475*9712c20fSFrederick Mayle       memory_(NULL) {
1476*9712c20fSFrederick Mayle   hexdump_width_ = minidump_ ? minidump_->HexdumpMode() : 0;
1477*9712c20fSFrederick Mayle   hexdump_ = hexdump_width_ != 0;
1478*9712c20fSFrederick Mayle }
1479*9712c20fSFrederick Mayle 
1480*9712c20fSFrederick Mayle 
~MinidumpMemoryRegion()1481*9712c20fSFrederick Mayle MinidumpMemoryRegion::~MinidumpMemoryRegion() {
1482*9712c20fSFrederick Mayle   delete memory_;
1483*9712c20fSFrederick Mayle }
1484*9712c20fSFrederick Mayle 
1485*9712c20fSFrederick Mayle 
SetDescriptor(MDMemoryDescriptor * descriptor)1486*9712c20fSFrederick Mayle void MinidumpMemoryRegion::SetDescriptor(MDMemoryDescriptor* descriptor) {
1487*9712c20fSFrederick Mayle   descriptor_ = descriptor;
1488*9712c20fSFrederick Mayle   valid_ = descriptor &&
1489*9712c20fSFrederick Mayle            descriptor_->memory.data_size <=
1490*9712c20fSFrederick Mayle                numeric_limits<uint64_t>::max() -
1491*9712c20fSFrederick Mayle                descriptor_->start_of_memory_range;
1492*9712c20fSFrederick Mayle }
1493*9712c20fSFrederick Mayle 
1494*9712c20fSFrederick Mayle 
GetMemory() const1495*9712c20fSFrederick Mayle const uint8_t* MinidumpMemoryRegion::GetMemory() const {
1496*9712c20fSFrederick Mayle   if (!valid_) {
1497*9712c20fSFrederick Mayle     BPLOG(ERROR) << "Invalid MinidumpMemoryRegion for GetMemory";
1498*9712c20fSFrederick Mayle     return NULL;
1499*9712c20fSFrederick Mayle   }
1500*9712c20fSFrederick Mayle 
1501*9712c20fSFrederick Mayle   if (!memory_) {
1502*9712c20fSFrederick Mayle     if (descriptor_->memory.data_size == 0) {
1503*9712c20fSFrederick Mayle       BPLOG(ERROR) << "MinidumpMemoryRegion is empty";
1504*9712c20fSFrederick Mayle       return NULL;
1505*9712c20fSFrederick Mayle     }
1506*9712c20fSFrederick Mayle 
1507*9712c20fSFrederick Mayle     if (!minidump_->SeekSet(descriptor_->memory.rva)) {
1508*9712c20fSFrederick Mayle       BPLOG(ERROR) << "MinidumpMemoryRegion could not seek to memory region";
1509*9712c20fSFrederick Mayle       return NULL;
1510*9712c20fSFrederick Mayle     }
1511*9712c20fSFrederick Mayle 
1512*9712c20fSFrederick Mayle     if (descriptor_->memory.data_size > max_bytes_) {
1513*9712c20fSFrederick Mayle       BPLOG(ERROR) << "MinidumpMemoryRegion size " <<
1514*9712c20fSFrederick Mayle                       descriptor_->memory.data_size << " exceeds maximum " <<
1515*9712c20fSFrederick Mayle                       max_bytes_;
1516*9712c20fSFrederick Mayle       return NULL;
1517*9712c20fSFrederick Mayle     }
1518*9712c20fSFrederick Mayle 
1519*9712c20fSFrederick Mayle     scoped_ptr< vector<uint8_t> > memory(
1520*9712c20fSFrederick Mayle         new vector<uint8_t>(descriptor_->memory.data_size));
1521*9712c20fSFrederick Mayle 
1522*9712c20fSFrederick Mayle     if (!minidump_->ReadBytes(&(*memory)[0], descriptor_->memory.data_size)) {
1523*9712c20fSFrederick Mayle       BPLOG(ERROR) << "MinidumpMemoryRegion could not read memory region";
1524*9712c20fSFrederick Mayle       return NULL;
1525*9712c20fSFrederick Mayle     }
1526*9712c20fSFrederick Mayle 
1527*9712c20fSFrederick Mayle     memory_ = memory.release();
1528*9712c20fSFrederick Mayle   }
1529*9712c20fSFrederick Mayle 
1530*9712c20fSFrederick Mayle   return &(*memory_)[0];
1531*9712c20fSFrederick Mayle }
1532*9712c20fSFrederick Mayle 
1533*9712c20fSFrederick Mayle 
GetBase() const1534*9712c20fSFrederick Mayle uint64_t MinidumpMemoryRegion::GetBase() const {
1535*9712c20fSFrederick Mayle   if (!valid_) {
1536*9712c20fSFrederick Mayle     BPLOG(ERROR) << "Invalid MinidumpMemoryRegion for GetBase";
1537*9712c20fSFrederick Mayle     return static_cast<uint64_t>(-1);
1538*9712c20fSFrederick Mayle   }
1539*9712c20fSFrederick Mayle 
1540*9712c20fSFrederick Mayle   return descriptor_->start_of_memory_range;
1541*9712c20fSFrederick Mayle }
1542*9712c20fSFrederick Mayle 
1543*9712c20fSFrederick Mayle 
GetSize() const1544*9712c20fSFrederick Mayle uint32_t MinidumpMemoryRegion::GetSize() const {
1545*9712c20fSFrederick Mayle   if (!valid_) {
1546*9712c20fSFrederick Mayle     BPLOG(ERROR) << "Invalid MinidumpMemoryRegion for GetSize";
1547*9712c20fSFrederick Mayle     return 0;
1548*9712c20fSFrederick Mayle   }
1549*9712c20fSFrederick Mayle 
1550*9712c20fSFrederick Mayle   return descriptor_->memory.data_size;
1551*9712c20fSFrederick Mayle }
1552*9712c20fSFrederick Mayle 
1553*9712c20fSFrederick Mayle 
FreeMemory()1554*9712c20fSFrederick Mayle void MinidumpMemoryRegion::FreeMemory() {
1555*9712c20fSFrederick Mayle   delete memory_;
1556*9712c20fSFrederick Mayle   memory_ = NULL;
1557*9712c20fSFrederick Mayle }
1558*9712c20fSFrederick Mayle 
1559*9712c20fSFrederick Mayle 
1560*9712c20fSFrederick Mayle template<typename T>
GetMemoryAtAddressInternal(uint64_t address,T * value) const1561*9712c20fSFrederick Mayle bool MinidumpMemoryRegion::GetMemoryAtAddressInternal(uint64_t address,
1562*9712c20fSFrederick Mayle                                                       T*        value) const {
1563*9712c20fSFrederick Mayle   BPLOG_IF(ERROR, !value) << "MinidumpMemoryRegion::GetMemoryAtAddressInternal "
1564*9712c20fSFrederick Mayle                              "requires |value|";
1565*9712c20fSFrederick Mayle   assert(value);
1566*9712c20fSFrederick Mayle   *value = 0;
1567*9712c20fSFrederick Mayle 
1568*9712c20fSFrederick Mayle   if (!valid_) {
1569*9712c20fSFrederick Mayle     BPLOG(ERROR) << "Invalid MinidumpMemoryRegion for "
1570*9712c20fSFrederick Mayle                     "GetMemoryAtAddressInternal";
1571*9712c20fSFrederick Mayle     return false;
1572*9712c20fSFrederick Mayle   }
1573*9712c20fSFrederick Mayle 
1574*9712c20fSFrederick Mayle   // Common failure case
1575*9712c20fSFrederick Mayle   if (address < descriptor_->start_of_memory_range ||
1576*9712c20fSFrederick Mayle       sizeof(T) > numeric_limits<uint64_t>::max() - address ||
1577*9712c20fSFrederick Mayle       address + sizeof(T) > descriptor_->start_of_memory_range +
1578*9712c20fSFrederick Mayle                             descriptor_->memory.data_size) {
1579*9712c20fSFrederick Mayle     BPLOG(INFO) << "MinidumpMemoryRegion request out of range: " <<
1580*9712c20fSFrederick Mayle                     HexString(address) << "+" << sizeof(T) << "/" <<
1581*9712c20fSFrederick Mayle                     HexString(descriptor_->start_of_memory_range) << "+" <<
1582*9712c20fSFrederick Mayle                     HexString(descriptor_->memory.data_size);
1583*9712c20fSFrederick Mayle     return false;
1584*9712c20fSFrederick Mayle   }
1585*9712c20fSFrederick Mayle 
1586*9712c20fSFrederick Mayle   const uint8_t* memory = GetMemory();
1587*9712c20fSFrederick Mayle   if (!memory) {
1588*9712c20fSFrederick Mayle     // GetMemory already logged a perfectly good message.
1589*9712c20fSFrederick Mayle     return false;
1590*9712c20fSFrederick Mayle   }
1591*9712c20fSFrederick Mayle 
1592*9712c20fSFrederick Mayle   // If the CPU requires memory accesses to be aligned, this can crash.
1593*9712c20fSFrederick Mayle   // x86 and ppc are able to cope, though.
1594*9712c20fSFrederick Mayle   *value = *reinterpret_cast<const T*>(
1595*9712c20fSFrederick Mayle       &memory[address - descriptor_->start_of_memory_range]);
1596*9712c20fSFrederick Mayle 
1597*9712c20fSFrederick Mayle   if (minidump_->swap())
1598*9712c20fSFrederick Mayle     Swap(value);
1599*9712c20fSFrederick Mayle 
1600*9712c20fSFrederick Mayle   return true;
1601*9712c20fSFrederick Mayle }
1602*9712c20fSFrederick Mayle 
1603*9712c20fSFrederick Mayle 
GetMemoryAtAddress(uint64_t address,uint8_t * value) const1604*9712c20fSFrederick Mayle bool MinidumpMemoryRegion::GetMemoryAtAddress(uint64_t  address,
1605*9712c20fSFrederick Mayle                                               uint8_t*  value) const {
1606*9712c20fSFrederick Mayle   return GetMemoryAtAddressInternal(address, value);
1607*9712c20fSFrederick Mayle }
1608*9712c20fSFrederick Mayle 
1609*9712c20fSFrederick Mayle 
GetMemoryAtAddress(uint64_t address,uint16_t * value) const1610*9712c20fSFrederick Mayle bool MinidumpMemoryRegion::GetMemoryAtAddress(uint64_t  address,
1611*9712c20fSFrederick Mayle                                               uint16_t* value) const {
1612*9712c20fSFrederick Mayle   return GetMemoryAtAddressInternal(address, value);
1613*9712c20fSFrederick Mayle }
1614*9712c20fSFrederick Mayle 
1615*9712c20fSFrederick Mayle 
GetMemoryAtAddress(uint64_t address,uint32_t * value) const1616*9712c20fSFrederick Mayle bool MinidumpMemoryRegion::GetMemoryAtAddress(uint64_t  address,
1617*9712c20fSFrederick Mayle                                               uint32_t* value) const {
1618*9712c20fSFrederick Mayle   return GetMemoryAtAddressInternal(address, value);
1619*9712c20fSFrederick Mayle }
1620*9712c20fSFrederick Mayle 
1621*9712c20fSFrederick Mayle 
GetMemoryAtAddress(uint64_t address,uint64_t * value) const1622*9712c20fSFrederick Mayle bool MinidumpMemoryRegion::GetMemoryAtAddress(uint64_t  address,
1623*9712c20fSFrederick Mayle                                               uint64_t* value) const {
1624*9712c20fSFrederick Mayle   return GetMemoryAtAddressInternal(address, value);
1625*9712c20fSFrederick Mayle }
1626*9712c20fSFrederick Mayle 
1627*9712c20fSFrederick Mayle 
Print() const1628*9712c20fSFrederick Mayle void MinidumpMemoryRegion::Print() const {
1629*9712c20fSFrederick Mayle   if (!valid_) {
1630*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpMemoryRegion cannot print invalid data";
1631*9712c20fSFrederick Mayle     return;
1632*9712c20fSFrederick Mayle   }
1633*9712c20fSFrederick Mayle 
1634*9712c20fSFrederick Mayle   const uint8_t* memory = GetMemory();
1635*9712c20fSFrederick Mayle   if (memory) {
1636*9712c20fSFrederick Mayle     if (hexdump_) {
1637*9712c20fSFrederick Mayle       // Pretty hexdump view.
1638*9712c20fSFrederick Mayle       for (unsigned int byte_index = 0;
1639*9712c20fSFrederick Mayle            byte_index < descriptor_->memory.data_size;
1640*9712c20fSFrederick Mayle            byte_index += hexdump_width_) {
1641*9712c20fSFrederick Mayle         // In case the memory won't fill a whole line.
1642*9712c20fSFrederick Mayle         unsigned int num_bytes = std::min(
1643*9712c20fSFrederick Mayle             descriptor_->memory.data_size - byte_index, hexdump_width_);
1644*9712c20fSFrederick Mayle 
1645*9712c20fSFrederick Mayle         // Display the leading address.
1646*9712c20fSFrederick Mayle         printf("%08x  ", byte_index);
1647*9712c20fSFrederick Mayle 
1648*9712c20fSFrederick Mayle         // Show the bytes in hex.
1649*9712c20fSFrederick Mayle         for (unsigned int i = 0; i < hexdump_width_; ++i) {
1650*9712c20fSFrederick Mayle           if (i < num_bytes) {
1651*9712c20fSFrederick Mayle             // Show the single byte of memory in hex.
1652*9712c20fSFrederick Mayle             printf("%02x ", memory[byte_index + i]);
1653*9712c20fSFrederick Mayle           } else {
1654*9712c20fSFrederick Mayle             // If this line doesn't fill up, pad it out.
1655*9712c20fSFrederick Mayle             printf("   ");
1656*9712c20fSFrederick Mayle           }
1657*9712c20fSFrederick Mayle 
1658*9712c20fSFrederick Mayle           // Insert a space every 8 bytes to make it more readable.
1659*9712c20fSFrederick Mayle           if (((i + 1) % 8) == 0) {
1660*9712c20fSFrederick Mayle             printf(" ");
1661*9712c20fSFrederick Mayle           }
1662*9712c20fSFrederick Mayle         }
1663*9712c20fSFrederick Mayle 
1664*9712c20fSFrederick Mayle         // Decode the line as ASCII.
1665*9712c20fSFrederick Mayle         printf("|");
1666*9712c20fSFrederick Mayle         for (unsigned int i = 0; i < hexdump_width_; ++i) {
1667*9712c20fSFrederick Mayle           if (i < num_bytes) {
1668*9712c20fSFrederick Mayle             uint8_t byte = memory[byte_index + i];
1669*9712c20fSFrederick Mayle             printf("%c", isprint(byte) ? byte : '.');
1670*9712c20fSFrederick Mayle           } else {
1671*9712c20fSFrederick Mayle             // If this line doesn't fill up, pad it out.
1672*9712c20fSFrederick Mayle             printf(" ");
1673*9712c20fSFrederick Mayle           }
1674*9712c20fSFrederick Mayle         }
1675*9712c20fSFrederick Mayle         printf("|\n");
1676*9712c20fSFrederick Mayle       }
1677*9712c20fSFrederick Mayle     } else {
1678*9712c20fSFrederick Mayle       // Ugly raw string view.
1679*9712c20fSFrederick Mayle       printf("0x");
1680*9712c20fSFrederick Mayle       for (unsigned int i = 0;
1681*9712c20fSFrederick Mayle            i < descriptor_->memory.data_size;
1682*9712c20fSFrederick Mayle            i++) {
1683*9712c20fSFrederick Mayle         printf("%02x", memory[i]);
1684*9712c20fSFrederick Mayle       }
1685*9712c20fSFrederick Mayle       printf("\n");
1686*9712c20fSFrederick Mayle     }
1687*9712c20fSFrederick Mayle   } else {
1688*9712c20fSFrederick Mayle     printf("No memory\n");
1689*9712c20fSFrederick Mayle   }
1690*9712c20fSFrederick Mayle }
1691*9712c20fSFrederick Mayle 
1692*9712c20fSFrederick Mayle 
SetPrintMode(bool hexdump,unsigned int hexdump_width)1693*9712c20fSFrederick Mayle void MinidumpMemoryRegion::SetPrintMode(bool hexdump,
1694*9712c20fSFrederick Mayle                                         unsigned int hexdump_width) {
1695*9712c20fSFrederick Mayle   // Require the width to be a multiple of 8 bytes.
1696*9712c20fSFrederick Mayle   if (hexdump_width == 0 || (hexdump_width % 8) != 0) {
1697*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpMemoryRegion print hexdump_width must be "
1698*9712c20fSFrederick Mayle                     "multiple of 8, not " << hexdump_width;
1699*9712c20fSFrederick Mayle     return;
1700*9712c20fSFrederick Mayle   }
1701*9712c20fSFrederick Mayle 
1702*9712c20fSFrederick Mayle   hexdump_ = hexdump;
1703*9712c20fSFrederick Mayle   hexdump_width_ = hexdump_width;
1704*9712c20fSFrederick Mayle }
1705*9712c20fSFrederick Mayle 
1706*9712c20fSFrederick Mayle 
1707*9712c20fSFrederick Mayle //
1708*9712c20fSFrederick Mayle // MinidumpThread
1709*9712c20fSFrederick Mayle //
1710*9712c20fSFrederick Mayle 
1711*9712c20fSFrederick Mayle 
MinidumpThread(Minidump * minidump)1712*9712c20fSFrederick Mayle MinidumpThread::MinidumpThread(Minidump* minidump)
1713*9712c20fSFrederick Mayle     : MinidumpObject(minidump),
1714*9712c20fSFrederick Mayle       thread_(),
1715*9712c20fSFrederick Mayle       memory_(NULL),
1716*9712c20fSFrederick Mayle       context_(NULL) {
1717*9712c20fSFrederick Mayle }
1718*9712c20fSFrederick Mayle 
1719*9712c20fSFrederick Mayle 
~MinidumpThread()1720*9712c20fSFrederick Mayle MinidumpThread::~MinidumpThread() {
1721*9712c20fSFrederick Mayle   delete memory_;
1722*9712c20fSFrederick Mayle   delete context_;
1723*9712c20fSFrederick Mayle }
1724*9712c20fSFrederick Mayle 
1725*9712c20fSFrederick Mayle 
Read()1726*9712c20fSFrederick Mayle bool MinidumpThread::Read() {
1727*9712c20fSFrederick Mayle   // Invalidate cached data.
1728*9712c20fSFrederick Mayle   delete memory_;
1729*9712c20fSFrederick Mayle   memory_ = NULL;
1730*9712c20fSFrederick Mayle   delete context_;
1731*9712c20fSFrederick Mayle   context_ = NULL;
1732*9712c20fSFrederick Mayle 
1733*9712c20fSFrederick Mayle   valid_ = false;
1734*9712c20fSFrederick Mayle 
1735*9712c20fSFrederick Mayle   if (!minidump_->ReadBytes(&thread_, sizeof(thread_))) {
1736*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpThread cannot read thread";
1737*9712c20fSFrederick Mayle     return false;
1738*9712c20fSFrederick Mayle   }
1739*9712c20fSFrederick Mayle 
1740*9712c20fSFrederick Mayle   if (minidump_->swap()) {
1741*9712c20fSFrederick Mayle     Swap(&thread_.thread_id);
1742*9712c20fSFrederick Mayle     Swap(&thread_.suspend_count);
1743*9712c20fSFrederick Mayle     Swap(&thread_.priority_class);
1744*9712c20fSFrederick Mayle     Swap(&thread_.priority);
1745*9712c20fSFrederick Mayle     Swap(&thread_.teb);
1746*9712c20fSFrederick Mayle     Swap(&thread_.stack);
1747*9712c20fSFrederick Mayle     Swap(&thread_.thread_context);
1748*9712c20fSFrederick Mayle   }
1749*9712c20fSFrederick Mayle 
1750*9712c20fSFrederick Mayle   // Check for base + size overflow or undersize.
1751*9712c20fSFrederick Mayle   if (thread_.stack.memory.rva == 0 ||
1752*9712c20fSFrederick Mayle       thread_.stack.memory.data_size == 0 ||
1753*9712c20fSFrederick Mayle       thread_.stack.memory.data_size > numeric_limits<uint64_t>::max() -
1754*9712c20fSFrederick Mayle                                        thread_.stack.start_of_memory_range) {
1755*9712c20fSFrederick Mayle     // This is ok, but log an error anyway.
1756*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpThread has a memory region problem, " <<
1757*9712c20fSFrederick Mayle                     HexString(thread_.stack.start_of_memory_range) << "+" <<
1758*9712c20fSFrederick Mayle                     HexString(thread_.stack.memory.data_size) <<
1759*9712c20fSFrederick Mayle                     ", RVA 0x" << HexString(thread_.stack.memory.rva);
1760*9712c20fSFrederick Mayle   } else {
1761*9712c20fSFrederick Mayle     memory_ = new MinidumpMemoryRegion(minidump_);
1762*9712c20fSFrederick Mayle     memory_->SetDescriptor(&thread_.stack);
1763*9712c20fSFrederick Mayle   }
1764*9712c20fSFrederick Mayle 
1765*9712c20fSFrederick Mayle   valid_ = true;
1766*9712c20fSFrederick Mayle   return true;
1767*9712c20fSFrederick Mayle }
1768*9712c20fSFrederick Mayle 
GetStartOfStackMemoryRange() const1769*9712c20fSFrederick Mayle uint64_t MinidumpThread::GetStartOfStackMemoryRange() const {
1770*9712c20fSFrederick Mayle   if (!valid_) {
1771*9712c20fSFrederick Mayle     BPLOG(ERROR) << "GetStartOfStackMemoryRange: Invalid MinidumpThread";
1772*9712c20fSFrederick Mayle     return 0;
1773*9712c20fSFrederick Mayle   }
1774*9712c20fSFrederick Mayle 
1775*9712c20fSFrederick Mayle   return thread_.stack.start_of_memory_range;
1776*9712c20fSFrederick Mayle }
1777*9712c20fSFrederick Mayle 
GetMemory()1778*9712c20fSFrederick Mayle MinidumpMemoryRegion* MinidumpThread::GetMemory() {
1779*9712c20fSFrederick Mayle   if (!valid_) {
1780*9712c20fSFrederick Mayle     BPLOG(ERROR) << "Invalid MinidumpThread for GetMemory";
1781*9712c20fSFrederick Mayle     return NULL;
1782*9712c20fSFrederick Mayle   }
1783*9712c20fSFrederick Mayle 
1784*9712c20fSFrederick Mayle   return memory_;
1785*9712c20fSFrederick Mayle }
1786*9712c20fSFrederick Mayle 
1787*9712c20fSFrederick Mayle 
GetContext()1788*9712c20fSFrederick Mayle MinidumpContext* MinidumpThread::GetContext() {
1789*9712c20fSFrederick Mayle   if (!valid_) {
1790*9712c20fSFrederick Mayle     BPLOG(ERROR) << "Invalid MinidumpThread for GetContext";
1791*9712c20fSFrederick Mayle     return NULL;
1792*9712c20fSFrederick Mayle   }
1793*9712c20fSFrederick Mayle 
1794*9712c20fSFrederick Mayle   if (!context_) {
1795*9712c20fSFrederick Mayle     if (!minidump_->SeekSet(thread_.thread_context.rva)) {
1796*9712c20fSFrederick Mayle       BPLOG(ERROR) << "MinidumpThread cannot seek to context";
1797*9712c20fSFrederick Mayle       return NULL;
1798*9712c20fSFrederick Mayle     }
1799*9712c20fSFrederick Mayle 
1800*9712c20fSFrederick Mayle     scoped_ptr<MinidumpContext> context(new MinidumpContext(minidump_));
1801*9712c20fSFrederick Mayle 
1802*9712c20fSFrederick Mayle     if (!context->Read(thread_.thread_context.data_size)) {
1803*9712c20fSFrederick Mayle       BPLOG(ERROR) << "MinidumpThread cannot read context";
1804*9712c20fSFrederick Mayle       return NULL;
1805*9712c20fSFrederick Mayle     }
1806*9712c20fSFrederick Mayle 
1807*9712c20fSFrederick Mayle     context_ = context.release();
1808*9712c20fSFrederick Mayle   }
1809*9712c20fSFrederick Mayle 
1810*9712c20fSFrederick Mayle   return context_;
1811*9712c20fSFrederick Mayle }
1812*9712c20fSFrederick Mayle 
1813*9712c20fSFrederick Mayle 
GetThreadID(uint32_t * thread_id) const1814*9712c20fSFrederick Mayle bool MinidumpThread::GetThreadID(uint32_t* thread_id) const {
1815*9712c20fSFrederick Mayle   BPLOG_IF(ERROR, !thread_id) << "MinidumpThread::GetThreadID requires "
1816*9712c20fSFrederick Mayle                                  "|thread_id|";
1817*9712c20fSFrederick Mayle   assert(thread_id);
1818*9712c20fSFrederick Mayle   *thread_id = 0;
1819*9712c20fSFrederick Mayle 
1820*9712c20fSFrederick Mayle   if (!valid_) {
1821*9712c20fSFrederick Mayle     BPLOG(ERROR) << "Invalid MinidumpThread for GetThreadID";
1822*9712c20fSFrederick Mayle     return false;
1823*9712c20fSFrederick Mayle   }
1824*9712c20fSFrederick Mayle 
1825*9712c20fSFrederick Mayle   *thread_id = thread_.thread_id;
1826*9712c20fSFrederick Mayle   return true;
1827*9712c20fSFrederick Mayle }
1828*9712c20fSFrederick Mayle 
1829*9712c20fSFrederick Mayle 
Print()1830*9712c20fSFrederick Mayle void MinidumpThread::Print() {
1831*9712c20fSFrederick Mayle   if (!valid_) {
1832*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpThread cannot print invalid data";
1833*9712c20fSFrederick Mayle     return;
1834*9712c20fSFrederick Mayle   }
1835*9712c20fSFrederick Mayle 
1836*9712c20fSFrederick Mayle   printf("MDRawThread\n");
1837*9712c20fSFrederick Mayle   printf("  thread_id                   = 0x%x\n",   thread_.thread_id);
1838*9712c20fSFrederick Mayle   printf("  suspend_count               = %d\n",     thread_.suspend_count);
1839*9712c20fSFrederick Mayle   printf("  priority_class              = 0x%x\n",   thread_.priority_class);
1840*9712c20fSFrederick Mayle   printf("  priority                    = 0x%x\n",   thread_.priority);
1841*9712c20fSFrederick Mayle   printf("  teb                         = 0x%" PRIx64 "\n", thread_.teb);
1842*9712c20fSFrederick Mayle   printf("  stack.start_of_memory_range = 0x%" PRIx64 "\n",
1843*9712c20fSFrederick Mayle          thread_.stack.start_of_memory_range);
1844*9712c20fSFrederick Mayle   printf("  stack.memory.data_size      = 0x%x\n",
1845*9712c20fSFrederick Mayle          thread_.stack.memory.data_size);
1846*9712c20fSFrederick Mayle   printf("  stack.memory.rva            = 0x%x\n",   thread_.stack.memory.rva);
1847*9712c20fSFrederick Mayle   printf("  thread_context.data_size    = 0x%x\n",
1848*9712c20fSFrederick Mayle          thread_.thread_context.data_size);
1849*9712c20fSFrederick Mayle   printf("  thread_context.rva          = 0x%x\n",
1850*9712c20fSFrederick Mayle          thread_.thread_context.rva);
1851*9712c20fSFrederick Mayle 
1852*9712c20fSFrederick Mayle   MinidumpContext* context = GetContext();
1853*9712c20fSFrederick Mayle   if (context) {
1854*9712c20fSFrederick Mayle     printf("\n");
1855*9712c20fSFrederick Mayle     context->Print();
1856*9712c20fSFrederick Mayle   } else {
1857*9712c20fSFrederick Mayle     printf("  (no context)\n");
1858*9712c20fSFrederick Mayle     printf("\n");
1859*9712c20fSFrederick Mayle   }
1860*9712c20fSFrederick Mayle 
1861*9712c20fSFrederick Mayle   MinidumpMemoryRegion* memory = GetMemory();
1862*9712c20fSFrederick Mayle   if (memory) {
1863*9712c20fSFrederick Mayle     printf("Stack\n");
1864*9712c20fSFrederick Mayle     memory->Print();
1865*9712c20fSFrederick Mayle   } else {
1866*9712c20fSFrederick Mayle     printf("No stack\n");
1867*9712c20fSFrederick Mayle   }
1868*9712c20fSFrederick Mayle   printf("\n");
1869*9712c20fSFrederick Mayle }
1870*9712c20fSFrederick Mayle 
1871*9712c20fSFrederick Mayle 
1872*9712c20fSFrederick Mayle //
1873*9712c20fSFrederick Mayle // MinidumpThreadList
1874*9712c20fSFrederick Mayle //
1875*9712c20fSFrederick Mayle 
1876*9712c20fSFrederick Mayle 
1877*9712c20fSFrederick Mayle uint32_t MinidumpThreadList::max_threads_ = 4096;
1878*9712c20fSFrederick Mayle 
1879*9712c20fSFrederick Mayle 
MinidumpThreadList(Minidump * minidump)1880*9712c20fSFrederick Mayle MinidumpThreadList::MinidumpThreadList(Minidump* minidump)
1881*9712c20fSFrederick Mayle     : MinidumpStream(minidump),
1882*9712c20fSFrederick Mayle       id_to_thread_map_(),
1883*9712c20fSFrederick Mayle       threads_(NULL),
1884*9712c20fSFrederick Mayle       thread_count_(0) {
1885*9712c20fSFrederick Mayle }
1886*9712c20fSFrederick Mayle 
1887*9712c20fSFrederick Mayle 
~MinidumpThreadList()1888*9712c20fSFrederick Mayle MinidumpThreadList::~MinidumpThreadList() {
1889*9712c20fSFrederick Mayle   delete threads_;
1890*9712c20fSFrederick Mayle }
1891*9712c20fSFrederick Mayle 
1892*9712c20fSFrederick Mayle 
Read(uint32_t expected_size)1893*9712c20fSFrederick Mayle bool MinidumpThreadList::Read(uint32_t expected_size) {
1894*9712c20fSFrederick Mayle   // Invalidate cached data.
1895*9712c20fSFrederick Mayle   id_to_thread_map_.clear();
1896*9712c20fSFrederick Mayle   delete threads_;
1897*9712c20fSFrederick Mayle   threads_ = NULL;
1898*9712c20fSFrederick Mayle   thread_count_ = 0;
1899*9712c20fSFrederick Mayle 
1900*9712c20fSFrederick Mayle   valid_ = false;
1901*9712c20fSFrederick Mayle 
1902*9712c20fSFrederick Mayle   uint32_t thread_count;
1903*9712c20fSFrederick Mayle   if (expected_size < sizeof(thread_count)) {
1904*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpThreadList count size mismatch, " <<
1905*9712c20fSFrederick Mayle                     expected_size << " < " << sizeof(thread_count);
1906*9712c20fSFrederick Mayle     return false;
1907*9712c20fSFrederick Mayle   }
1908*9712c20fSFrederick Mayle   if (!minidump_->ReadBytes(&thread_count, sizeof(thread_count))) {
1909*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpThreadList cannot read thread count";
1910*9712c20fSFrederick Mayle     return false;
1911*9712c20fSFrederick Mayle   }
1912*9712c20fSFrederick Mayle 
1913*9712c20fSFrederick Mayle   if (minidump_->swap())
1914*9712c20fSFrederick Mayle     Swap(&thread_count);
1915*9712c20fSFrederick Mayle 
1916*9712c20fSFrederick Mayle   if (thread_count > numeric_limits<uint32_t>::max() / sizeof(MDRawThread)) {
1917*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpThreadList thread count " << thread_count <<
1918*9712c20fSFrederick Mayle                     " would cause multiplication overflow";
1919*9712c20fSFrederick Mayle     return false;
1920*9712c20fSFrederick Mayle   }
1921*9712c20fSFrederick Mayle 
1922*9712c20fSFrederick Mayle   if (expected_size != sizeof(thread_count) +
1923*9712c20fSFrederick Mayle                        thread_count * sizeof(MDRawThread)) {
1924*9712c20fSFrederick Mayle     // may be padded with 4 bytes on 64bit ABIs for alignment
1925*9712c20fSFrederick Mayle     if (expected_size == sizeof(thread_count) + 4 +
1926*9712c20fSFrederick Mayle                          thread_count * sizeof(MDRawThread)) {
1927*9712c20fSFrederick Mayle       uint32_t useless;
1928*9712c20fSFrederick Mayle       if (!minidump_->ReadBytes(&useless, 4)) {
1929*9712c20fSFrederick Mayle         BPLOG(ERROR) << "MinidumpThreadList cannot read threadlist padded "
1930*9712c20fSFrederick Mayle                         "bytes";
1931*9712c20fSFrederick Mayle         return false;
1932*9712c20fSFrederick Mayle       }
1933*9712c20fSFrederick Mayle     } else {
1934*9712c20fSFrederick Mayle       BPLOG(ERROR) << "MinidumpThreadList size mismatch, " << expected_size <<
1935*9712c20fSFrederick Mayle                     " != " << sizeof(thread_count) +
1936*9712c20fSFrederick Mayle                     thread_count * sizeof(MDRawThread);
1937*9712c20fSFrederick Mayle       return false;
1938*9712c20fSFrederick Mayle     }
1939*9712c20fSFrederick Mayle   }
1940*9712c20fSFrederick Mayle 
1941*9712c20fSFrederick Mayle 
1942*9712c20fSFrederick Mayle   if (thread_count > max_threads_) {
1943*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpThreadList count " << thread_count <<
1944*9712c20fSFrederick Mayle                     " exceeds maximum " << max_threads_;
1945*9712c20fSFrederick Mayle     return false;
1946*9712c20fSFrederick Mayle   }
1947*9712c20fSFrederick Mayle 
1948*9712c20fSFrederick Mayle   if (thread_count != 0) {
1949*9712c20fSFrederick Mayle     scoped_ptr<MinidumpThreads> threads(
1950*9712c20fSFrederick Mayle         new MinidumpThreads(thread_count, MinidumpThread(minidump_)));
1951*9712c20fSFrederick Mayle 
1952*9712c20fSFrederick Mayle     for (unsigned int thread_index = 0;
1953*9712c20fSFrederick Mayle          thread_index < thread_count;
1954*9712c20fSFrederick Mayle          ++thread_index) {
1955*9712c20fSFrederick Mayle       MinidumpThread* thread = &(*threads)[thread_index];
1956*9712c20fSFrederick Mayle 
1957*9712c20fSFrederick Mayle       // Assume that the file offset is correct after the last read.
1958*9712c20fSFrederick Mayle       if (!thread->Read()) {
1959*9712c20fSFrederick Mayle         BPLOG(ERROR) << "MinidumpThreadList cannot read thread " <<
1960*9712c20fSFrederick Mayle                         thread_index << "/" << thread_count;
1961*9712c20fSFrederick Mayle         return false;
1962*9712c20fSFrederick Mayle       }
1963*9712c20fSFrederick Mayle 
1964*9712c20fSFrederick Mayle       uint32_t thread_id;
1965*9712c20fSFrederick Mayle       if (!thread->GetThreadID(&thread_id)) {
1966*9712c20fSFrederick Mayle         BPLOG(ERROR) << "MinidumpThreadList cannot get thread ID for thread " <<
1967*9712c20fSFrederick Mayle                         thread_index << "/" << thread_count;
1968*9712c20fSFrederick Mayle         return false;
1969*9712c20fSFrederick Mayle       }
1970*9712c20fSFrederick Mayle 
1971*9712c20fSFrederick Mayle       if (GetThreadByID(thread_id)) {
1972*9712c20fSFrederick Mayle         // Another thread with this ID is already in the list.  Data error.
1973*9712c20fSFrederick Mayle         BPLOG(ERROR) << "MinidumpThreadList found multiple threads with ID " <<
1974*9712c20fSFrederick Mayle                         HexString(thread_id) << " at thread " <<
1975*9712c20fSFrederick Mayle                         thread_index << "/" << thread_count;
1976*9712c20fSFrederick Mayle         return false;
1977*9712c20fSFrederick Mayle       }
1978*9712c20fSFrederick Mayle       id_to_thread_map_[thread_id] = thread;
1979*9712c20fSFrederick Mayle     }
1980*9712c20fSFrederick Mayle 
1981*9712c20fSFrederick Mayle     threads_ = threads.release();
1982*9712c20fSFrederick Mayle   }
1983*9712c20fSFrederick Mayle 
1984*9712c20fSFrederick Mayle   thread_count_ = thread_count;
1985*9712c20fSFrederick Mayle 
1986*9712c20fSFrederick Mayle   valid_ = true;
1987*9712c20fSFrederick Mayle   return true;
1988*9712c20fSFrederick Mayle }
1989*9712c20fSFrederick Mayle 
1990*9712c20fSFrederick Mayle 
GetThreadAtIndex(unsigned int index) const1991*9712c20fSFrederick Mayle MinidumpThread* MinidumpThreadList::GetThreadAtIndex(unsigned int index)
1992*9712c20fSFrederick Mayle     const {
1993*9712c20fSFrederick Mayle   if (!valid_) {
1994*9712c20fSFrederick Mayle     BPLOG(ERROR) << "Invalid MinidumpThreadList for GetThreadAtIndex";
1995*9712c20fSFrederick Mayle     return NULL;
1996*9712c20fSFrederick Mayle   }
1997*9712c20fSFrederick Mayle 
1998*9712c20fSFrederick Mayle   if (index >= thread_count_) {
1999*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpThreadList index out of range: " <<
2000*9712c20fSFrederick Mayle                     index << "/" << thread_count_;
2001*9712c20fSFrederick Mayle     return NULL;
2002*9712c20fSFrederick Mayle   }
2003*9712c20fSFrederick Mayle 
2004*9712c20fSFrederick Mayle   return &(*threads_)[index];
2005*9712c20fSFrederick Mayle }
2006*9712c20fSFrederick Mayle 
2007*9712c20fSFrederick Mayle 
GetThreadByID(uint32_t thread_id)2008*9712c20fSFrederick Mayle MinidumpThread* MinidumpThreadList::GetThreadByID(uint32_t thread_id) {
2009*9712c20fSFrederick Mayle   // Don't check valid_.  Read calls this method before everything is
2010*9712c20fSFrederick Mayle   // validated.  It is safe to not check valid_ here.
2011*9712c20fSFrederick Mayle   return id_to_thread_map_[thread_id];
2012*9712c20fSFrederick Mayle }
2013*9712c20fSFrederick Mayle 
2014*9712c20fSFrederick Mayle 
Print()2015*9712c20fSFrederick Mayle void MinidumpThreadList::Print() {
2016*9712c20fSFrederick Mayle   if (!valid_) {
2017*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpThreadList cannot print invalid data";
2018*9712c20fSFrederick Mayle     return;
2019*9712c20fSFrederick Mayle   }
2020*9712c20fSFrederick Mayle 
2021*9712c20fSFrederick Mayle   printf("MinidumpThreadList\n");
2022*9712c20fSFrederick Mayle   printf("  thread_count = %d\n", thread_count_);
2023*9712c20fSFrederick Mayle   printf("\n");
2024*9712c20fSFrederick Mayle 
2025*9712c20fSFrederick Mayle   for (unsigned int thread_index = 0;
2026*9712c20fSFrederick Mayle        thread_index < thread_count_;
2027*9712c20fSFrederick Mayle        ++thread_index) {
2028*9712c20fSFrederick Mayle     printf("thread[%d]\n", thread_index);
2029*9712c20fSFrederick Mayle 
2030*9712c20fSFrederick Mayle     (*threads_)[thread_index].Print();
2031*9712c20fSFrederick Mayle   }
2032*9712c20fSFrederick Mayle }
2033*9712c20fSFrederick Mayle 
2034*9712c20fSFrederick Mayle //
2035*9712c20fSFrederick Mayle // MinidumpThreadName
2036*9712c20fSFrederick Mayle //
2037*9712c20fSFrederick Mayle 
MinidumpThreadName(Minidump * minidump)2038*9712c20fSFrederick Mayle MinidumpThreadName::MinidumpThreadName(Minidump* minidump)
2039*9712c20fSFrederick Mayle     : MinidumpObject(minidump),
2040*9712c20fSFrederick Mayle       thread_name_valid_(false),
2041*9712c20fSFrederick Mayle       thread_name_(),
2042*9712c20fSFrederick Mayle       name_(NULL) {}
2043*9712c20fSFrederick Mayle 
~MinidumpThreadName()2044*9712c20fSFrederick Mayle MinidumpThreadName::~MinidumpThreadName() {
2045*9712c20fSFrederick Mayle   delete name_;
2046*9712c20fSFrederick Mayle }
2047*9712c20fSFrederick Mayle 
Read()2048*9712c20fSFrederick Mayle bool MinidumpThreadName::Read() {
2049*9712c20fSFrederick Mayle   // Invalidate cached data.
2050*9712c20fSFrederick Mayle   delete name_;
2051*9712c20fSFrederick Mayle   name_ = NULL;
2052*9712c20fSFrederick Mayle 
2053*9712c20fSFrederick Mayle   valid_ = false;
2054*9712c20fSFrederick Mayle 
2055*9712c20fSFrederick Mayle   if (!minidump_->ReadBytes(&thread_name_, sizeof(thread_name_))) {
2056*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpThreadName cannot read thread name";
2057*9712c20fSFrederick Mayle     return false;
2058*9712c20fSFrederick Mayle   }
2059*9712c20fSFrederick Mayle 
2060*9712c20fSFrederick Mayle   if (minidump_->swap()) {
2061*9712c20fSFrederick Mayle     Swap(&thread_name_.thread_id);
2062*9712c20fSFrederick Mayle     Swap(&thread_name_.thread_name_rva);
2063*9712c20fSFrederick Mayle   }
2064*9712c20fSFrederick Mayle 
2065*9712c20fSFrederick Mayle   thread_name_valid_ = true;
2066*9712c20fSFrederick Mayle   return true;
2067*9712c20fSFrederick Mayle }
2068*9712c20fSFrederick Mayle 
ReadAuxiliaryData()2069*9712c20fSFrederick Mayle bool MinidumpThreadName::ReadAuxiliaryData() {
2070*9712c20fSFrederick Mayle   if (!thread_name_valid_) {
2071*9712c20fSFrederick Mayle     BPLOG(ERROR) << "Invalid MinidumpThreadName for ReadAuxiliaryData";
2072*9712c20fSFrederick Mayle     return false;
2073*9712c20fSFrederick Mayle   }
2074*9712c20fSFrederick Mayle 
2075*9712c20fSFrederick Mayle   // On 32-bit systems, check that the RVA64 is within range (off_t is 32 bits).
2076*9712c20fSFrederick Mayle   if (thread_name_.thread_name_rva > numeric_limits<off_t>::max()) {
2077*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpThreadName RVA64 out of range";
2078*9712c20fSFrederick Mayle     return false;
2079*9712c20fSFrederick Mayle   }
2080*9712c20fSFrederick Mayle 
2081*9712c20fSFrederick Mayle   // Read the thread name.
2082*9712c20fSFrederick Mayle   const off_t thread_name_rva_offset =
2083*9712c20fSFrederick Mayle       static_cast<off_t>(thread_name_.thread_name_rva);
2084*9712c20fSFrederick Mayle   name_ = minidump_->ReadString(thread_name_rva_offset);
2085*9712c20fSFrederick Mayle   if (!name_) {
2086*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpThreadName could not read name";
2087*9712c20fSFrederick Mayle     return false;
2088*9712c20fSFrederick Mayle   }
2089*9712c20fSFrederick Mayle 
2090*9712c20fSFrederick Mayle   // At this point, we have enough info for the thread name to be valid.
2091*9712c20fSFrederick Mayle   valid_ = true;
2092*9712c20fSFrederick Mayle   return true;
2093*9712c20fSFrederick Mayle }
2094*9712c20fSFrederick Mayle 
GetThreadID(uint32_t * thread_id) const2095*9712c20fSFrederick Mayle bool MinidumpThreadName::GetThreadID(uint32_t* thread_id) const {
2096*9712c20fSFrederick Mayle   BPLOG_IF(ERROR, !thread_id) << "MinidumpThreadName::GetThreadID requires "
2097*9712c20fSFrederick Mayle                                  "|thread_id|";
2098*9712c20fSFrederick Mayle   assert(thread_id);
2099*9712c20fSFrederick Mayle   *thread_id = 0;
2100*9712c20fSFrederick Mayle 
2101*9712c20fSFrederick Mayle   if (!valid_) {
2102*9712c20fSFrederick Mayle     BPLOG(ERROR) << "Invalid MinidumpThreadName for GetThreadID";
2103*9712c20fSFrederick Mayle     return false;
2104*9712c20fSFrederick Mayle   }
2105*9712c20fSFrederick Mayle 
2106*9712c20fSFrederick Mayle   *thread_id = thread_name_.thread_id;
2107*9712c20fSFrederick Mayle   return true;
2108*9712c20fSFrederick Mayle }
2109*9712c20fSFrederick Mayle 
GetThreadName() const2110*9712c20fSFrederick Mayle string MinidumpThreadName::GetThreadName() const {
2111*9712c20fSFrederick Mayle   if (!valid_) {
2112*9712c20fSFrederick Mayle     BPLOG(ERROR) << "Invalid MinidumpThreadName for GetThreadName";
2113*9712c20fSFrederick Mayle     return "";
2114*9712c20fSFrederick Mayle   }
2115*9712c20fSFrederick Mayle 
2116*9712c20fSFrederick Mayle   return *name_;
2117*9712c20fSFrederick Mayle }
2118*9712c20fSFrederick Mayle 
Print()2119*9712c20fSFrederick Mayle void MinidumpThreadName::Print() {
2120*9712c20fSFrederick Mayle   if (!valid_) {
2121*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpThreadName cannot print invalid data";
2122*9712c20fSFrederick Mayle     return;
2123*9712c20fSFrederick Mayle   }
2124*9712c20fSFrederick Mayle 
2125*9712c20fSFrederick Mayle   printf("MDRawThreadName\n");
2126*9712c20fSFrederick Mayle   printf("  thread_id                   = 0x%x\n", thread_name_.thread_id);
2127*9712c20fSFrederick Mayle   printf("  thread_name_rva             = 0x%" PRIx64 "\n",
2128*9712c20fSFrederick Mayle          thread_name_.thread_name_rva);
2129*9712c20fSFrederick Mayle   printf("  thread_name                 = \"%s\"\n", GetThreadName().c_str());
2130*9712c20fSFrederick Mayle   printf("\n");
2131*9712c20fSFrederick Mayle }
2132*9712c20fSFrederick Mayle 
2133*9712c20fSFrederick Mayle //
2134*9712c20fSFrederick Mayle // MinidumpThreadNameList
2135*9712c20fSFrederick Mayle //
2136*9712c20fSFrederick Mayle 
MinidumpThreadNameList(Minidump * minidump)2137*9712c20fSFrederick Mayle MinidumpThreadNameList::MinidumpThreadNameList(Minidump* minidump)
2138*9712c20fSFrederick Mayle     : MinidumpStream(minidump), thread_names_(NULL), thread_name_count_(0) {}
2139*9712c20fSFrederick Mayle 
~MinidumpThreadNameList()2140*9712c20fSFrederick Mayle MinidumpThreadNameList::~MinidumpThreadNameList() {
2141*9712c20fSFrederick Mayle   delete thread_names_;
2142*9712c20fSFrederick Mayle }
2143*9712c20fSFrederick Mayle 
Read(uint32_t expected_size)2144*9712c20fSFrederick Mayle bool MinidumpThreadNameList::Read(uint32_t expected_size) {
2145*9712c20fSFrederick Mayle   // Invalidate cached data.
2146*9712c20fSFrederick Mayle   delete thread_names_;
2147*9712c20fSFrederick Mayle   thread_names_ = NULL;
2148*9712c20fSFrederick Mayle   thread_name_count_ = 0;
2149*9712c20fSFrederick Mayle 
2150*9712c20fSFrederick Mayle   valid_ = false;
2151*9712c20fSFrederick Mayle 
2152*9712c20fSFrederick Mayle   uint32_t thread_name_count;
2153*9712c20fSFrederick Mayle   if (expected_size < sizeof(thread_name_count)) {
2154*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpThreadNameList count size mismatch, "
2155*9712c20fSFrederick Mayle                  << expected_size << " < " << sizeof(thread_name_count);
2156*9712c20fSFrederick Mayle     return false;
2157*9712c20fSFrederick Mayle   }
2158*9712c20fSFrederick Mayle   if (!minidump_->ReadBytes(&thread_name_count, sizeof(thread_name_count))) {
2159*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpThreadNameList cannot read thread name count";
2160*9712c20fSFrederick Mayle     return false;
2161*9712c20fSFrederick Mayle   }
2162*9712c20fSFrederick Mayle 
2163*9712c20fSFrederick Mayle   if (minidump_->swap())
2164*9712c20fSFrederick Mayle     Swap(&thread_name_count);
2165*9712c20fSFrederick Mayle 
2166*9712c20fSFrederick Mayle   if (thread_name_count >
2167*9712c20fSFrederick Mayle       numeric_limits<uint32_t>::max() / sizeof(MDRawThreadName)) {
2168*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpThreadNameList thread name count "
2169*9712c20fSFrederick Mayle                  << thread_name_count << " would cause multiplication overflow";
2170*9712c20fSFrederick Mayle     return false;
2171*9712c20fSFrederick Mayle   }
2172*9712c20fSFrederick Mayle 
2173*9712c20fSFrederick Mayle   if (expected_size !=
2174*9712c20fSFrederick Mayle       sizeof(thread_name_count) + thread_name_count * sizeof(MDRawThreadName)) {
2175*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpThreadNameList size mismatch, " << expected_size
2176*9712c20fSFrederick Mayle                  << " != "
2177*9712c20fSFrederick Mayle                  << sizeof(thread_name_count) +
2178*9712c20fSFrederick Mayle                         thread_name_count * sizeof(MDRawThreadName);
2179*9712c20fSFrederick Mayle     return false;
2180*9712c20fSFrederick Mayle   }
2181*9712c20fSFrederick Mayle 
2182*9712c20fSFrederick Mayle   if (thread_name_count > MinidumpThreadList::max_threads()) {
2183*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpThreadNameList count " << thread_name_count
2184*9712c20fSFrederick Mayle                  << " exceeds maximum " << MinidumpThreadList::max_threads();
2185*9712c20fSFrederick Mayle     return false;
2186*9712c20fSFrederick Mayle   }
2187*9712c20fSFrederick Mayle 
2188*9712c20fSFrederick Mayle   if (thread_name_count != 0) {
2189*9712c20fSFrederick Mayle     scoped_ptr<MinidumpThreadNames> thread_names(new MinidumpThreadNames(
2190*9712c20fSFrederick Mayle         thread_name_count, MinidumpThreadName(minidump_)));
2191*9712c20fSFrederick Mayle 
2192*9712c20fSFrederick Mayle     for (unsigned int thread_name_index = 0;
2193*9712c20fSFrederick Mayle          thread_name_index < thread_name_count; ++thread_name_index) {
2194*9712c20fSFrederick Mayle       MinidumpThreadName* thread_name = &(*thread_names)[thread_name_index];
2195*9712c20fSFrederick Mayle 
2196*9712c20fSFrederick Mayle       // Assume that the file offset is correct after the last read.
2197*9712c20fSFrederick Mayle       if (!thread_name->Read()) {
2198*9712c20fSFrederick Mayle         BPLOG(ERROR) << "MinidumpThreadNameList cannot read thread name "
2199*9712c20fSFrederick Mayle                      << thread_name_index << "/" << thread_name_count;
2200*9712c20fSFrederick Mayle         return false;
2201*9712c20fSFrederick Mayle       }
2202*9712c20fSFrederick Mayle     }
2203*9712c20fSFrederick Mayle 
2204*9712c20fSFrederick Mayle     for (unsigned int thread_name_index = 0;
2205*9712c20fSFrederick Mayle          thread_name_index < thread_name_count; ++thread_name_index) {
2206*9712c20fSFrederick Mayle       MinidumpThreadName* thread_name = &(*thread_names)[thread_name_index];
2207*9712c20fSFrederick Mayle 
2208*9712c20fSFrederick Mayle       if (!thread_name->ReadAuxiliaryData() && !thread_name->valid()) {
2209*9712c20fSFrederick Mayle         BPLOG(ERROR) << "MinidumpThreadNameList cannot read thread name "
2210*9712c20fSFrederick Mayle                      << thread_name_index << "/" << thread_name_count;
2211*9712c20fSFrederick Mayle         return false;
2212*9712c20fSFrederick Mayle       }
2213*9712c20fSFrederick Mayle     }
2214*9712c20fSFrederick Mayle 
2215*9712c20fSFrederick Mayle     thread_names_ = thread_names.release();
2216*9712c20fSFrederick Mayle   }
2217*9712c20fSFrederick Mayle 
2218*9712c20fSFrederick Mayle   thread_name_count_ = thread_name_count;
2219*9712c20fSFrederick Mayle 
2220*9712c20fSFrederick Mayle   valid_ = true;
2221*9712c20fSFrederick Mayle   return true;
2222*9712c20fSFrederick Mayle }
2223*9712c20fSFrederick Mayle 
GetThreadNameAtIndex(unsigned int index) const2224*9712c20fSFrederick Mayle MinidumpThreadName* MinidumpThreadNameList::GetThreadNameAtIndex(
2225*9712c20fSFrederick Mayle     unsigned int index) const {
2226*9712c20fSFrederick Mayle   if (!valid_) {
2227*9712c20fSFrederick Mayle     BPLOG(ERROR) << "Invalid MinidumpThreadNameList for GetThreadNameAtIndex";
2228*9712c20fSFrederick Mayle     return NULL;
2229*9712c20fSFrederick Mayle   }
2230*9712c20fSFrederick Mayle 
2231*9712c20fSFrederick Mayle   if (index >= thread_name_count_) {
2232*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpThreadNameList index out of range: " << index
2233*9712c20fSFrederick Mayle                  << "/" << thread_name_count_;
2234*9712c20fSFrederick Mayle     return NULL;
2235*9712c20fSFrederick Mayle   }
2236*9712c20fSFrederick Mayle 
2237*9712c20fSFrederick Mayle   return &(*thread_names_)[index];
2238*9712c20fSFrederick Mayle }
2239*9712c20fSFrederick Mayle 
Print()2240*9712c20fSFrederick Mayle void MinidumpThreadNameList::Print() {
2241*9712c20fSFrederick Mayle   if (!valid_) {
2242*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpThreadNameList cannot print invalid data";
2243*9712c20fSFrederick Mayle     return;
2244*9712c20fSFrederick Mayle   }
2245*9712c20fSFrederick Mayle 
2246*9712c20fSFrederick Mayle   printf("MinidumpThreadNameList\n");
2247*9712c20fSFrederick Mayle   printf("  thread_name_count = %d\n", thread_name_count_);
2248*9712c20fSFrederick Mayle   printf("\n");
2249*9712c20fSFrederick Mayle 
2250*9712c20fSFrederick Mayle   for (unsigned int thread_name_index = 0;
2251*9712c20fSFrederick Mayle        thread_name_index < thread_name_count_; ++thread_name_index) {
2252*9712c20fSFrederick Mayle     printf("thread_name[%d]\n", thread_name_index);
2253*9712c20fSFrederick Mayle 
2254*9712c20fSFrederick Mayle     (*thread_names_)[thread_name_index].Print();
2255*9712c20fSFrederick Mayle   }
2256*9712c20fSFrederick Mayle }
2257*9712c20fSFrederick Mayle 
2258*9712c20fSFrederick Mayle //
2259*9712c20fSFrederick Mayle // MinidumpModule
2260*9712c20fSFrederick Mayle //
2261*9712c20fSFrederick Mayle 
2262*9712c20fSFrederick Mayle 
2263*9712c20fSFrederick Mayle uint32_t MinidumpModule::max_cv_bytes_ = 32768;
2264*9712c20fSFrederick Mayle uint32_t MinidumpModule::max_misc_bytes_ = 32768;
2265*9712c20fSFrederick Mayle 
2266*9712c20fSFrederick Mayle 
MinidumpModule(Minidump * minidump)2267*9712c20fSFrederick Mayle MinidumpModule::MinidumpModule(Minidump* minidump)
2268*9712c20fSFrederick Mayle     : MinidumpObject(minidump),
2269*9712c20fSFrederick Mayle       module_valid_(false),
2270*9712c20fSFrederick Mayle       has_debug_info_(false),
2271*9712c20fSFrederick Mayle       module_(),
2272*9712c20fSFrederick Mayle       name_(NULL),
2273*9712c20fSFrederick Mayle       cv_record_(NULL),
2274*9712c20fSFrederick Mayle       cv_record_signature_(MD_CVINFOUNKNOWN_SIGNATURE),
2275*9712c20fSFrederick Mayle       misc_record_(NULL) {
2276*9712c20fSFrederick Mayle }
2277*9712c20fSFrederick Mayle 
2278*9712c20fSFrederick Mayle 
~MinidumpModule()2279*9712c20fSFrederick Mayle MinidumpModule::~MinidumpModule() {
2280*9712c20fSFrederick Mayle   delete name_;
2281*9712c20fSFrederick Mayle   delete cv_record_;
2282*9712c20fSFrederick Mayle   delete misc_record_;
2283*9712c20fSFrederick Mayle }
2284*9712c20fSFrederick Mayle 
2285*9712c20fSFrederick Mayle 
Read()2286*9712c20fSFrederick Mayle bool MinidumpModule::Read() {
2287*9712c20fSFrederick Mayle   // Invalidate cached data.
2288*9712c20fSFrederick Mayle   delete name_;
2289*9712c20fSFrederick Mayle   name_ = NULL;
2290*9712c20fSFrederick Mayle   delete cv_record_;
2291*9712c20fSFrederick Mayle   cv_record_ = NULL;
2292*9712c20fSFrederick Mayle   cv_record_signature_ = MD_CVINFOUNKNOWN_SIGNATURE;
2293*9712c20fSFrederick Mayle   delete misc_record_;
2294*9712c20fSFrederick Mayle   misc_record_ = NULL;
2295*9712c20fSFrederick Mayle 
2296*9712c20fSFrederick Mayle   module_valid_ = false;
2297*9712c20fSFrederick Mayle   has_debug_info_ = false;
2298*9712c20fSFrederick Mayle   valid_ = false;
2299*9712c20fSFrederick Mayle 
2300*9712c20fSFrederick Mayle   if (!minidump_->ReadBytes(&module_, MD_MODULE_SIZE)) {
2301*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpModule cannot read module";
2302*9712c20fSFrederick Mayle     return false;
2303*9712c20fSFrederick Mayle   }
2304*9712c20fSFrederick Mayle 
2305*9712c20fSFrederick Mayle   if (minidump_->swap()) {
2306*9712c20fSFrederick Mayle     Swap(&module_.base_of_image);
2307*9712c20fSFrederick Mayle     Swap(&module_.size_of_image);
2308*9712c20fSFrederick Mayle     Swap(&module_.checksum);
2309*9712c20fSFrederick Mayle     Swap(&module_.time_date_stamp);
2310*9712c20fSFrederick Mayle     Swap(&module_.module_name_rva);
2311*9712c20fSFrederick Mayle     Swap(&module_.version_info.signature);
2312*9712c20fSFrederick Mayle     Swap(&module_.version_info.struct_version);
2313*9712c20fSFrederick Mayle     Swap(&module_.version_info.file_version_hi);
2314*9712c20fSFrederick Mayle     Swap(&module_.version_info.file_version_lo);
2315*9712c20fSFrederick Mayle     Swap(&module_.version_info.product_version_hi);
2316*9712c20fSFrederick Mayle     Swap(&module_.version_info.product_version_lo);
2317*9712c20fSFrederick Mayle     Swap(&module_.version_info.file_flags_mask);
2318*9712c20fSFrederick Mayle     Swap(&module_.version_info.file_flags);
2319*9712c20fSFrederick Mayle     Swap(&module_.version_info.file_os);
2320*9712c20fSFrederick Mayle     Swap(&module_.version_info.file_type);
2321*9712c20fSFrederick Mayle     Swap(&module_.version_info.file_subtype);
2322*9712c20fSFrederick Mayle     Swap(&module_.version_info.file_date_hi);
2323*9712c20fSFrederick Mayle     Swap(&module_.version_info.file_date_lo);
2324*9712c20fSFrederick Mayle     Swap(&module_.cv_record);
2325*9712c20fSFrederick Mayle     Swap(&module_.misc_record);
2326*9712c20fSFrederick Mayle     // Don't swap reserved fields because their contents are unknown (as
2327*9712c20fSFrederick Mayle     // are their proper widths).
2328*9712c20fSFrederick Mayle   }
2329*9712c20fSFrederick Mayle 
2330*9712c20fSFrederick Mayle   // Check for base + size overflow or undersize.
2331*9712c20fSFrederick Mayle   if (module_.size_of_image == 0 ||
2332*9712c20fSFrederick Mayle       module_.size_of_image >
2333*9712c20fSFrederick Mayle           numeric_limits<uint64_t>::max() - module_.base_of_image) {
2334*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpModule has a module problem, " <<
2335*9712c20fSFrederick Mayle                     HexString(module_.base_of_image) << "+" <<
2336*9712c20fSFrederick Mayle                     HexString(module_.size_of_image);
2337*9712c20fSFrederick Mayle     return false;
2338*9712c20fSFrederick Mayle   }
2339*9712c20fSFrederick Mayle 
2340*9712c20fSFrederick Mayle   module_valid_ = true;
2341*9712c20fSFrederick Mayle   return true;
2342*9712c20fSFrederick Mayle }
2343*9712c20fSFrederick Mayle 
2344*9712c20fSFrederick Mayle 
ReadAuxiliaryData()2345*9712c20fSFrederick Mayle bool MinidumpModule::ReadAuxiliaryData() {
2346*9712c20fSFrederick Mayle   if (!module_valid_) {
2347*9712c20fSFrederick Mayle     BPLOG(ERROR) << "Invalid MinidumpModule for ReadAuxiliaryData";
2348*9712c20fSFrederick Mayle     return false;
2349*9712c20fSFrederick Mayle   }
2350*9712c20fSFrederick Mayle 
2351*9712c20fSFrederick Mayle   // Each module must have a name.
2352*9712c20fSFrederick Mayle   name_ = minidump_->ReadString(module_.module_name_rva);
2353*9712c20fSFrederick Mayle   if (!name_) {
2354*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpModule could not read name";
2355*9712c20fSFrederick Mayle     return false;
2356*9712c20fSFrederick Mayle   }
2357*9712c20fSFrederick Mayle 
2358*9712c20fSFrederick Mayle   // At this point, we have enough info for the module to be valid.
2359*9712c20fSFrederick Mayle   valid_ = true;
2360*9712c20fSFrederick Mayle 
2361*9712c20fSFrederick Mayle   // CodeView and miscellaneous debug records are only required if the
2362*9712c20fSFrederick Mayle   // module indicates that they exist.
2363*9712c20fSFrederick Mayle   if (module_.cv_record.data_size && !GetCVRecord(NULL)) {
2364*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpModule has no CodeView record, "
2365*9712c20fSFrederick Mayle                     "but one was expected";
2366*9712c20fSFrederick Mayle     return false;
2367*9712c20fSFrederick Mayle   }
2368*9712c20fSFrederick Mayle 
2369*9712c20fSFrederick Mayle   if (module_.misc_record.data_size && !GetMiscRecord(NULL)) {
2370*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpModule has no miscellaneous debug record, "
2371*9712c20fSFrederick Mayle                     "but one was expected";
2372*9712c20fSFrederick Mayle     return false;
2373*9712c20fSFrederick Mayle   }
2374*9712c20fSFrederick Mayle 
2375*9712c20fSFrederick Mayle   has_debug_info_ = true;
2376*9712c20fSFrederick Mayle   return true;
2377*9712c20fSFrederick Mayle }
2378*9712c20fSFrederick Mayle 
2379*9712c20fSFrederick Mayle 
code_file() const2380*9712c20fSFrederick Mayle string MinidumpModule::code_file() const {
2381*9712c20fSFrederick Mayle   if (!valid_) {
2382*9712c20fSFrederick Mayle     BPLOG(ERROR) << "Invalid MinidumpModule for code_file";
2383*9712c20fSFrederick Mayle     return "";
2384*9712c20fSFrederick Mayle   }
2385*9712c20fSFrederick Mayle 
2386*9712c20fSFrederick Mayle   return *name_;
2387*9712c20fSFrederick Mayle }
2388*9712c20fSFrederick Mayle 
2389*9712c20fSFrederick Mayle 
code_identifier() const2390*9712c20fSFrederick Mayle string MinidumpModule::code_identifier() const {
2391*9712c20fSFrederick Mayle   if (!valid_) {
2392*9712c20fSFrederick Mayle     BPLOG(ERROR) << "Invalid MinidumpModule for code_identifier";
2393*9712c20fSFrederick Mayle     return "";
2394*9712c20fSFrederick Mayle   }
2395*9712c20fSFrederick Mayle 
2396*9712c20fSFrederick Mayle   if (!has_debug_info_)
2397*9712c20fSFrederick Mayle     return "";
2398*9712c20fSFrederick Mayle 
2399*9712c20fSFrederick Mayle   MinidumpSystemInfo* minidump_system_info = minidump_->GetSystemInfo();
2400*9712c20fSFrederick Mayle   if (!minidump_system_info) {
2401*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpModule code_identifier requires "
2402*9712c20fSFrederick Mayle                     "MinidumpSystemInfo";
2403*9712c20fSFrederick Mayle     return "";
2404*9712c20fSFrederick Mayle   }
2405*9712c20fSFrederick Mayle 
2406*9712c20fSFrederick Mayle   const MDRawSystemInfo* raw_system_info = minidump_system_info->system_info();
2407*9712c20fSFrederick Mayle   if (!raw_system_info) {
2408*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpModule code_identifier requires MDRawSystemInfo";
2409*9712c20fSFrederick Mayle     return "";
2410*9712c20fSFrederick Mayle   }
2411*9712c20fSFrederick Mayle 
2412*9712c20fSFrederick Mayle   string identifier;
2413*9712c20fSFrederick Mayle 
2414*9712c20fSFrederick Mayle   switch (raw_system_info->platform_id) {
2415*9712c20fSFrederick Mayle     case MD_OS_WIN32_NT:
2416*9712c20fSFrederick Mayle     case MD_OS_WIN32_WINDOWS: {
2417*9712c20fSFrederick Mayle       // Use the same format that the MS symbol server uses in filesystem
2418*9712c20fSFrederick Mayle       // hierarchies.
2419*9712c20fSFrederick Mayle       char identifier_string[17];
2420*9712c20fSFrederick Mayle       snprintf(identifier_string, sizeof(identifier_string), "%08X%x",
2421*9712c20fSFrederick Mayle                module_.time_date_stamp, module_.size_of_image);
2422*9712c20fSFrederick Mayle       identifier = identifier_string;
2423*9712c20fSFrederick Mayle       break;
2424*9712c20fSFrederick Mayle     }
2425*9712c20fSFrederick Mayle 
2426*9712c20fSFrederick Mayle     case MD_OS_ANDROID:
2427*9712c20fSFrederick Mayle     case MD_OS_FUCHSIA:
2428*9712c20fSFrederick Mayle     case MD_OS_LINUX: {
2429*9712c20fSFrederick Mayle       // If ELF CodeView data is present, return the debug id.
2430*9712c20fSFrederick Mayle       if (cv_record_ && cv_record_signature_ == MD_CVINFOELF_SIGNATURE) {
2431*9712c20fSFrederick Mayle         const MDCVInfoELF* cv_record_elf =
2432*9712c20fSFrederick Mayle             reinterpret_cast<const MDCVInfoELF*>(&(*cv_record_)[0]);
2433*9712c20fSFrederick Mayle         assert(cv_record_elf->cv_signature == MD_CVINFOELF_SIGNATURE);
2434*9712c20fSFrederick Mayle 
2435*9712c20fSFrederick Mayle         for (unsigned int build_id_index = 0;
2436*9712c20fSFrederick Mayle              build_id_index < (cv_record_->size() - MDCVInfoELF_minsize);
2437*9712c20fSFrederick Mayle              ++build_id_index) {
2438*9712c20fSFrederick Mayle           char hexbyte[3];
2439*9712c20fSFrederick Mayle           snprintf(hexbyte, sizeof(hexbyte), "%02x",
2440*9712c20fSFrederick Mayle                    cv_record_elf->build_id[build_id_index]);
2441*9712c20fSFrederick Mayle           identifier += hexbyte;
2442*9712c20fSFrederick Mayle         }
2443*9712c20fSFrederick Mayle         break;
2444*9712c20fSFrederick Mayle       }
2445*9712c20fSFrederick Mayle       // Otherwise fall through to the case below.
2446*9712c20fSFrederick Mayle       BP_FALLTHROUGH;
2447*9712c20fSFrederick Mayle     }
2448*9712c20fSFrederick Mayle 
2449*9712c20fSFrederick Mayle     case MD_OS_MAC_OS_X:
2450*9712c20fSFrederick Mayle     case MD_OS_IOS:
2451*9712c20fSFrederick Mayle     case MD_OS_SOLARIS:
2452*9712c20fSFrederick Mayle     case MD_OS_NACL:
2453*9712c20fSFrederick Mayle     case MD_OS_PS3: {
2454*9712c20fSFrederick Mayle       // TODO(mmentovai): support uuid extension if present, otherwise fall
2455*9712c20fSFrederick Mayle       // back to version (from LC_ID_DYLIB?), otherwise fall back to something
2456*9712c20fSFrederick Mayle       // else.
2457*9712c20fSFrederick Mayle       identifier = "id";
2458*9712c20fSFrederick Mayle       break;
2459*9712c20fSFrederick Mayle     }
2460*9712c20fSFrederick Mayle 
2461*9712c20fSFrederick Mayle     default: {
2462*9712c20fSFrederick Mayle       // Without knowing what OS generated the dump, we can't generate a good
2463*9712c20fSFrederick Mayle       // identifier.  Return an empty string, signalling failure.
2464*9712c20fSFrederick Mayle       BPLOG(ERROR) << "MinidumpModule code_identifier requires known platform, "
2465*9712c20fSFrederick Mayle                       "found " << HexString(raw_system_info->platform_id);
2466*9712c20fSFrederick Mayle       break;
2467*9712c20fSFrederick Mayle     }
2468*9712c20fSFrederick Mayle   }
2469*9712c20fSFrederick Mayle 
2470*9712c20fSFrederick Mayle   return identifier;
2471*9712c20fSFrederick Mayle }
2472*9712c20fSFrederick Mayle 
2473*9712c20fSFrederick Mayle 
debug_file() const2474*9712c20fSFrederick Mayle string MinidumpModule::debug_file() const {
2475*9712c20fSFrederick Mayle   if (!valid_) {
2476*9712c20fSFrederick Mayle     BPLOG(ERROR) << "Invalid MinidumpModule for debug_file";
2477*9712c20fSFrederick Mayle     return "";
2478*9712c20fSFrederick Mayle   }
2479*9712c20fSFrederick Mayle 
2480*9712c20fSFrederick Mayle   if (!has_debug_info_)
2481*9712c20fSFrederick Mayle     return "";
2482*9712c20fSFrederick Mayle 
2483*9712c20fSFrederick Mayle   string file;
2484*9712c20fSFrederick Mayle   // Prefer the CodeView record if present.
2485*9712c20fSFrederick Mayle   if (cv_record_) {
2486*9712c20fSFrederick Mayle     if (cv_record_signature_ == MD_CVINFOPDB70_SIGNATURE) {
2487*9712c20fSFrederick Mayle       // It's actually an MDCVInfoPDB70 structure.
2488*9712c20fSFrederick Mayle       const MDCVInfoPDB70* cv_record_70 =
2489*9712c20fSFrederick Mayle           reinterpret_cast<const MDCVInfoPDB70*>(&(*cv_record_)[0]);
2490*9712c20fSFrederick Mayle       assert(cv_record_70->cv_signature == MD_CVINFOPDB70_SIGNATURE);
2491*9712c20fSFrederick Mayle 
2492*9712c20fSFrederick Mayle       // GetCVRecord guarantees pdb_file_name is null-terminated.
2493*9712c20fSFrederick Mayle       file = reinterpret_cast<const char*>(cv_record_70->pdb_file_name);
2494*9712c20fSFrederick Mayle     } else if (cv_record_signature_ == MD_CVINFOPDB20_SIGNATURE) {
2495*9712c20fSFrederick Mayle       // It's actually an MDCVInfoPDB20 structure.
2496*9712c20fSFrederick Mayle       const MDCVInfoPDB20* cv_record_20 =
2497*9712c20fSFrederick Mayle           reinterpret_cast<const MDCVInfoPDB20*>(&(*cv_record_)[0]);
2498*9712c20fSFrederick Mayle       assert(cv_record_20->cv_header.signature == MD_CVINFOPDB20_SIGNATURE);
2499*9712c20fSFrederick Mayle 
2500*9712c20fSFrederick Mayle       // GetCVRecord guarantees pdb_file_name is null-terminated.
2501*9712c20fSFrederick Mayle       file = reinterpret_cast<const char*>(cv_record_20->pdb_file_name);
2502*9712c20fSFrederick Mayle     } else if (cv_record_signature_ == MD_CVINFOELF_SIGNATURE) {
2503*9712c20fSFrederick Mayle       // It's actually an MDCVInfoELF structure.
2504*9712c20fSFrederick Mayle       assert(reinterpret_cast<const MDCVInfoELF*>(&(*cv_record_)[0])->
2505*9712c20fSFrederick Mayle           cv_signature == MD_CVINFOELF_SIGNATURE);
2506*9712c20fSFrederick Mayle 
2507*9712c20fSFrederick Mayle       // For MDCVInfoELF, the debug file is the code file.
2508*9712c20fSFrederick Mayle       file = *name_;
2509*9712c20fSFrederick Mayle     }
2510*9712c20fSFrederick Mayle 
2511*9712c20fSFrederick Mayle     // If there's a CodeView record but it doesn't match a known signature,
2512*9712c20fSFrederick Mayle     // try the miscellaneous record.
2513*9712c20fSFrederick Mayle   }
2514*9712c20fSFrederick Mayle 
2515*9712c20fSFrederick Mayle   if (file.empty()) {
2516*9712c20fSFrederick Mayle     // No usable CodeView record.  Try the miscellaneous debug record.
2517*9712c20fSFrederick Mayle     if (misc_record_) {
2518*9712c20fSFrederick Mayle       const MDImageDebugMisc* misc_record =
2519*9712c20fSFrederick Mayle           reinterpret_cast<const MDImageDebugMisc*>(&(*misc_record_)[0]);
2520*9712c20fSFrederick Mayle       if (!misc_record->unicode) {
2521*9712c20fSFrederick Mayle         // If it's not Unicode, just stuff it into the string.  It's unclear
2522*9712c20fSFrederick Mayle         // if misc_record->data is 0-terminated, so use an explicit size.
2523*9712c20fSFrederick Mayle         file = string(
2524*9712c20fSFrederick Mayle             reinterpret_cast<const char*>(misc_record->data),
2525*9712c20fSFrederick Mayle             module_.misc_record.data_size - MDImageDebugMisc_minsize);
2526*9712c20fSFrederick Mayle       } else {
2527*9712c20fSFrederick Mayle         // There's a misc_record but it encodes the debug filename in UTF-16.
2528*9712c20fSFrederick Mayle         // (Actually, because miscellaneous records are so old, it's probably
2529*9712c20fSFrederick Mayle         // UCS-2.)  Convert it to UTF-8 for congruity with the other strings
2530*9712c20fSFrederick Mayle         // that this method (and all other methods in the Minidump family)
2531*9712c20fSFrederick Mayle         // return.
2532*9712c20fSFrederick Mayle 
2533*9712c20fSFrederick Mayle         size_t bytes =
2534*9712c20fSFrederick Mayle             module_.misc_record.data_size - MDImageDebugMisc_minsize;
2535*9712c20fSFrederick Mayle         if (bytes % 2 == 0) {
2536*9712c20fSFrederick Mayle           size_t utf16_words = bytes / 2;
2537*9712c20fSFrederick Mayle 
2538*9712c20fSFrederick Mayle           // UTF16ToUTF8 expects a vector<uint16_t>, so create a temporary one
2539*9712c20fSFrederick Mayle           // and copy the UTF-16 data into it.
2540*9712c20fSFrederick Mayle           vector<uint16_t> string_utf16(utf16_words);
2541*9712c20fSFrederick Mayle           if (utf16_words)
2542*9712c20fSFrederick Mayle             memcpy(&string_utf16[0], &misc_record->data, bytes);
2543*9712c20fSFrederick Mayle 
2544*9712c20fSFrederick Mayle           // GetMiscRecord already byte-swapped the data[] field if it contains
2545*9712c20fSFrederick Mayle           // UTF-16, so pass false as the swap argument.
2546*9712c20fSFrederick Mayle           scoped_ptr<string> new_file(UTF16ToUTF8(string_utf16, false));
2547*9712c20fSFrederick Mayle           if (new_file.get() != nullptr) {
2548*9712c20fSFrederick Mayle             file = *new_file;
2549*9712c20fSFrederick Mayle           }
2550*9712c20fSFrederick Mayle         }
2551*9712c20fSFrederick Mayle       }
2552*9712c20fSFrederick Mayle     }
2553*9712c20fSFrederick Mayle   }
2554*9712c20fSFrederick Mayle 
2555*9712c20fSFrederick Mayle   // Relatively common case
2556*9712c20fSFrederick Mayle   BPLOG_IF(INFO, file.empty()) << "MinidumpModule could not determine "
2557*9712c20fSFrederick Mayle                                   "debug_file for " << *name_;
2558*9712c20fSFrederick Mayle 
2559*9712c20fSFrederick Mayle   return file;
2560*9712c20fSFrederick Mayle }
2561*9712c20fSFrederick Mayle 
guid_and_age_to_debug_id(const MDGUID & guid,uint32_t age)2562*9712c20fSFrederick Mayle static string guid_and_age_to_debug_id(const MDGUID& guid,
2563*9712c20fSFrederick Mayle                                        uint32_t age) {
2564*9712c20fSFrederick Mayle   char identifier_string[41];
2565*9712c20fSFrederick Mayle   snprintf(identifier_string, sizeof(identifier_string),
2566*9712c20fSFrederick Mayle            "%08X%04X%04X%02X%02X%02X%02X%02X%02X%02X%02X%x",
2567*9712c20fSFrederick Mayle            guid.data1,
2568*9712c20fSFrederick Mayle            guid.data2,
2569*9712c20fSFrederick Mayle            guid.data3,
2570*9712c20fSFrederick Mayle            guid.data4[0],
2571*9712c20fSFrederick Mayle            guid.data4[1],
2572*9712c20fSFrederick Mayle            guid.data4[2],
2573*9712c20fSFrederick Mayle            guid.data4[3],
2574*9712c20fSFrederick Mayle            guid.data4[4],
2575*9712c20fSFrederick Mayle            guid.data4[5],
2576*9712c20fSFrederick Mayle            guid.data4[6],
2577*9712c20fSFrederick Mayle            guid.data4[7],
2578*9712c20fSFrederick Mayle            age);
2579*9712c20fSFrederick Mayle   return identifier_string;
2580*9712c20fSFrederick Mayle }
2581*9712c20fSFrederick Mayle 
debug_identifier() const2582*9712c20fSFrederick Mayle string MinidumpModule::debug_identifier() const {
2583*9712c20fSFrederick Mayle   if (!valid_) {
2584*9712c20fSFrederick Mayle     BPLOG(ERROR) << "Invalid MinidumpModule for debug_identifier";
2585*9712c20fSFrederick Mayle     return "";
2586*9712c20fSFrederick Mayle   }
2587*9712c20fSFrederick Mayle 
2588*9712c20fSFrederick Mayle   if (!has_debug_info_)
2589*9712c20fSFrederick Mayle     return "";
2590*9712c20fSFrederick Mayle 
2591*9712c20fSFrederick Mayle   string identifier;
2592*9712c20fSFrederick Mayle 
2593*9712c20fSFrederick Mayle   // Use the CodeView record if present.
2594*9712c20fSFrederick Mayle   if (cv_record_) {
2595*9712c20fSFrederick Mayle     if (cv_record_signature_ == MD_CVINFOPDB70_SIGNATURE) {
2596*9712c20fSFrederick Mayle       // It's actually an MDCVInfoPDB70 structure.
2597*9712c20fSFrederick Mayle       const MDCVInfoPDB70* cv_record_70 =
2598*9712c20fSFrederick Mayle           reinterpret_cast<const MDCVInfoPDB70*>(&(*cv_record_)[0]);
2599*9712c20fSFrederick Mayle       assert(cv_record_70->cv_signature == MD_CVINFOPDB70_SIGNATURE);
2600*9712c20fSFrederick Mayle 
2601*9712c20fSFrederick Mayle       // Use the same format that the MS symbol server uses in filesystem
2602*9712c20fSFrederick Mayle       // hierarchies.
2603*9712c20fSFrederick Mayle       identifier = guid_and_age_to_debug_id(cv_record_70->signature,
2604*9712c20fSFrederick Mayle                                             cv_record_70->age);
2605*9712c20fSFrederick Mayle     } else if (cv_record_signature_ == MD_CVINFOPDB20_SIGNATURE) {
2606*9712c20fSFrederick Mayle       // It's actually an MDCVInfoPDB20 structure.
2607*9712c20fSFrederick Mayle       const MDCVInfoPDB20* cv_record_20 =
2608*9712c20fSFrederick Mayle           reinterpret_cast<const MDCVInfoPDB20*>(&(*cv_record_)[0]);
2609*9712c20fSFrederick Mayle       assert(cv_record_20->cv_header.signature == MD_CVINFOPDB20_SIGNATURE);
2610*9712c20fSFrederick Mayle 
2611*9712c20fSFrederick Mayle       // Use the same format that the MS symbol server uses in filesystem
2612*9712c20fSFrederick Mayle       // hierarchies.
2613*9712c20fSFrederick Mayle       char identifier_string[17];
2614*9712c20fSFrederick Mayle       snprintf(identifier_string, sizeof(identifier_string),
2615*9712c20fSFrederick Mayle                "%08X%x", cv_record_20->signature, cv_record_20->age);
2616*9712c20fSFrederick Mayle       identifier = identifier_string;
2617*9712c20fSFrederick Mayle     } else if (cv_record_signature_ == MD_CVINFOELF_SIGNATURE) {
2618*9712c20fSFrederick Mayle       // It's actually an MDCVInfoELF structure.
2619*9712c20fSFrederick Mayle       const MDCVInfoELF* cv_record_elf =
2620*9712c20fSFrederick Mayle           reinterpret_cast<const MDCVInfoELF*>(&(*cv_record_)[0]);
2621*9712c20fSFrederick Mayle       assert(cv_record_elf->cv_signature == MD_CVINFOELF_SIGNATURE);
2622*9712c20fSFrederick Mayle 
2623*9712c20fSFrederick Mayle       // For backwards-compatibility, stuff as many bytes as will fit into
2624*9712c20fSFrederick Mayle       // a MDGUID and use the MS symbol server format as MDCVInfoPDB70 does
2625*9712c20fSFrederick Mayle       // with age = 0. Historically Breakpad would do this during dump
2626*9712c20fSFrederick Mayle       // writing to fit the build id data into a MDCVInfoPDB70 struct.
2627*9712c20fSFrederick Mayle       // The full build id is available by calling code_identifier.
2628*9712c20fSFrederick Mayle       MDGUID guid = {0};
2629*9712c20fSFrederick Mayle       memcpy(&guid, &cv_record_elf->build_id,
2630*9712c20fSFrederick Mayle              std::min(cv_record_->size() - MDCVInfoELF_minsize,
2631*9712c20fSFrederick Mayle                       sizeof(MDGUID)));
2632*9712c20fSFrederick Mayle       identifier = guid_and_age_to_debug_id(guid, 0);
2633*9712c20fSFrederick Mayle     }
2634*9712c20fSFrederick Mayle   }
2635*9712c20fSFrederick Mayle 
2636*9712c20fSFrederick Mayle   // TODO(mmentovai): if there's no usable CodeView record, there might be a
2637*9712c20fSFrederick Mayle   // miscellaneous debug record.  It only carries a filename, though, and no
2638*9712c20fSFrederick Mayle   // identifier.  I'm not sure what the right thing to do for the identifier
2639*9712c20fSFrederick Mayle   // is in that case, but I don't expect to find many modules without a
2640*9712c20fSFrederick Mayle   // CodeView record (or some other Breakpad extension structure in place of
2641*9712c20fSFrederick Mayle   // a CodeView record).  Treat it as an error (empty identifier) for now.
2642*9712c20fSFrederick Mayle 
2643*9712c20fSFrederick Mayle   // TODO(mmentovai): on the Mac, provide fallbacks as in code_identifier().
2644*9712c20fSFrederick Mayle 
2645*9712c20fSFrederick Mayle   // Relatively common case
2646*9712c20fSFrederick Mayle   BPLOG_IF(INFO, identifier.empty()) << "MinidumpModule could not determine "
2647*9712c20fSFrederick Mayle                                         "debug_identifier for " << *name_;
2648*9712c20fSFrederick Mayle 
2649*9712c20fSFrederick Mayle   return identifier;
2650*9712c20fSFrederick Mayle }
2651*9712c20fSFrederick Mayle 
2652*9712c20fSFrederick Mayle 
version() const2653*9712c20fSFrederick Mayle string MinidumpModule::version() const {
2654*9712c20fSFrederick Mayle   if (!valid_) {
2655*9712c20fSFrederick Mayle     BPLOG(ERROR) << "Invalid MinidumpModule for version";
2656*9712c20fSFrederick Mayle     return "";
2657*9712c20fSFrederick Mayle   }
2658*9712c20fSFrederick Mayle 
2659*9712c20fSFrederick Mayle   string version;
2660*9712c20fSFrederick Mayle 
2661*9712c20fSFrederick Mayle   if (module_.version_info.signature == MD_VSFIXEDFILEINFO_SIGNATURE &&
2662*9712c20fSFrederick Mayle       module_.version_info.struct_version & MD_VSFIXEDFILEINFO_VERSION) {
2663*9712c20fSFrederick Mayle     char version_string[24];
2664*9712c20fSFrederick Mayle     snprintf(version_string, sizeof(version_string), "%u.%u.%u.%u",
2665*9712c20fSFrederick Mayle              module_.version_info.file_version_hi >> 16,
2666*9712c20fSFrederick Mayle              module_.version_info.file_version_hi & 0xffff,
2667*9712c20fSFrederick Mayle              module_.version_info.file_version_lo >> 16,
2668*9712c20fSFrederick Mayle              module_.version_info.file_version_lo & 0xffff);
2669*9712c20fSFrederick Mayle     version = version_string;
2670*9712c20fSFrederick Mayle   }
2671*9712c20fSFrederick Mayle 
2672*9712c20fSFrederick Mayle   // TODO(mmentovai): possibly support other struct types in place of
2673*9712c20fSFrederick Mayle   // the one used with MD_VSFIXEDFILEINFO_SIGNATURE.  We can possibly use
2674*9712c20fSFrederick Mayle   // a different structure that better represents versioning facilities on
2675*9712c20fSFrederick Mayle   // Mac OS X and Linux, instead of forcing them to adhere to the dotted
2676*9712c20fSFrederick Mayle   // quad of 16-bit ints that Windows uses.
2677*9712c20fSFrederick Mayle 
2678*9712c20fSFrederick Mayle   BPLOG_IF(INFO, version.empty()) << "MinidumpModule could not determine "
2679*9712c20fSFrederick Mayle                                      "version for " << *name_;
2680*9712c20fSFrederick Mayle 
2681*9712c20fSFrederick Mayle   return version;
2682*9712c20fSFrederick Mayle }
2683*9712c20fSFrederick Mayle 
2684*9712c20fSFrederick Mayle 
Copy() const2685*9712c20fSFrederick Mayle CodeModule* MinidumpModule::Copy() const {
2686*9712c20fSFrederick Mayle   return new BasicCodeModule(this);
2687*9712c20fSFrederick Mayle }
2688*9712c20fSFrederick Mayle 
2689*9712c20fSFrederick Mayle 
shrink_down_delta() const2690*9712c20fSFrederick Mayle uint64_t MinidumpModule::shrink_down_delta() const {
2691*9712c20fSFrederick Mayle   return 0;
2692*9712c20fSFrederick Mayle }
2693*9712c20fSFrederick Mayle 
SetShrinkDownDelta(uint64_t shrink_down_delta)2694*9712c20fSFrederick Mayle void MinidumpModule::SetShrinkDownDelta(uint64_t shrink_down_delta) {
2695*9712c20fSFrederick Mayle   // Not implemented
2696*9712c20fSFrederick Mayle   assert(false);
2697*9712c20fSFrederick Mayle }
2698*9712c20fSFrederick Mayle 
2699*9712c20fSFrederick Mayle 
GetCVRecord(uint32_t * size)2700*9712c20fSFrederick Mayle const uint8_t* MinidumpModule::GetCVRecord(uint32_t* size) {
2701*9712c20fSFrederick Mayle   if (!module_valid_) {
2702*9712c20fSFrederick Mayle     BPLOG(ERROR) << "Invalid MinidumpModule for GetCVRecord";
2703*9712c20fSFrederick Mayle     return NULL;
2704*9712c20fSFrederick Mayle   }
2705*9712c20fSFrederick Mayle 
2706*9712c20fSFrederick Mayle   if (!cv_record_) {
2707*9712c20fSFrederick Mayle     // This just guards against 0-sized CodeView records; more specific checks
2708*9712c20fSFrederick Mayle     // are used when the signature is checked against various structure types.
2709*9712c20fSFrederick Mayle     if (module_.cv_record.data_size == 0) {
2710*9712c20fSFrederick Mayle       return NULL;
2711*9712c20fSFrederick Mayle     }
2712*9712c20fSFrederick Mayle 
2713*9712c20fSFrederick Mayle     if (!minidump_->SeekSet(module_.cv_record.rva)) {
2714*9712c20fSFrederick Mayle       BPLOG(ERROR) << "MinidumpModule could not seek to CodeView record";
2715*9712c20fSFrederick Mayle       return NULL;
2716*9712c20fSFrederick Mayle     }
2717*9712c20fSFrederick Mayle 
2718*9712c20fSFrederick Mayle     if (module_.cv_record.data_size > max_cv_bytes_) {
2719*9712c20fSFrederick Mayle       BPLOG(ERROR) << "MinidumpModule CodeView record size " <<
2720*9712c20fSFrederick Mayle                       module_.cv_record.data_size << " exceeds maximum " <<
2721*9712c20fSFrederick Mayle                       max_cv_bytes_;
2722*9712c20fSFrederick Mayle       return NULL;
2723*9712c20fSFrederick Mayle     }
2724*9712c20fSFrederick Mayle 
2725*9712c20fSFrederick Mayle     // Allocating something that will be accessed as MDCVInfoPDB70 or
2726*9712c20fSFrederick Mayle     // MDCVInfoPDB20 but is allocated as uint8_t[] can cause alignment
2727*9712c20fSFrederick Mayle     // problems.  x86 and ppc are able to cope, though.  This allocation
2728*9712c20fSFrederick Mayle     // style is needed because the MDCVInfoPDB70 or MDCVInfoPDB20 are
2729*9712c20fSFrederick Mayle     // variable-sized due to their pdb_file_name fields; these structures
2730*9712c20fSFrederick Mayle     // are not MDCVInfoPDB70_minsize or MDCVInfoPDB20_minsize and treating
2731*9712c20fSFrederick Mayle     // them as such would result in incomplete structures or overruns.
2732*9712c20fSFrederick Mayle     scoped_ptr< vector<uint8_t> > cv_record(
2733*9712c20fSFrederick Mayle         new vector<uint8_t>(module_.cv_record.data_size));
2734*9712c20fSFrederick Mayle 
2735*9712c20fSFrederick Mayle     if (!minidump_->ReadBytes(&(*cv_record)[0], module_.cv_record.data_size)) {
2736*9712c20fSFrederick Mayle       BPLOG(ERROR) << "MinidumpModule could not read CodeView record";
2737*9712c20fSFrederick Mayle       return NULL;
2738*9712c20fSFrederick Mayle     }
2739*9712c20fSFrederick Mayle 
2740*9712c20fSFrederick Mayle     uint32_t signature = MD_CVINFOUNKNOWN_SIGNATURE;
2741*9712c20fSFrederick Mayle     if (module_.cv_record.data_size > sizeof(signature)) {
2742*9712c20fSFrederick Mayle       MDCVInfoPDB70* cv_record_signature =
2743*9712c20fSFrederick Mayle           reinterpret_cast<MDCVInfoPDB70*>(&(*cv_record)[0]);
2744*9712c20fSFrederick Mayle       signature = cv_record_signature->cv_signature;
2745*9712c20fSFrederick Mayle       if (minidump_->swap())
2746*9712c20fSFrederick Mayle         Swap(&signature);
2747*9712c20fSFrederick Mayle     }
2748*9712c20fSFrederick Mayle 
2749*9712c20fSFrederick Mayle     if (signature == MD_CVINFOPDB70_SIGNATURE) {
2750*9712c20fSFrederick Mayle       // Now that the structure type is known, recheck the size,
2751*9712c20fSFrederick Mayle       // ensuring at least one byte for the null terminator.
2752*9712c20fSFrederick Mayle       if (MDCVInfoPDB70_minsize + 1 > module_.cv_record.data_size) {
2753*9712c20fSFrederick Mayle         BPLOG(ERROR) << "MinidumpModule CodeView7 record size mismatch, " <<
2754*9712c20fSFrederick Mayle                         MDCVInfoPDB70_minsize << " > " <<
2755*9712c20fSFrederick Mayle                         module_.cv_record.data_size;
2756*9712c20fSFrederick Mayle         return NULL;
2757*9712c20fSFrederick Mayle       }
2758*9712c20fSFrederick Mayle 
2759*9712c20fSFrederick Mayle       if (minidump_->swap()) {
2760*9712c20fSFrederick Mayle         MDCVInfoPDB70* cv_record_70 =
2761*9712c20fSFrederick Mayle             reinterpret_cast<MDCVInfoPDB70*>(&(*cv_record)[0]);
2762*9712c20fSFrederick Mayle         Swap(&cv_record_70->cv_signature);
2763*9712c20fSFrederick Mayle         Swap(&cv_record_70->signature);
2764*9712c20fSFrederick Mayle         Swap(&cv_record_70->age);
2765*9712c20fSFrederick Mayle         // Don't swap cv_record_70.pdb_file_name because it's an array of 8-bit
2766*9712c20fSFrederick Mayle         // quantities.  (It's a path, is it UTF-8?)
2767*9712c20fSFrederick Mayle       }
2768*9712c20fSFrederick Mayle 
2769*9712c20fSFrederick Mayle       // The last field of either structure is null-terminated 8-bit character
2770*9712c20fSFrederick Mayle       // data.  Ensure that it's null-terminated.
2771*9712c20fSFrederick Mayle       if ((*cv_record)[module_.cv_record.data_size - 1] != '\0') {
2772*9712c20fSFrederick Mayle         BPLOG(ERROR) << "MinidumpModule CodeView7 record string is not "
2773*9712c20fSFrederick Mayle                         "0-terminated";
2774*9712c20fSFrederick Mayle         return NULL;
2775*9712c20fSFrederick Mayle       }
2776*9712c20fSFrederick Mayle     } else if (signature == MD_CVINFOPDB20_SIGNATURE) {
2777*9712c20fSFrederick Mayle       // Now that the structure type is known, recheck the size,
2778*9712c20fSFrederick Mayle       // ensuring at least one byte for the null terminator.
2779*9712c20fSFrederick Mayle       if (MDCVInfoPDB20_minsize + 1 > module_.cv_record.data_size) {
2780*9712c20fSFrederick Mayle         BPLOG(ERROR) << "MinidumpModule CodeView2 record size mismatch, " <<
2781*9712c20fSFrederick Mayle                         MDCVInfoPDB20_minsize << " > " <<
2782*9712c20fSFrederick Mayle                         module_.cv_record.data_size;
2783*9712c20fSFrederick Mayle         return NULL;
2784*9712c20fSFrederick Mayle       }
2785*9712c20fSFrederick Mayle       if (minidump_->swap()) {
2786*9712c20fSFrederick Mayle         MDCVInfoPDB20* cv_record_20 =
2787*9712c20fSFrederick Mayle             reinterpret_cast<MDCVInfoPDB20*>(&(*cv_record)[0]);
2788*9712c20fSFrederick Mayle         Swap(&cv_record_20->cv_header.signature);
2789*9712c20fSFrederick Mayle         Swap(&cv_record_20->cv_header.offset);
2790*9712c20fSFrederick Mayle         Swap(&cv_record_20->signature);
2791*9712c20fSFrederick Mayle         Swap(&cv_record_20->age);
2792*9712c20fSFrederick Mayle         // Don't swap cv_record_20.pdb_file_name because it's an array of 8-bit
2793*9712c20fSFrederick Mayle         // quantities.  (It's a path, is it UTF-8?)
2794*9712c20fSFrederick Mayle       }
2795*9712c20fSFrederick Mayle 
2796*9712c20fSFrederick Mayle       // The last field of either structure is null-terminated 8-bit character
2797*9712c20fSFrederick Mayle       // data.  Ensure that it's null-terminated.
2798*9712c20fSFrederick Mayle       if ((*cv_record)[module_.cv_record.data_size - 1] != '\0') {
2799*9712c20fSFrederick Mayle         BPLOG(ERROR) << "MindumpModule CodeView2 record string is not "
2800*9712c20fSFrederick Mayle                         "0-terminated";
2801*9712c20fSFrederick Mayle         return NULL;
2802*9712c20fSFrederick Mayle       }
2803*9712c20fSFrederick Mayle     } else if (signature == MD_CVINFOELF_SIGNATURE) {
2804*9712c20fSFrederick Mayle       // Now that the structure type is known, recheck the size.
2805*9712c20fSFrederick Mayle       if (MDCVInfoELF_minsize > module_.cv_record.data_size) {
2806*9712c20fSFrederick Mayle         BPLOG(ERROR) << "MinidumpModule CodeViewELF record size mismatch, " <<
2807*9712c20fSFrederick Mayle                         MDCVInfoELF_minsize << " > " <<
2808*9712c20fSFrederick Mayle                         module_.cv_record.data_size;
2809*9712c20fSFrederick Mayle         return NULL;
2810*9712c20fSFrederick Mayle       }
2811*9712c20fSFrederick Mayle       if (minidump_->swap()) {
2812*9712c20fSFrederick Mayle         MDCVInfoELF* cv_record_elf =
2813*9712c20fSFrederick Mayle             reinterpret_cast<MDCVInfoELF*>(&(*cv_record)[0]);
2814*9712c20fSFrederick Mayle         Swap(&cv_record_elf->cv_signature);
2815*9712c20fSFrederick Mayle       }
2816*9712c20fSFrederick Mayle     }
2817*9712c20fSFrederick Mayle 
2818*9712c20fSFrederick Mayle     // If the signature doesn't match something above, it's not something
2819*9712c20fSFrederick Mayle     // that Breakpad can presently handle directly.  Because some modules in
2820*9712c20fSFrederick Mayle     // the wild contain such CodeView records as MD_CVINFOCV50_SIGNATURE,
2821*9712c20fSFrederick Mayle     // don't bail out here - allow the data to be returned to the user,
2822*9712c20fSFrederick Mayle     // although byte-swapping can't be done.
2823*9712c20fSFrederick Mayle 
2824*9712c20fSFrederick Mayle     // Store the vector type because that's how storage was allocated, but
2825*9712c20fSFrederick Mayle     // return it casted to uint8_t*.
2826*9712c20fSFrederick Mayle     cv_record_ = cv_record.release();
2827*9712c20fSFrederick Mayle     cv_record_signature_ = signature;
2828*9712c20fSFrederick Mayle   }
2829*9712c20fSFrederick Mayle 
2830*9712c20fSFrederick Mayle   if (size)
2831*9712c20fSFrederick Mayle     *size = module_.cv_record.data_size;
2832*9712c20fSFrederick Mayle 
2833*9712c20fSFrederick Mayle   return &(*cv_record_)[0];
2834*9712c20fSFrederick Mayle }
2835*9712c20fSFrederick Mayle 
2836*9712c20fSFrederick Mayle 
GetMiscRecord(uint32_t * size)2837*9712c20fSFrederick Mayle const MDImageDebugMisc* MinidumpModule::GetMiscRecord(uint32_t* size) {
2838*9712c20fSFrederick Mayle   if (!module_valid_) {
2839*9712c20fSFrederick Mayle     BPLOG(ERROR) << "Invalid MinidumpModule for GetMiscRecord";
2840*9712c20fSFrederick Mayle     return NULL;
2841*9712c20fSFrederick Mayle   }
2842*9712c20fSFrederick Mayle 
2843*9712c20fSFrederick Mayle   if (!misc_record_) {
2844*9712c20fSFrederick Mayle     if (module_.misc_record.data_size == 0) {
2845*9712c20fSFrederick Mayle       return NULL;
2846*9712c20fSFrederick Mayle     }
2847*9712c20fSFrederick Mayle 
2848*9712c20fSFrederick Mayle     if (MDImageDebugMisc_minsize > module_.misc_record.data_size) {
2849*9712c20fSFrederick Mayle       BPLOG(ERROR) << "MinidumpModule miscellaneous debugging record "
2850*9712c20fSFrederick Mayle                       "size mismatch, " << MDImageDebugMisc_minsize << " > " <<
2851*9712c20fSFrederick Mayle                       module_.misc_record.data_size;
2852*9712c20fSFrederick Mayle       return NULL;
2853*9712c20fSFrederick Mayle     }
2854*9712c20fSFrederick Mayle 
2855*9712c20fSFrederick Mayle     if (!minidump_->SeekSet(module_.misc_record.rva)) {
2856*9712c20fSFrederick Mayle       BPLOG(ERROR) << "MinidumpModule could not seek to miscellaneous "
2857*9712c20fSFrederick Mayle                       "debugging record";
2858*9712c20fSFrederick Mayle       return NULL;
2859*9712c20fSFrederick Mayle     }
2860*9712c20fSFrederick Mayle 
2861*9712c20fSFrederick Mayle     if (module_.misc_record.data_size > max_misc_bytes_) {
2862*9712c20fSFrederick Mayle       BPLOG(ERROR) << "MinidumpModule miscellaneous debugging record size " <<
2863*9712c20fSFrederick Mayle                       module_.misc_record.data_size << " exceeds maximum " <<
2864*9712c20fSFrederick Mayle                       max_misc_bytes_;
2865*9712c20fSFrederick Mayle       return NULL;
2866*9712c20fSFrederick Mayle     }
2867*9712c20fSFrederick Mayle 
2868*9712c20fSFrederick Mayle     // Allocating something that will be accessed as MDImageDebugMisc but
2869*9712c20fSFrederick Mayle     // is allocated as uint8_t[] can cause alignment problems.  x86 and
2870*9712c20fSFrederick Mayle     // ppc are able to cope, though.  This allocation style is needed
2871*9712c20fSFrederick Mayle     // because the MDImageDebugMisc is variable-sized due to its data field;
2872*9712c20fSFrederick Mayle     // this structure is not MDImageDebugMisc_minsize and treating it as such
2873*9712c20fSFrederick Mayle     // would result in an incomplete structure or an overrun.
2874*9712c20fSFrederick Mayle     scoped_ptr< vector<uint8_t> > misc_record_mem(
2875*9712c20fSFrederick Mayle         new vector<uint8_t>(module_.misc_record.data_size));
2876*9712c20fSFrederick Mayle     MDImageDebugMisc* misc_record =
2877*9712c20fSFrederick Mayle         reinterpret_cast<MDImageDebugMisc*>(&(*misc_record_mem)[0]);
2878*9712c20fSFrederick Mayle 
2879*9712c20fSFrederick Mayle     if (!minidump_->ReadBytes(misc_record, module_.misc_record.data_size)) {
2880*9712c20fSFrederick Mayle       BPLOG(ERROR) << "MinidumpModule could not read miscellaneous debugging "
2881*9712c20fSFrederick Mayle                       "record";
2882*9712c20fSFrederick Mayle       return NULL;
2883*9712c20fSFrederick Mayle     }
2884*9712c20fSFrederick Mayle 
2885*9712c20fSFrederick Mayle     if (minidump_->swap()) {
2886*9712c20fSFrederick Mayle       Swap(&misc_record->data_type);
2887*9712c20fSFrederick Mayle       Swap(&misc_record->length);
2888*9712c20fSFrederick Mayle       // Don't swap misc_record.unicode because it's an 8-bit quantity.
2889*9712c20fSFrederick Mayle       // Don't swap the reserved fields for the same reason, and because
2890*9712c20fSFrederick Mayle       // they don't contain any valid data.
2891*9712c20fSFrederick Mayle       if (misc_record->unicode) {
2892*9712c20fSFrederick Mayle         // There is a potential alignment problem, but shouldn't be a problem
2893*9712c20fSFrederick Mayle         // in practice due to the layout of MDImageDebugMisc.
2894*9712c20fSFrederick Mayle         uint16_t* data16 = reinterpret_cast<uint16_t*>(&(misc_record->data));
2895*9712c20fSFrederick Mayle         size_t dataBytes = module_.misc_record.data_size -
2896*9712c20fSFrederick Mayle                            MDImageDebugMisc_minsize;
2897*9712c20fSFrederick Mayle         Swap(data16, dataBytes);
2898*9712c20fSFrederick Mayle       }
2899*9712c20fSFrederick Mayle     }
2900*9712c20fSFrederick Mayle 
2901*9712c20fSFrederick Mayle     if (module_.misc_record.data_size != misc_record->length) {
2902*9712c20fSFrederick Mayle       BPLOG(ERROR) << "MinidumpModule miscellaneous debugging record data "
2903*9712c20fSFrederick Mayle                       "size mismatch, " << module_.misc_record.data_size <<
2904*9712c20fSFrederick Mayle                       " != " << misc_record->length;
2905*9712c20fSFrederick Mayle       return NULL;
2906*9712c20fSFrederick Mayle     }
2907*9712c20fSFrederick Mayle 
2908*9712c20fSFrederick Mayle     // Store the vector type because that's how storage was allocated, but
2909*9712c20fSFrederick Mayle     // return it casted to MDImageDebugMisc*.
2910*9712c20fSFrederick Mayle     misc_record_ = misc_record_mem.release();
2911*9712c20fSFrederick Mayle   }
2912*9712c20fSFrederick Mayle 
2913*9712c20fSFrederick Mayle   if (size)
2914*9712c20fSFrederick Mayle     *size = module_.misc_record.data_size;
2915*9712c20fSFrederick Mayle 
2916*9712c20fSFrederick Mayle   return reinterpret_cast<MDImageDebugMisc*>(&(*misc_record_)[0]);
2917*9712c20fSFrederick Mayle }
2918*9712c20fSFrederick Mayle 
2919*9712c20fSFrederick Mayle 
Print()2920*9712c20fSFrederick Mayle void MinidumpModule::Print() {
2921*9712c20fSFrederick Mayle   if (!valid_) {
2922*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpModule cannot print invalid data";
2923*9712c20fSFrederick Mayle     return;
2924*9712c20fSFrederick Mayle   }
2925*9712c20fSFrederick Mayle 
2926*9712c20fSFrederick Mayle   printf("MDRawModule\n");
2927*9712c20fSFrederick Mayle   printf("  base_of_image                   = 0x%" PRIx64 "\n",
2928*9712c20fSFrederick Mayle          module_.base_of_image);
2929*9712c20fSFrederick Mayle   printf("  size_of_image                   = 0x%x\n",
2930*9712c20fSFrederick Mayle          module_.size_of_image);
2931*9712c20fSFrederick Mayle   printf("  checksum                        = 0x%x\n",
2932*9712c20fSFrederick Mayle          module_.checksum);
2933*9712c20fSFrederick Mayle   printf("  time_date_stamp                 = 0x%x %s\n",
2934*9712c20fSFrederick Mayle          module_.time_date_stamp,
2935*9712c20fSFrederick Mayle          TimeTToUTCString(module_.time_date_stamp).c_str());
2936*9712c20fSFrederick Mayle   printf("  module_name_rva                 = 0x%x\n",
2937*9712c20fSFrederick Mayle          module_.module_name_rva);
2938*9712c20fSFrederick Mayle   printf("  version_info.signature          = 0x%x\n",
2939*9712c20fSFrederick Mayle          module_.version_info.signature);
2940*9712c20fSFrederick Mayle   printf("  version_info.struct_version     = 0x%x\n",
2941*9712c20fSFrederick Mayle          module_.version_info.struct_version);
2942*9712c20fSFrederick Mayle   printf("  version_info.file_version       = 0x%x:0x%x\n",
2943*9712c20fSFrederick Mayle          module_.version_info.file_version_hi,
2944*9712c20fSFrederick Mayle          module_.version_info.file_version_lo);
2945*9712c20fSFrederick Mayle   printf("  version_info.product_version    = 0x%x:0x%x\n",
2946*9712c20fSFrederick Mayle          module_.version_info.product_version_hi,
2947*9712c20fSFrederick Mayle          module_.version_info.product_version_lo);
2948*9712c20fSFrederick Mayle   printf("  version_info.file_flags_mask    = 0x%x\n",
2949*9712c20fSFrederick Mayle          module_.version_info.file_flags_mask);
2950*9712c20fSFrederick Mayle   printf("  version_info.file_flags         = 0x%x\n",
2951*9712c20fSFrederick Mayle          module_.version_info.file_flags);
2952*9712c20fSFrederick Mayle   printf("  version_info.file_os            = 0x%x\n",
2953*9712c20fSFrederick Mayle          module_.version_info.file_os);
2954*9712c20fSFrederick Mayle   printf("  version_info.file_type          = 0x%x\n",
2955*9712c20fSFrederick Mayle          module_.version_info.file_type);
2956*9712c20fSFrederick Mayle   printf("  version_info.file_subtype       = 0x%x\n",
2957*9712c20fSFrederick Mayle          module_.version_info.file_subtype);
2958*9712c20fSFrederick Mayle   printf("  version_info.file_date          = 0x%x:0x%x\n",
2959*9712c20fSFrederick Mayle          module_.version_info.file_date_hi,
2960*9712c20fSFrederick Mayle          module_.version_info.file_date_lo);
2961*9712c20fSFrederick Mayle   printf("  cv_record.data_size             = %d\n",
2962*9712c20fSFrederick Mayle          module_.cv_record.data_size);
2963*9712c20fSFrederick Mayle   printf("  cv_record.rva                   = 0x%x\n",
2964*9712c20fSFrederick Mayle          module_.cv_record.rva);
2965*9712c20fSFrederick Mayle   printf("  misc_record.data_size           = %d\n",
2966*9712c20fSFrederick Mayle          module_.misc_record.data_size);
2967*9712c20fSFrederick Mayle   printf("  misc_record.rva                 = 0x%x\n",
2968*9712c20fSFrederick Mayle          module_.misc_record.rva);
2969*9712c20fSFrederick Mayle 
2970*9712c20fSFrederick Mayle   printf("  (code_file)                     = \"%s\"\n", code_file().c_str());
2971*9712c20fSFrederick Mayle   printf("  (code_identifier)               = \"%s\"\n",
2972*9712c20fSFrederick Mayle          code_identifier().c_str());
2973*9712c20fSFrederick Mayle 
2974*9712c20fSFrederick Mayle   uint32_t cv_record_size;
2975*9712c20fSFrederick Mayle   const uint8_t* cv_record = GetCVRecord(&cv_record_size);
2976*9712c20fSFrederick Mayle   if (cv_record) {
2977*9712c20fSFrederick Mayle     if (cv_record_signature_ == MD_CVINFOPDB70_SIGNATURE) {
2978*9712c20fSFrederick Mayle       const MDCVInfoPDB70* cv_record_70 =
2979*9712c20fSFrederick Mayle           reinterpret_cast<const MDCVInfoPDB70*>(cv_record);
2980*9712c20fSFrederick Mayle       assert(cv_record_70->cv_signature == MD_CVINFOPDB70_SIGNATURE);
2981*9712c20fSFrederick Mayle 
2982*9712c20fSFrederick Mayle       printf("  (cv_record).cv_signature        = 0x%x\n",
2983*9712c20fSFrederick Mayle              cv_record_70->cv_signature);
2984*9712c20fSFrederick Mayle       printf("  (cv_record).signature           = %s\n",
2985*9712c20fSFrederick Mayle              MDGUIDToString(cv_record_70->signature).c_str());
2986*9712c20fSFrederick Mayle       printf("  (cv_record).age                 = %d\n",
2987*9712c20fSFrederick Mayle              cv_record_70->age);
2988*9712c20fSFrederick Mayle       printf("  (cv_record).pdb_file_name       = \"%s\"\n",
2989*9712c20fSFrederick Mayle              cv_record_70->pdb_file_name);
2990*9712c20fSFrederick Mayle     } else if (cv_record_signature_ == MD_CVINFOPDB20_SIGNATURE) {
2991*9712c20fSFrederick Mayle       const MDCVInfoPDB20* cv_record_20 =
2992*9712c20fSFrederick Mayle           reinterpret_cast<const MDCVInfoPDB20*>(cv_record);
2993*9712c20fSFrederick Mayle       assert(cv_record_20->cv_header.signature == MD_CVINFOPDB20_SIGNATURE);
2994*9712c20fSFrederick Mayle 
2995*9712c20fSFrederick Mayle       printf("  (cv_record).cv_header.signature = 0x%x\n",
2996*9712c20fSFrederick Mayle              cv_record_20->cv_header.signature);
2997*9712c20fSFrederick Mayle       printf("  (cv_record).cv_header.offset    = 0x%x\n",
2998*9712c20fSFrederick Mayle              cv_record_20->cv_header.offset);
2999*9712c20fSFrederick Mayle       printf("  (cv_record).signature           = 0x%x %s\n",
3000*9712c20fSFrederick Mayle              cv_record_20->signature,
3001*9712c20fSFrederick Mayle              TimeTToUTCString(cv_record_20->signature).c_str());
3002*9712c20fSFrederick Mayle       printf("  (cv_record).age                 = %d\n",
3003*9712c20fSFrederick Mayle              cv_record_20->age);
3004*9712c20fSFrederick Mayle       printf("  (cv_record).pdb_file_name       = \"%s\"\n",
3005*9712c20fSFrederick Mayle              cv_record_20->pdb_file_name);
3006*9712c20fSFrederick Mayle     } else if (cv_record_signature_ == MD_CVINFOELF_SIGNATURE) {
3007*9712c20fSFrederick Mayle       const MDCVInfoELF* cv_record_elf =
3008*9712c20fSFrederick Mayle           reinterpret_cast<const MDCVInfoELF*>(cv_record);
3009*9712c20fSFrederick Mayle       assert(cv_record_elf->cv_signature == MD_CVINFOELF_SIGNATURE);
3010*9712c20fSFrederick Mayle 
3011*9712c20fSFrederick Mayle       printf("  (cv_record).cv_signature        = 0x%x\n",
3012*9712c20fSFrederick Mayle              cv_record_elf->cv_signature);
3013*9712c20fSFrederick Mayle       printf("  (cv_record).build_id            = ");
3014*9712c20fSFrederick Mayle       for (unsigned int build_id_index = 0;
3015*9712c20fSFrederick Mayle            build_id_index < (cv_record_size - MDCVInfoELF_minsize);
3016*9712c20fSFrederick Mayle            ++build_id_index) {
3017*9712c20fSFrederick Mayle         printf("%02x", cv_record_elf->build_id[build_id_index]);
3018*9712c20fSFrederick Mayle       }
3019*9712c20fSFrederick Mayle       printf("\n");
3020*9712c20fSFrederick Mayle     } else {
3021*9712c20fSFrederick Mayle       printf("  (cv_record)                     = ");
3022*9712c20fSFrederick Mayle       for (unsigned int cv_byte_index = 0;
3023*9712c20fSFrederick Mayle            cv_byte_index < cv_record_size;
3024*9712c20fSFrederick Mayle            ++cv_byte_index) {
3025*9712c20fSFrederick Mayle         printf("%02x", cv_record[cv_byte_index]);
3026*9712c20fSFrederick Mayle       }
3027*9712c20fSFrederick Mayle       printf("\n");
3028*9712c20fSFrederick Mayle     }
3029*9712c20fSFrederick Mayle   } else {
3030*9712c20fSFrederick Mayle     printf("  (cv_record)                     = (null)\n");
3031*9712c20fSFrederick Mayle   }
3032*9712c20fSFrederick Mayle 
3033*9712c20fSFrederick Mayle   const MDImageDebugMisc* misc_record = GetMiscRecord(NULL);
3034*9712c20fSFrederick Mayle   if (misc_record) {
3035*9712c20fSFrederick Mayle     printf("  (misc_record).data_type         = 0x%x\n",
3036*9712c20fSFrederick Mayle            misc_record->data_type);
3037*9712c20fSFrederick Mayle     printf("  (misc_record).length            = 0x%x\n",
3038*9712c20fSFrederick Mayle            misc_record->length);
3039*9712c20fSFrederick Mayle     printf("  (misc_record).unicode           = %d\n",
3040*9712c20fSFrederick Mayle            misc_record->unicode);
3041*9712c20fSFrederick Mayle     if (misc_record->unicode) {
3042*9712c20fSFrederick Mayle       string misc_record_data_utf8;
3043*9712c20fSFrederick Mayle       ConvertUTF16BufferToUTF8String(
3044*9712c20fSFrederick Mayle           reinterpret_cast<const uint16_t*>(misc_record->data),
3045*9712c20fSFrederick Mayle           misc_record->length - offsetof(MDImageDebugMisc, data),
3046*9712c20fSFrederick Mayle           &misc_record_data_utf8,
3047*9712c20fSFrederick Mayle           false);  // already swapped
3048*9712c20fSFrederick Mayle       printf("  (misc_record).data              = \"%s\"\n",
3049*9712c20fSFrederick Mayle              misc_record_data_utf8.c_str());
3050*9712c20fSFrederick Mayle     } else {
3051*9712c20fSFrederick Mayle       printf("  (misc_record).data              = \"%s\"\n",
3052*9712c20fSFrederick Mayle              misc_record->data);
3053*9712c20fSFrederick Mayle     }
3054*9712c20fSFrederick Mayle   } else {
3055*9712c20fSFrederick Mayle     printf("  (misc_record)                   = (null)\n");
3056*9712c20fSFrederick Mayle   }
3057*9712c20fSFrederick Mayle 
3058*9712c20fSFrederick Mayle   printf("  (debug_file)                    = \"%s\"\n", debug_file().c_str());
3059*9712c20fSFrederick Mayle   printf("  (debug_identifier)              = \"%s\"\n",
3060*9712c20fSFrederick Mayle          debug_identifier().c_str());
3061*9712c20fSFrederick Mayle   printf("  (version)                       = \"%s\"\n", version().c_str());
3062*9712c20fSFrederick Mayle   printf("\n");
3063*9712c20fSFrederick Mayle }
3064*9712c20fSFrederick Mayle 
3065*9712c20fSFrederick Mayle 
3066*9712c20fSFrederick Mayle //
3067*9712c20fSFrederick Mayle // MinidumpModuleList
3068*9712c20fSFrederick Mayle //
3069*9712c20fSFrederick Mayle 
3070*9712c20fSFrederick Mayle 
3071*9712c20fSFrederick Mayle uint32_t MinidumpModuleList::max_modules_ = 2048;
3072*9712c20fSFrederick Mayle 
3073*9712c20fSFrederick Mayle 
MinidumpModuleList(Minidump * minidump)3074*9712c20fSFrederick Mayle MinidumpModuleList::MinidumpModuleList(Minidump* minidump)
3075*9712c20fSFrederick Mayle     : MinidumpStream(minidump),
3076*9712c20fSFrederick Mayle       range_map_(new RangeMap<uint64_t, unsigned int>()),
3077*9712c20fSFrederick Mayle       modules_(NULL),
3078*9712c20fSFrederick Mayle       module_count_(0) {
3079*9712c20fSFrederick Mayle   MDOSPlatform platform;
3080*9712c20fSFrederick Mayle   if (minidump_->GetPlatform(&platform) &&
3081*9712c20fSFrederick Mayle       (platform == MD_OS_ANDROID || platform == MD_OS_LINUX)) {
3082*9712c20fSFrederick Mayle     range_map_->SetMergeStrategy(MergeRangeStrategy::kTruncateLower);
3083*9712c20fSFrederick Mayle   }
3084*9712c20fSFrederick Mayle }
3085*9712c20fSFrederick Mayle 
3086*9712c20fSFrederick Mayle 
~MinidumpModuleList()3087*9712c20fSFrederick Mayle MinidumpModuleList::~MinidumpModuleList() {
3088*9712c20fSFrederick Mayle   delete range_map_;
3089*9712c20fSFrederick Mayle   delete modules_;
3090*9712c20fSFrederick Mayle }
3091*9712c20fSFrederick Mayle 
3092*9712c20fSFrederick Mayle 
Read(uint32_t expected_size)3093*9712c20fSFrederick Mayle bool MinidumpModuleList::Read(uint32_t expected_size) {
3094*9712c20fSFrederick Mayle   // Invalidate cached data.
3095*9712c20fSFrederick Mayle   range_map_->Clear();
3096*9712c20fSFrederick Mayle   delete modules_;
3097*9712c20fSFrederick Mayle   modules_ = NULL;
3098*9712c20fSFrederick Mayle   module_count_ = 0;
3099*9712c20fSFrederick Mayle 
3100*9712c20fSFrederick Mayle   valid_ = false;
3101*9712c20fSFrederick Mayle 
3102*9712c20fSFrederick Mayle   uint32_t module_count;
3103*9712c20fSFrederick Mayle   if (expected_size < sizeof(module_count)) {
3104*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpModuleList count size mismatch, " <<
3105*9712c20fSFrederick Mayle                     expected_size << " < " << sizeof(module_count);
3106*9712c20fSFrederick Mayle     return false;
3107*9712c20fSFrederick Mayle   }
3108*9712c20fSFrederick Mayle   if (!minidump_->ReadBytes(&module_count, sizeof(module_count))) {
3109*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpModuleList could not read module count";
3110*9712c20fSFrederick Mayle     return false;
3111*9712c20fSFrederick Mayle   }
3112*9712c20fSFrederick Mayle 
3113*9712c20fSFrederick Mayle   if (minidump_->swap())
3114*9712c20fSFrederick Mayle     Swap(&module_count);
3115*9712c20fSFrederick Mayle 
3116*9712c20fSFrederick Mayle   if (module_count > numeric_limits<uint32_t>::max() / MD_MODULE_SIZE) {
3117*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpModuleList module count " << module_count <<
3118*9712c20fSFrederick Mayle                     " would cause multiplication overflow";
3119*9712c20fSFrederick Mayle     return false;
3120*9712c20fSFrederick Mayle   }
3121*9712c20fSFrederick Mayle 
3122*9712c20fSFrederick Mayle   if (expected_size != sizeof(module_count) +
3123*9712c20fSFrederick Mayle                        module_count * MD_MODULE_SIZE) {
3124*9712c20fSFrederick Mayle     // may be padded with 4 bytes on 64bit ABIs for alignment
3125*9712c20fSFrederick Mayle     if (expected_size == sizeof(module_count) + 4 +
3126*9712c20fSFrederick Mayle                          module_count * MD_MODULE_SIZE) {
3127*9712c20fSFrederick Mayle       uint32_t useless;
3128*9712c20fSFrederick Mayle       if (!minidump_->ReadBytes(&useless, 4)) {
3129*9712c20fSFrederick Mayle         BPLOG(ERROR) << "MinidumpModuleList cannot read modulelist padded "
3130*9712c20fSFrederick Mayle                         "bytes";
3131*9712c20fSFrederick Mayle         return false;
3132*9712c20fSFrederick Mayle       }
3133*9712c20fSFrederick Mayle     } else {
3134*9712c20fSFrederick Mayle       BPLOG(ERROR) << "MinidumpModuleList size mismatch, " << expected_size <<
3135*9712c20fSFrederick Mayle                       " != " << sizeof(module_count) +
3136*9712c20fSFrederick Mayle                       module_count * MD_MODULE_SIZE;
3137*9712c20fSFrederick Mayle       return false;
3138*9712c20fSFrederick Mayle     }
3139*9712c20fSFrederick Mayle   }
3140*9712c20fSFrederick Mayle 
3141*9712c20fSFrederick Mayle   if (module_count > max_modules_) {
3142*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpModuleList count " << module_count <<
3143*9712c20fSFrederick Mayle                     " exceeds maximum " << max_modules_;
3144*9712c20fSFrederick Mayle     return false;
3145*9712c20fSFrederick Mayle   }
3146*9712c20fSFrederick Mayle 
3147*9712c20fSFrederick Mayle   if (module_count != 0) {
3148*9712c20fSFrederick Mayle     scoped_ptr<MinidumpModules> modules(
3149*9712c20fSFrederick Mayle         new MinidumpModules(module_count, MinidumpModule(minidump_)));
3150*9712c20fSFrederick Mayle 
3151*9712c20fSFrederick Mayle     for (uint32_t module_index = 0; module_index < module_count;
3152*9712c20fSFrederick Mayle          ++module_index) {
3153*9712c20fSFrederick Mayle       MinidumpModule* module = &(*modules)[module_index];
3154*9712c20fSFrederick Mayle 
3155*9712c20fSFrederick Mayle       // Assume that the file offset is correct after the last read.
3156*9712c20fSFrederick Mayle       if (!module->Read()) {
3157*9712c20fSFrederick Mayle         BPLOG(ERROR) << "MinidumpModuleList could not read module " <<
3158*9712c20fSFrederick Mayle                         module_index << "/" << module_count;
3159*9712c20fSFrederick Mayle         return false;
3160*9712c20fSFrederick Mayle       }
3161*9712c20fSFrederick Mayle     }
3162*9712c20fSFrederick Mayle 
3163*9712c20fSFrederick Mayle     // Loop through the module list once more to read additional data and
3164*9712c20fSFrederick Mayle     // build the range map.  This is done in a second pass because
3165*9712c20fSFrederick Mayle     // MinidumpModule::ReadAuxiliaryData seeks around, and if it were
3166*9712c20fSFrederick Mayle     // included in the loop above, additional seeks would be needed where
3167*9712c20fSFrederick Mayle     // none are now to read contiguous data.
3168*9712c20fSFrederick Mayle     uint64_t last_end_address = 0;
3169*9712c20fSFrederick Mayle     for (uint32_t module_index = 0; module_index < module_count;
3170*9712c20fSFrederick Mayle          ++module_index) {
3171*9712c20fSFrederick Mayle       MinidumpModule& module = (*modules)[module_index];
3172*9712c20fSFrederick Mayle 
3173*9712c20fSFrederick Mayle       // ReadAuxiliaryData fails if any data that the module indicates should
3174*9712c20fSFrederick Mayle       // exist is missing, but we treat some such cases as valid anyway.  See
3175*9712c20fSFrederick Mayle       // issue #222: if a debugging record is of a format that's too large to
3176*9712c20fSFrederick Mayle       // handle, it shouldn't render the entire dump invalid.  Check module
3177*9712c20fSFrederick Mayle       // validity before giving up.
3178*9712c20fSFrederick Mayle       if (!module.ReadAuxiliaryData() && !module.valid()) {
3179*9712c20fSFrederick Mayle         BPLOG(ERROR) << "MinidumpModuleList could not read required module "
3180*9712c20fSFrederick Mayle                         "auxiliary data for module " <<
3181*9712c20fSFrederick Mayle                         module_index << "/" << module_count;
3182*9712c20fSFrederick Mayle         return false;
3183*9712c20fSFrederick Mayle       }
3184*9712c20fSFrederick Mayle 
3185*9712c20fSFrederick Mayle       // It is safe to use module->code_file() after successfully calling
3186*9712c20fSFrederick Mayle       // module->ReadAuxiliaryData or noting that the module is valid.
3187*9712c20fSFrederick Mayle 
3188*9712c20fSFrederick Mayle       uint64_t base_address = module.base_address();
3189*9712c20fSFrederick Mayle       uint64_t module_size = module.size();
3190*9712c20fSFrederick Mayle       if (base_address == static_cast<uint64_t>(-1)) {
3191*9712c20fSFrederick Mayle         BPLOG(ERROR) << "MinidumpModuleList found bad base address for module "
3192*9712c20fSFrederick Mayle                      << module_index << "/" << module_count << ", "
3193*9712c20fSFrederick Mayle                      << module.code_file();
3194*9712c20fSFrederick Mayle         return false;
3195*9712c20fSFrederick Mayle       }
3196*9712c20fSFrederick Mayle 
3197*9712c20fSFrederick Mayle       // Some minidumps have additional modules in the list that are duplicates.
3198*9712c20fSFrederick Mayle       // Ignore them. See https://crbug.com/838322
3199*9712c20fSFrederick Mayle       uint32_t existing_module_index;
3200*9712c20fSFrederick Mayle       if (range_map_->RetrieveRange(base_address, &existing_module_index,
3201*9712c20fSFrederick Mayle                                     nullptr, nullptr, nullptr) &&
3202*9712c20fSFrederick Mayle           existing_module_index < module_count) {
3203*9712c20fSFrederick Mayle         const MinidumpModule& existing_module =
3204*9712c20fSFrederick Mayle             (*modules)[existing_module_index];
3205*9712c20fSFrederick Mayle         if (existing_module.base_address() == module.base_address() &&
3206*9712c20fSFrederick Mayle             existing_module.size() == module.size() &&
3207*9712c20fSFrederick Mayle             existing_module.code_file() == module.code_file() &&
3208*9712c20fSFrederick Mayle             existing_module.code_identifier() == module.code_identifier()) {
3209*9712c20fSFrederick Mayle           continue;
3210*9712c20fSFrederick Mayle         }
3211*9712c20fSFrederick Mayle       }
3212*9712c20fSFrederick Mayle 
3213*9712c20fSFrederick Mayle       const bool is_android = minidump_->IsAndroid();
3214*9712c20fSFrederick Mayle       if (!StoreRange(module, base_address, module_index, module_count,
3215*9712c20fSFrederick Mayle                       is_android)) {
3216*9712c20fSFrederick Mayle         if (!is_android || base_address >= last_end_address) {
3217*9712c20fSFrederick Mayle           BPLOG(ERROR) << "MinidumpModuleList could not store module "
3218*9712c20fSFrederick Mayle                        << module_index << "/" << module_count << ", "
3219*9712c20fSFrederick Mayle                        << module.code_file() << ", " << HexString(base_address)
3220*9712c20fSFrederick Mayle                        << "+" << HexString(module_size);
3221*9712c20fSFrederick Mayle           return false;
3222*9712c20fSFrederick Mayle         }
3223*9712c20fSFrederick Mayle 
3224*9712c20fSFrederick Mayle         // If failed due to apparent range overlap the cause may be the client
3225*9712c20fSFrederick Mayle         // correction applied for Android packed relocations.  If this is the
3226*9712c20fSFrederick Mayle         // case, back out the client correction and retry.
3227*9712c20fSFrederick Mayle         assert(is_android);
3228*9712c20fSFrederick Mayle         module_size -= last_end_address - base_address;
3229*9712c20fSFrederick Mayle         base_address = last_end_address;
3230*9712c20fSFrederick Mayle         if (!range_map_->StoreRange(base_address, module_size, module_index)) {
3231*9712c20fSFrederick Mayle           BPLOG(ERROR) << "MinidumpModuleList could not store module "
3232*9712c20fSFrederick Mayle                        << module_index << "/" << module_count << ", "
3233*9712c20fSFrederick Mayle                        << module.code_file() << ", " << HexString(base_address)
3234*9712c20fSFrederick Mayle                        << "+" << HexString(module_size) << ", after adjusting";
3235*9712c20fSFrederick Mayle           return false;
3236*9712c20fSFrederick Mayle         }
3237*9712c20fSFrederick Mayle       }
3238*9712c20fSFrederick Mayle       last_end_address = base_address + module_size;
3239*9712c20fSFrederick Mayle     }
3240*9712c20fSFrederick Mayle 
3241*9712c20fSFrederick Mayle     modules_ = modules.release();
3242*9712c20fSFrederick Mayle   }
3243*9712c20fSFrederick Mayle 
3244*9712c20fSFrederick Mayle   module_count_ = module_count;
3245*9712c20fSFrederick Mayle 
3246*9712c20fSFrederick Mayle   valid_ = true;
3247*9712c20fSFrederick Mayle   return true;
3248*9712c20fSFrederick Mayle }
3249*9712c20fSFrederick Mayle 
StoreRange(const MinidumpModule & module,uint64_t base_address,uint32_t module_index,uint32_t module_count,bool is_android)3250*9712c20fSFrederick Mayle bool MinidumpModuleList::StoreRange(const MinidumpModule& module,
3251*9712c20fSFrederick Mayle                                     uint64_t base_address,
3252*9712c20fSFrederick Mayle                                     uint32_t module_index,
3253*9712c20fSFrederick Mayle                                     uint32_t module_count,
3254*9712c20fSFrederick Mayle                                     bool is_android) {
3255*9712c20fSFrederick Mayle   if (range_map_->StoreRange(base_address, module.size(), module_index))
3256*9712c20fSFrederick Mayle     return true;
3257*9712c20fSFrederick Mayle 
3258*9712c20fSFrederick Mayle   // Android's shared memory implementation /dev/ashmem can contain duplicate
3259*9712c20fSFrederick Mayle   // entries for JITted code, so ignore these.
3260*9712c20fSFrederick Mayle   // TODO(wfh): Remove this code when Android is fixed.
3261*9712c20fSFrederick Mayle   // See https://crbug.com/439531
3262*9712c20fSFrederick Mayle   if (is_android && IsDevAshmem(module.code_file())) {
3263*9712c20fSFrederick Mayle     BPLOG(INFO) << "MinidumpModuleList ignoring overlapping module "
3264*9712c20fSFrederick Mayle                 << module_index << "/" << module_count << ", "
3265*9712c20fSFrederick Mayle                 << module.code_file() << ", " << HexString(base_address) << "+"
3266*9712c20fSFrederick Mayle                 << HexString(module.size());
3267*9712c20fSFrederick Mayle     return true;
3268*9712c20fSFrederick Mayle   }
3269*9712c20fSFrederick Mayle 
3270*9712c20fSFrederick Mayle   return false;
3271*9712c20fSFrederick Mayle }
3272*9712c20fSFrederick Mayle 
GetModuleForAddress(uint64_t address) const3273*9712c20fSFrederick Mayle const MinidumpModule* MinidumpModuleList::GetModuleForAddress(
3274*9712c20fSFrederick Mayle     uint64_t address) const {
3275*9712c20fSFrederick Mayle   if (!valid_) {
3276*9712c20fSFrederick Mayle     BPLOG(ERROR) << "Invalid MinidumpModuleList for GetModuleForAddress";
3277*9712c20fSFrederick Mayle     return NULL;
3278*9712c20fSFrederick Mayle   }
3279*9712c20fSFrederick Mayle 
3280*9712c20fSFrederick Mayle   unsigned int module_index;
3281*9712c20fSFrederick Mayle   if (!range_map_->RetrieveRange(address, &module_index, NULL /* base */,
3282*9712c20fSFrederick Mayle                                  NULL /* delta */, NULL /* size */)) {
3283*9712c20fSFrederick Mayle     BPLOG(INFO) << "MinidumpModuleList has no module at " <<
3284*9712c20fSFrederick Mayle                    HexString(address);
3285*9712c20fSFrederick Mayle     return NULL;
3286*9712c20fSFrederick Mayle   }
3287*9712c20fSFrederick Mayle 
3288*9712c20fSFrederick Mayle   return GetModuleAtIndex(module_index);
3289*9712c20fSFrederick Mayle }
3290*9712c20fSFrederick Mayle 
3291*9712c20fSFrederick Mayle 
GetMainModule() const3292*9712c20fSFrederick Mayle const MinidumpModule* MinidumpModuleList::GetMainModule() const {
3293*9712c20fSFrederick Mayle   if (!valid_) {
3294*9712c20fSFrederick Mayle     BPLOG(ERROR) << "Invalid MinidumpModuleList for GetMainModule";
3295*9712c20fSFrederick Mayle     return NULL;
3296*9712c20fSFrederick Mayle   }
3297*9712c20fSFrederick Mayle 
3298*9712c20fSFrederick Mayle   // The main code module is the first one present in a minidump file's
3299*9712c20fSFrederick Mayle   // MDRawModuleList.
3300*9712c20fSFrederick Mayle   return GetModuleAtIndex(0);
3301*9712c20fSFrederick Mayle }
3302*9712c20fSFrederick Mayle 
3303*9712c20fSFrederick Mayle 
GetModuleAtSequence(unsigned int sequence) const3304*9712c20fSFrederick Mayle const MinidumpModule* MinidumpModuleList::GetModuleAtSequence(
3305*9712c20fSFrederick Mayle     unsigned int sequence) const {
3306*9712c20fSFrederick Mayle   if (!valid_) {
3307*9712c20fSFrederick Mayle     BPLOG(ERROR) << "Invalid MinidumpModuleList for GetModuleAtSequence";
3308*9712c20fSFrederick Mayle     return NULL;
3309*9712c20fSFrederick Mayle   }
3310*9712c20fSFrederick Mayle 
3311*9712c20fSFrederick Mayle   if (sequence >= module_count_) {
3312*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpModuleList sequence out of range: " <<
3313*9712c20fSFrederick Mayle                     sequence << "/" << module_count_;
3314*9712c20fSFrederick Mayle     return NULL;
3315*9712c20fSFrederick Mayle   }
3316*9712c20fSFrederick Mayle 
3317*9712c20fSFrederick Mayle   unsigned int module_index;
3318*9712c20fSFrederick Mayle   if (!range_map_->RetrieveRangeAtIndex(sequence, &module_index,
3319*9712c20fSFrederick Mayle                                         NULL /* base */, NULL /* delta */,
3320*9712c20fSFrederick Mayle                                         NULL /* size */)) {
3321*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpModuleList has no module at sequence " << sequence;
3322*9712c20fSFrederick Mayle     return NULL;
3323*9712c20fSFrederick Mayle   }
3324*9712c20fSFrederick Mayle 
3325*9712c20fSFrederick Mayle   return GetModuleAtIndex(module_index);
3326*9712c20fSFrederick Mayle }
3327*9712c20fSFrederick Mayle 
3328*9712c20fSFrederick Mayle 
GetModuleAtIndex(unsigned int index) const3329*9712c20fSFrederick Mayle const MinidumpModule* MinidumpModuleList::GetModuleAtIndex(
3330*9712c20fSFrederick Mayle     unsigned int index) const {
3331*9712c20fSFrederick Mayle   if (!valid_) {
3332*9712c20fSFrederick Mayle     BPLOG(ERROR) << "Invalid MinidumpModuleList for GetModuleAtIndex";
3333*9712c20fSFrederick Mayle     return NULL;
3334*9712c20fSFrederick Mayle   }
3335*9712c20fSFrederick Mayle 
3336*9712c20fSFrederick Mayle   if (index >= module_count_) {
3337*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpModuleList index out of range: " <<
3338*9712c20fSFrederick Mayle                     index << "/" << module_count_;
3339*9712c20fSFrederick Mayle     return NULL;
3340*9712c20fSFrederick Mayle   }
3341*9712c20fSFrederick Mayle 
3342*9712c20fSFrederick Mayle   return &(*modules_)[index];
3343*9712c20fSFrederick Mayle }
3344*9712c20fSFrederick Mayle 
3345*9712c20fSFrederick Mayle 
Copy() const3346*9712c20fSFrederick Mayle const CodeModules* MinidumpModuleList::Copy() const {
3347*9712c20fSFrederick Mayle   return new BasicCodeModules(this, range_map_->GetMergeStrategy());
3348*9712c20fSFrederick Mayle }
3349*9712c20fSFrederick Mayle 
3350*9712c20fSFrederick Mayle vector<linked_ptr<const CodeModule> >
GetShrunkRangeModules() const3351*9712c20fSFrederick Mayle MinidumpModuleList::GetShrunkRangeModules() const {
3352*9712c20fSFrederick Mayle   return vector<linked_ptr<const CodeModule> >();
3353*9712c20fSFrederick Mayle }
3354*9712c20fSFrederick Mayle 
Print()3355*9712c20fSFrederick Mayle void MinidumpModuleList::Print() {
3356*9712c20fSFrederick Mayle   if (!valid_) {
3357*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpModuleList cannot print invalid data";
3358*9712c20fSFrederick Mayle     return;
3359*9712c20fSFrederick Mayle   }
3360*9712c20fSFrederick Mayle 
3361*9712c20fSFrederick Mayle   printf("MinidumpModuleList\n");
3362*9712c20fSFrederick Mayle   printf("  module_count = %d\n", module_count_);
3363*9712c20fSFrederick Mayle   printf("\n");
3364*9712c20fSFrederick Mayle 
3365*9712c20fSFrederick Mayle   for (unsigned int module_index = 0;
3366*9712c20fSFrederick Mayle        module_index < module_count_;
3367*9712c20fSFrederick Mayle        ++module_index) {
3368*9712c20fSFrederick Mayle     printf("module[%d]\n", module_index);
3369*9712c20fSFrederick Mayle 
3370*9712c20fSFrederick Mayle     (*modules_)[module_index].Print();
3371*9712c20fSFrederick Mayle   }
3372*9712c20fSFrederick Mayle }
3373*9712c20fSFrederick Mayle 
3374*9712c20fSFrederick Mayle 
3375*9712c20fSFrederick Mayle //
3376*9712c20fSFrederick Mayle // MinidumpMemoryList
3377*9712c20fSFrederick Mayle //
3378*9712c20fSFrederick Mayle 
3379*9712c20fSFrederick Mayle 
3380*9712c20fSFrederick Mayle uint32_t MinidumpMemoryList::max_regions_ = 4096;
3381*9712c20fSFrederick Mayle 
3382*9712c20fSFrederick Mayle 
MinidumpMemoryList(Minidump * minidump)3383*9712c20fSFrederick Mayle MinidumpMemoryList::MinidumpMemoryList(Minidump* minidump)
3384*9712c20fSFrederick Mayle     : MinidumpStream(minidump),
3385*9712c20fSFrederick Mayle       range_map_(new RangeMap<uint64_t, unsigned int>()),
3386*9712c20fSFrederick Mayle       descriptors_(NULL),
3387*9712c20fSFrederick Mayle       regions_(NULL),
3388*9712c20fSFrederick Mayle       region_count_(0) {
3389*9712c20fSFrederick Mayle }
3390*9712c20fSFrederick Mayle 
3391*9712c20fSFrederick Mayle 
~MinidumpMemoryList()3392*9712c20fSFrederick Mayle MinidumpMemoryList::~MinidumpMemoryList() {
3393*9712c20fSFrederick Mayle   delete range_map_;
3394*9712c20fSFrederick Mayle   delete descriptors_;
3395*9712c20fSFrederick Mayle   delete regions_;
3396*9712c20fSFrederick Mayle }
3397*9712c20fSFrederick Mayle 
3398*9712c20fSFrederick Mayle 
Read(uint32_t expected_size)3399*9712c20fSFrederick Mayle bool MinidumpMemoryList::Read(uint32_t expected_size) {
3400*9712c20fSFrederick Mayle   // Invalidate cached data.
3401*9712c20fSFrederick Mayle   delete descriptors_;
3402*9712c20fSFrederick Mayle   descriptors_ = NULL;
3403*9712c20fSFrederick Mayle   delete regions_;
3404*9712c20fSFrederick Mayle   regions_ = NULL;
3405*9712c20fSFrederick Mayle   range_map_->Clear();
3406*9712c20fSFrederick Mayle   region_count_ = 0;
3407*9712c20fSFrederick Mayle 
3408*9712c20fSFrederick Mayle   valid_ = false;
3409*9712c20fSFrederick Mayle 
3410*9712c20fSFrederick Mayle   uint32_t region_count;
3411*9712c20fSFrederick Mayle   if (expected_size < sizeof(region_count)) {
3412*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpMemoryList count size mismatch, " <<
3413*9712c20fSFrederick Mayle                     expected_size << " < " << sizeof(region_count);
3414*9712c20fSFrederick Mayle     return false;
3415*9712c20fSFrederick Mayle   }
3416*9712c20fSFrederick Mayle   if (!minidump_->ReadBytes(&region_count, sizeof(region_count))) {
3417*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpMemoryList could not read memory region count";
3418*9712c20fSFrederick Mayle     return false;
3419*9712c20fSFrederick Mayle   }
3420*9712c20fSFrederick Mayle 
3421*9712c20fSFrederick Mayle   if (minidump_->swap())
3422*9712c20fSFrederick Mayle     Swap(&region_count);
3423*9712c20fSFrederick Mayle 
3424*9712c20fSFrederick Mayle   if (region_count >
3425*9712c20fSFrederick Mayle           numeric_limits<uint32_t>::max() / sizeof(MDMemoryDescriptor)) {
3426*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpMemoryList region count " << region_count <<
3427*9712c20fSFrederick Mayle                     " would cause multiplication overflow";
3428*9712c20fSFrederick Mayle     return false;
3429*9712c20fSFrederick Mayle   }
3430*9712c20fSFrederick Mayle 
3431*9712c20fSFrederick Mayle   if (expected_size != sizeof(region_count) +
3432*9712c20fSFrederick Mayle                        region_count * sizeof(MDMemoryDescriptor)) {
3433*9712c20fSFrederick Mayle     // may be padded with 4 bytes on 64bit ABIs for alignment
3434*9712c20fSFrederick Mayle     if (expected_size == sizeof(region_count) + 4 +
3435*9712c20fSFrederick Mayle                          region_count * sizeof(MDMemoryDescriptor)) {
3436*9712c20fSFrederick Mayle       uint32_t useless;
3437*9712c20fSFrederick Mayle       if (!minidump_->ReadBytes(&useless, 4)) {
3438*9712c20fSFrederick Mayle         BPLOG(ERROR) << "MinidumpMemoryList cannot read memorylist padded "
3439*9712c20fSFrederick Mayle                         "bytes";
3440*9712c20fSFrederick Mayle         return false;
3441*9712c20fSFrederick Mayle       }
3442*9712c20fSFrederick Mayle     } else {
3443*9712c20fSFrederick Mayle       BPLOG(ERROR) << "MinidumpMemoryList size mismatch, " << expected_size <<
3444*9712c20fSFrederick Mayle                       " != " << sizeof(region_count) +
3445*9712c20fSFrederick Mayle                       region_count * sizeof(MDMemoryDescriptor);
3446*9712c20fSFrederick Mayle       return false;
3447*9712c20fSFrederick Mayle     }
3448*9712c20fSFrederick Mayle   }
3449*9712c20fSFrederick Mayle 
3450*9712c20fSFrederick Mayle   if (region_count > max_regions_) {
3451*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpMemoryList count " << region_count <<
3452*9712c20fSFrederick Mayle                     " exceeds maximum " << max_regions_;
3453*9712c20fSFrederick Mayle     return false;
3454*9712c20fSFrederick Mayle   }
3455*9712c20fSFrederick Mayle 
3456*9712c20fSFrederick Mayle   if (region_count != 0) {
3457*9712c20fSFrederick Mayle     scoped_ptr<MemoryDescriptors> descriptors(
3458*9712c20fSFrederick Mayle         new MemoryDescriptors(region_count));
3459*9712c20fSFrederick Mayle 
3460*9712c20fSFrederick Mayle     // Read the entire array in one fell swoop, instead of reading one entry
3461*9712c20fSFrederick Mayle     // at a time in the loop.
3462*9712c20fSFrederick Mayle     if (!minidump_->ReadBytes(&(*descriptors)[0],
3463*9712c20fSFrederick Mayle                               sizeof(MDMemoryDescriptor) * region_count)) {
3464*9712c20fSFrederick Mayle       BPLOG(ERROR) << "MinidumpMemoryList could not read memory region list";
3465*9712c20fSFrederick Mayle       return false;
3466*9712c20fSFrederick Mayle     }
3467*9712c20fSFrederick Mayle 
3468*9712c20fSFrederick Mayle     scoped_ptr<MemoryRegions> regions(
3469*9712c20fSFrederick Mayle         new MemoryRegions(region_count, MinidumpMemoryRegion(minidump_)));
3470*9712c20fSFrederick Mayle 
3471*9712c20fSFrederick Mayle     for (unsigned int region_index = 0;
3472*9712c20fSFrederick Mayle          region_index < region_count;
3473*9712c20fSFrederick Mayle          ++region_index) {
3474*9712c20fSFrederick Mayle       MDMemoryDescriptor* descriptor = &(*descriptors)[region_index];
3475*9712c20fSFrederick Mayle 
3476*9712c20fSFrederick Mayle       if (minidump_->swap())
3477*9712c20fSFrederick Mayle         Swap(descriptor);
3478*9712c20fSFrederick Mayle 
3479*9712c20fSFrederick Mayle       uint64_t base_address = descriptor->start_of_memory_range;
3480*9712c20fSFrederick Mayle       uint32_t region_size = descriptor->memory.data_size;
3481*9712c20fSFrederick Mayle 
3482*9712c20fSFrederick Mayle       // Check for base + size overflow or undersize.
3483*9712c20fSFrederick Mayle       if (region_size == 0 ||
3484*9712c20fSFrederick Mayle           region_size > numeric_limits<uint64_t>::max() - base_address) {
3485*9712c20fSFrederick Mayle         BPLOG(ERROR) << "MinidumpMemoryList has a memory region problem, " <<
3486*9712c20fSFrederick Mayle                         " region " << region_index << "/" << region_count <<
3487*9712c20fSFrederick Mayle                         ", " << HexString(base_address) << "+" <<
3488*9712c20fSFrederick Mayle                         HexString(region_size);
3489*9712c20fSFrederick Mayle         return false;
3490*9712c20fSFrederick Mayle       }
3491*9712c20fSFrederick Mayle 
3492*9712c20fSFrederick Mayle       if (!range_map_->StoreRange(base_address, region_size, region_index)) {
3493*9712c20fSFrederick Mayle         BPLOG(ERROR) << "MinidumpMemoryList could not store memory region " <<
3494*9712c20fSFrederick Mayle                         region_index << "/" << region_count << ", " <<
3495*9712c20fSFrederick Mayle                         HexString(base_address) << "+" <<
3496*9712c20fSFrederick Mayle                         HexString(region_size);
3497*9712c20fSFrederick Mayle         return false;
3498*9712c20fSFrederick Mayle       }
3499*9712c20fSFrederick Mayle 
3500*9712c20fSFrederick Mayle       (*regions)[region_index].SetDescriptor(descriptor);
3501*9712c20fSFrederick Mayle     }
3502*9712c20fSFrederick Mayle 
3503*9712c20fSFrederick Mayle     descriptors_ = descriptors.release();
3504*9712c20fSFrederick Mayle     regions_ = regions.release();
3505*9712c20fSFrederick Mayle   }
3506*9712c20fSFrederick Mayle 
3507*9712c20fSFrederick Mayle   region_count_ = region_count;
3508*9712c20fSFrederick Mayle 
3509*9712c20fSFrederick Mayle   valid_ = true;
3510*9712c20fSFrederick Mayle   return true;
3511*9712c20fSFrederick Mayle }
3512*9712c20fSFrederick Mayle 
3513*9712c20fSFrederick Mayle 
GetMemoryRegionAtIndex(unsigned int index)3514*9712c20fSFrederick Mayle MinidumpMemoryRegion* MinidumpMemoryList::GetMemoryRegionAtIndex(
3515*9712c20fSFrederick Mayle       unsigned int index) {
3516*9712c20fSFrederick Mayle   if (!valid_) {
3517*9712c20fSFrederick Mayle     BPLOG(ERROR) << "Invalid MinidumpMemoryList for GetMemoryRegionAtIndex";
3518*9712c20fSFrederick Mayle     return NULL;
3519*9712c20fSFrederick Mayle   }
3520*9712c20fSFrederick Mayle 
3521*9712c20fSFrederick Mayle   if (index >= region_count_) {
3522*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpMemoryList index out of range: " <<
3523*9712c20fSFrederick Mayle                     index << "/" << region_count_;
3524*9712c20fSFrederick Mayle     return NULL;
3525*9712c20fSFrederick Mayle   }
3526*9712c20fSFrederick Mayle 
3527*9712c20fSFrederick Mayle   return &(*regions_)[index];
3528*9712c20fSFrederick Mayle }
3529*9712c20fSFrederick Mayle 
3530*9712c20fSFrederick Mayle 
GetMemoryRegionForAddress(uint64_t address)3531*9712c20fSFrederick Mayle MinidumpMemoryRegion* MinidumpMemoryList::GetMemoryRegionForAddress(
3532*9712c20fSFrederick Mayle     uint64_t address) {
3533*9712c20fSFrederick Mayle   if (!valid_) {
3534*9712c20fSFrederick Mayle     BPLOG(ERROR) << "Invalid MinidumpMemoryList for GetMemoryRegionForAddress";
3535*9712c20fSFrederick Mayle     return NULL;
3536*9712c20fSFrederick Mayle   }
3537*9712c20fSFrederick Mayle 
3538*9712c20fSFrederick Mayle   unsigned int region_index;
3539*9712c20fSFrederick Mayle   if (!range_map_->RetrieveRange(address, &region_index, NULL /* base */,
3540*9712c20fSFrederick Mayle                                  NULL /* delta */, NULL /* size */)) {
3541*9712c20fSFrederick Mayle     BPLOG(INFO) << "MinidumpMemoryList has no memory region at " <<
3542*9712c20fSFrederick Mayle                    HexString(address);
3543*9712c20fSFrederick Mayle     return NULL;
3544*9712c20fSFrederick Mayle   }
3545*9712c20fSFrederick Mayle 
3546*9712c20fSFrederick Mayle   return GetMemoryRegionAtIndex(region_index);
3547*9712c20fSFrederick Mayle }
3548*9712c20fSFrederick Mayle 
3549*9712c20fSFrederick Mayle 
Print()3550*9712c20fSFrederick Mayle void MinidumpMemoryList::Print() {
3551*9712c20fSFrederick Mayle   if (!valid_) {
3552*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpMemoryList cannot print invalid data";
3553*9712c20fSFrederick Mayle     return;
3554*9712c20fSFrederick Mayle   }
3555*9712c20fSFrederick Mayle 
3556*9712c20fSFrederick Mayle   printf("MinidumpMemoryList\n");
3557*9712c20fSFrederick Mayle   printf("  region_count = %d\n", region_count_);
3558*9712c20fSFrederick Mayle   printf("\n");
3559*9712c20fSFrederick Mayle 
3560*9712c20fSFrederick Mayle   for (unsigned int region_index = 0;
3561*9712c20fSFrederick Mayle        region_index < region_count_;
3562*9712c20fSFrederick Mayle        ++region_index) {
3563*9712c20fSFrederick Mayle     MDMemoryDescriptor* descriptor = &(*descriptors_)[region_index];
3564*9712c20fSFrederick Mayle     printf("region[%d]\n", region_index);
3565*9712c20fSFrederick Mayle     printf("MDMemoryDescriptor\n");
3566*9712c20fSFrederick Mayle     printf("  start_of_memory_range = 0x%" PRIx64 "\n",
3567*9712c20fSFrederick Mayle            descriptor->start_of_memory_range);
3568*9712c20fSFrederick Mayle     printf("  memory.data_size      = 0x%x\n", descriptor->memory.data_size);
3569*9712c20fSFrederick Mayle     printf("  memory.rva            = 0x%x\n", descriptor->memory.rva);
3570*9712c20fSFrederick Mayle     MinidumpMemoryRegion* region = GetMemoryRegionAtIndex(region_index);
3571*9712c20fSFrederick Mayle     if (region) {
3572*9712c20fSFrederick Mayle       printf("Memory\n");
3573*9712c20fSFrederick Mayle       region->Print();
3574*9712c20fSFrederick Mayle     } else {
3575*9712c20fSFrederick Mayle       printf("No memory\n");
3576*9712c20fSFrederick Mayle     }
3577*9712c20fSFrederick Mayle     printf("\n");
3578*9712c20fSFrederick Mayle   }
3579*9712c20fSFrederick Mayle }
3580*9712c20fSFrederick Mayle 
3581*9712c20fSFrederick Mayle 
3582*9712c20fSFrederick Mayle //
3583*9712c20fSFrederick Mayle // MinidumpException
3584*9712c20fSFrederick Mayle //
3585*9712c20fSFrederick Mayle 
3586*9712c20fSFrederick Mayle 
MinidumpException(Minidump * minidump)3587*9712c20fSFrederick Mayle MinidumpException::MinidumpException(Minidump* minidump)
3588*9712c20fSFrederick Mayle     : MinidumpStream(minidump),
3589*9712c20fSFrederick Mayle       exception_(),
3590*9712c20fSFrederick Mayle       context_(NULL) {
3591*9712c20fSFrederick Mayle }
3592*9712c20fSFrederick Mayle 
3593*9712c20fSFrederick Mayle 
~MinidumpException()3594*9712c20fSFrederick Mayle MinidumpException::~MinidumpException() {
3595*9712c20fSFrederick Mayle   delete context_;
3596*9712c20fSFrederick Mayle }
3597*9712c20fSFrederick Mayle 
3598*9712c20fSFrederick Mayle 
Read(uint32_t expected_size)3599*9712c20fSFrederick Mayle bool MinidumpException::Read(uint32_t expected_size) {
3600*9712c20fSFrederick Mayle   // Invalidate cached data.
3601*9712c20fSFrederick Mayle   delete context_;
3602*9712c20fSFrederick Mayle   context_ = NULL;
3603*9712c20fSFrederick Mayle 
3604*9712c20fSFrederick Mayle   valid_ = false;
3605*9712c20fSFrederick Mayle 
3606*9712c20fSFrederick Mayle   if (expected_size != sizeof(exception_)) {
3607*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpException size mismatch, " << expected_size <<
3608*9712c20fSFrederick Mayle                     " != " << sizeof(exception_);
3609*9712c20fSFrederick Mayle     return false;
3610*9712c20fSFrederick Mayle   }
3611*9712c20fSFrederick Mayle 
3612*9712c20fSFrederick Mayle   if (!minidump_->ReadBytes(&exception_, sizeof(exception_))) {
3613*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpException cannot read exception";
3614*9712c20fSFrederick Mayle     return false;
3615*9712c20fSFrederick Mayle   }
3616*9712c20fSFrederick Mayle 
3617*9712c20fSFrederick Mayle   if (minidump_->swap()) {
3618*9712c20fSFrederick Mayle     Swap(&exception_.thread_id);
3619*9712c20fSFrederick Mayle     // exception_.__align is for alignment only and does not need to be
3620*9712c20fSFrederick Mayle     // swapped.
3621*9712c20fSFrederick Mayle     Swap(&exception_.exception_record.exception_code);
3622*9712c20fSFrederick Mayle     Swap(&exception_.exception_record.exception_flags);
3623*9712c20fSFrederick Mayle     Swap(&exception_.exception_record.exception_record);
3624*9712c20fSFrederick Mayle     Swap(&exception_.exception_record.exception_address);
3625*9712c20fSFrederick Mayle     Swap(&exception_.exception_record.number_parameters);
3626*9712c20fSFrederick Mayle     // exception_.exception_record.__align is for alignment only and does not
3627*9712c20fSFrederick Mayle     // need to be swapped.
3628*9712c20fSFrederick Mayle     for (unsigned int parameter_index = 0;
3629*9712c20fSFrederick Mayle          parameter_index < MD_EXCEPTION_MAXIMUM_PARAMETERS;
3630*9712c20fSFrederick Mayle          ++parameter_index) {
3631*9712c20fSFrederick Mayle       Swap(&exception_.exception_record.exception_information[parameter_index]);
3632*9712c20fSFrederick Mayle     }
3633*9712c20fSFrederick Mayle     Swap(&exception_.thread_context);
3634*9712c20fSFrederick Mayle   }
3635*9712c20fSFrederick Mayle 
3636*9712c20fSFrederick Mayle   valid_ = true;
3637*9712c20fSFrederick Mayle   return true;
3638*9712c20fSFrederick Mayle }
3639*9712c20fSFrederick Mayle 
3640*9712c20fSFrederick Mayle 
GetThreadID(uint32_t * thread_id) const3641*9712c20fSFrederick Mayle bool MinidumpException::GetThreadID(uint32_t* thread_id) const {
3642*9712c20fSFrederick Mayle   BPLOG_IF(ERROR, !thread_id) << "MinidumpException::GetThreadID requires "
3643*9712c20fSFrederick Mayle                                  "|thread_id|";
3644*9712c20fSFrederick Mayle   assert(thread_id);
3645*9712c20fSFrederick Mayle   *thread_id = 0;
3646*9712c20fSFrederick Mayle 
3647*9712c20fSFrederick Mayle   if (!valid_) {
3648*9712c20fSFrederick Mayle     BPLOG(ERROR) << "Invalid MinidumpException for GetThreadID";
3649*9712c20fSFrederick Mayle     return false;
3650*9712c20fSFrederick Mayle   }
3651*9712c20fSFrederick Mayle 
3652*9712c20fSFrederick Mayle   *thread_id = exception_.thread_id;
3653*9712c20fSFrederick Mayle   return true;
3654*9712c20fSFrederick Mayle }
3655*9712c20fSFrederick Mayle 
3656*9712c20fSFrederick Mayle 
GetContext()3657*9712c20fSFrederick Mayle MinidumpContext* MinidumpException::GetContext() {
3658*9712c20fSFrederick Mayle   if (!valid_) {
3659*9712c20fSFrederick Mayle     BPLOG(ERROR) << "Invalid MinidumpException for GetContext";
3660*9712c20fSFrederick Mayle     return NULL;
3661*9712c20fSFrederick Mayle   }
3662*9712c20fSFrederick Mayle 
3663*9712c20fSFrederick Mayle   if (!context_) {
3664*9712c20fSFrederick Mayle     if (!minidump_->SeekSet(exception_.thread_context.rva)) {
3665*9712c20fSFrederick Mayle       BPLOG(ERROR) << "MinidumpException cannot seek to context";
3666*9712c20fSFrederick Mayle       return NULL;
3667*9712c20fSFrederick Mayle     }
3668*9712c20fSFrederick Mayle 
3669*9712c20fSFrederick Mayle     scoped_ptr<MinidumpContext> context(new MinidumpContext(minidump_));
3670*9712c20fSFrederick Mayle 
3671*9712c20fSFrederick Mayle     // Don't log as an error if we can still fall back on the thread's context
3672*9712c20fSFrederick Mayle     // (which must be possible if we got this far.)
3673*9712c20fSFrederick Mayle     if (!context->Read(exception_.thread_context.data_size)) {
3674*9712c20fSFrederick Mayle       BPLOG(INFO) << "MinidumpException cannot read context";
3675*9712c20fSFrederick Mayle       return NULL;
3676*9712c20fSFrederick Mayle     }
3677*9712c20fSFrederick Mayle 
3678*9712c20fSFrederick Mayle     context_ = context.release();
3679*9712c20fSFrederick Mayle   }
3680*9712c20fSFrederick Mayle 
3681*9712c20fSFrederick Mayle   return context_;
3682*9712c20fSFrederick Mayle }
3683*9712c20fSFrederick Mayle 
3684*9712c20fSFrederick Mayle 
Print()3685*9712c20fSFrederick Mayle void MinidumpException::Print() {
3686*9712c20fSFrederick Mayle   if (!valid_) {
3687*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpException cannot print invalid data";
3688*9712c20fSFrederick Mayle     return;
3689*9712c20fSFrederick Mayle   }
3690*9712c20fSFrederick Mayle 
3691*9712c20fSFrederick Mayle   printf("MDException\n");
3692*9712c20fSFrederick Mayle   printf("  thread_id                                  = 0x%x\n",
3693*9712c20fSFrederick Mayle          exception_.thread_id);
3694*9712c20fSFrederick Mayle   printf("  exception_record.exception_code            = 0x%x\n",
3695*9712c20fSFrederick Mayle          exception_.exception_record.exception_code);
3696*9712c20fSFrederick Mayle   printf("  exception_record.exception_flags           = 0x%x\n",
3697*9712c20fSFrederick Mayle          exception_.exception_record.exception_flags);
3698*9712c20fSFrederick Mayle   printf("  exception_record.exception_record          = 0x%" PRIx64 "\n",
3699*9712c20fSFrederick Mayle          exception_.exception_record.exception_record);
3700*9712c20fSFrederick Mayle   printf("  exception_record.exception_address         = 0x%" PRIx64 "\n",
3701*9712c20fSFrederick Mayle          exception_.exception_record.exception_address);
3702*9712c20fSFrederick Mayle   printf("  exception_record.number_parameters         = %d\n",
3703*9712c20fSFrederick Mayle          exception_.exception_record.number_parameters);
3704*9712c20fSFrederick Mayle   for (unsigned int parameterIndex = 0;
3705*9712c20fSFrederick Mayle        parameterIndex < exception_.exception_record.number_parameters;
3706*9712c20fSFrederick Mayle        ++parameterIndex) {
3707*9712c20fSFrederick Mayle     printf("  exception_record.exception_information[%2d] = 0x%" PRIx64 "\n",
3708*9712c20fSFrederick Mayle            parameterIndex,
3709*9712c20fSFrederick Mayle            exception_.exception_record.exception_information[parameterIndex]);
3710*9712c20fSFrederick Mayle   }
3711*9712c20fSFrederick Mayle   printf("  thread_context.data_size                   = %d\n",
3712*9712c20fSFrederick Mayle          exception_.thread_context.data_size);
3713*9712c20fSFrederick Mayle   printf("  thread_context.rva                         = 0x%x\n",
3714*9712c20fSFrederick Mayle          exception_.thread_context.rva);
3715*9712c20fSFrederick Mayle   MinidumpContext* context = GetContext();
3716*9712c20fSFrederick Mayle   if (context) {
3717*9712c20fSFrederick Mayle     printf("\n");
3718*9712c20fSFrederick Mayle     context->Print();
3719*9712c20fSFrederick Mayle   } else {
3720*9712c20fSFrederick Mayle     printf("  (no context)\n");
3721*9712c20fSFrederick Mayle     printf("\n");
3722*9712c20fSFrederick Mayle   }
3723*9712c20fSFrederick Mayle }
3724*9712c20fSFrederick Mayle 
3725*9712c20fSFrederick Mayle //
3726*9712c20fSFrederick Mayle // MinidumpAssertion
3727*9712c20fSFrederick Mayle //
3728*9712c20fSFrederick Mayle 
3729*9712c20fSFrederick Mayle 
MinidumpAssertion(Minidump * minidump)3730*9712c20fSFrederick Mayle MinidumpAssertion::MinidumpAssertion(Minidump* minidump)
3731*9712c20fSFrederick Mayle     : MinidumpStream(minidump),
3732*9712c20fSFrederick Mayle       assertion_(),
3733*9712c20fSFrederick Mayle       expression_(),
3734*9712c20fSFrederick Mayle       function_(),
3735*9712c20fSFrederick Mayle       file_() {
3736*9712c20fSFrederick Mayle }
3737*9712c20fSFrederick Mayle 
3738*9712c20fSFrederick Mayle 
~MinidumpAssertion()3739*9712c20fSFrederick Mayle MinidumpAssertion::~MinidumpAssertion() {
3740*9712c20fSFrederick Mayle }
3741*9712c20fSFrederick Mayle 
3742*9712c20fSFrederick Mayle 
Read(uint32_t expected_size)3743*9712c20fSFrederick Mayle bool MinidumpAssertion::Read(uint32_t expected_size) {
3744*9712c20fSFrederick Mayle   // Invalidate cached data.
3745*9712c20fSFrederick Mayle   valid_ = false;
3746*9712c20fSFrederick Mayle 
3747*9712c20fSFrederick Mayle   if (expected_size != sizeof(assertion_)) {
3748*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpAssertion size mismatch, " << expected_size <<
3749*9712c20fSFrederick Mayle                     " != " << sizeof(assertion_);
3750*9712c20fSFrederick Mayle     return false;
3751*9712c20fSFrederick Mayle   }
3752*9712c20fSFrederick Mayle 
3753*9712c20fSFrederick Mayle   if (!minidump_->ReadBytes(&assertion_, sizeof(assertion_))) {
3754*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpAssertion cannot read assertion";
3755*9712c20fSFrederick Mayle     return false;
3756*9712c20fSFrederick Mayle   }
3757*9712c20fSFrederick Mayle 
3758*9712c20fSFrederick Mayle   // Each of {expression, function, file} is a UTF-16 string,
3759*9712c20fSFrederick Mayle   // we'll convert them to UTF-8 for ease of use.
3760*9712c20fSFrederick Mayle   ConvertUTF16BufferToUTF8String(assertion_.expression,
3761*9712c20fSFrederick Mayle                                  sizeof(assertion_.expression), &expression_,
3762*9712c20fSFrederick Mayle                                  minidump_->swap());
3763*9712c20fSFrederick Mayle   ConvertUTF16BufferToUTF8String(assertion_.function,
3764*9712c20fSFrederick Mayle                                  sizeof(assertion_.function), &function_,
3765*9712c20fSFrederick Mayle                                  minidump_->swap());
3766*9712c20fSFrederick Mayle   ConvertUTF16BufferToUTF8String(assertion_.file, sizeof(assertion_.file),
3767*9712c20fSFrederick Mayle                                  &file_, minidump_->swap());
3768*9712c20fSFrederick Mayle 
3769*9712c20fSFrederick Mayle   if (minidump_->swap()) {
3770*9712c20fSFrederick Mayle     Swap(&assertion_.line);
3771*9712c20fSFrederick Mayle     Swap(&assertion_.type);
3772*9712c20fSFrederick Mayle   }
3773*9712c20fSFrederick Mayle 
3774*9712c20fSFrederick Mayle   valid_ = true;
3775*9712c20fSFrederick Mayle   return true;
3776*9712c20fSFrederick Mayle }
3777*9712c20fSFrederick Mayle 
Print()3778*9712c20fSFrederick Mayle void MinidumpAssertion::Print() {
3779*9712c20fSFrederick Mayle   if (!valid_) {
3780*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpAssertion cannot print invalid data";
3781*9712c20fSFrederick Mayle     return;
3782*9712c20fSFrederick Mayle   }
3783*9712c20fSFrederick Mayle 
3784*9712c20fSFrederick Mayle   printf("MDAssertion\n");
3785*9712c20fSFrederick Mayle   printf("  expression                                 = %s\n",
3786*9712c20fSFrederick Mayle          expression_.c_str());
3787*9712c20fSFrederick Mayle   printf("  function                                   = %s\n",
3788*9712c20fSFrederick Mayle          function_.c_str());
3789*9712c20fSFrederick Mayle   printf("  file                                       = %s\n",
3790*9712c20fSFrederick Mayle          file_.c_str());
3791*9712c20fSFrederick Mayle   printf("  line                                       = %u\n",
3792*9712c20fSFrederick Mayle          assertion_.line);
3793*9712c20fSFrederick Mayle   printf("  type                                       = %u\n",
3794*9712c20fSFrederick Mayle          assertion_.type);
3795*9712c20fSFrederick Mayle   printf("\n");
3796*9712c20fSFrederick Mayle }
3797*9712c20fSFrederick Mayle 
3798*9712c20fSFrederick Mayle //
3799*9712c20fSFrederick Mayle // MinidumpSystemInfo
3800*9712c20fSFrederick Mayle //
3801*9712c20fSFrederick Mayle 
3802*9712c20fSFrederick Mayle 
MinidumpSystemInfo(Minidump * minidump)3803*9712c20fSFrederick Mayle MinidumpSystemInfo::MinidumpSystemInfo(Minidump* minidump)
3804*9712c20fSFrederick Mayle     : MinidumpStream(minidump),
3805*9712c20fSFrederick Mayle       system_info_(),
3806*9712c20fSFrederick Mayle       csd_version_(NULL),
3807*9712c20fSFrederick Mayle       cpu_vendor_(NULL) {
3808*9712c20fSFrederick Mayle }
3809*9712c20fSFrederick Mayle 
3810*9712c20fSFrederick Mayle 
~MinidumpSystemInfo()3811*9712c20fSFrederick Mayle MinidumpSystemInfo::~MinidumpSystemInfo() {
3812*9712c20fSFrederick Mayle   delete csd_version_;
3813*9712c20fSFrederick Mayle   delete cpu_vendor_;
3814*9712c20fSFrederick Mayle }
3815*9712c20fSFrederick Mayle 
3816*9712c20fSFrederick Mayle 
Read(uint32_t expected_size)3817*9712c20fSFrederick Mayle bool MinidumpSystemInfo::Read(uint32_t expected_size) {
3818*9712c20fSFrederick Mayle   // Invalidate cached data.
3819*9712c20fSFrederick Mayle   delete csd_version_;
3820*9712c20fSFrederick Mayle   csd_version_ = NULL;
3821*9712c20fSFrederick Mayle   delete cpu_vendor_;
3822*9712c20fSFrederick Mayle   cpu_vendor_ = NULL;
3823*9712c20fSFrederick Mayle 
3824*9712c20fSFrederick Mayle   valid_ = false;
3825*9712c20fSFrederick Mayle 
3826*9712c20fSFrederick Mayle   if (expected_size != sizeof(system_info_)) {
3827*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpSystemInfo size mismatch, " << expected_size <<
3828*9712c20fSFrederick Mayle                     " != " << sizeof(system_info_);
3829*9712c20fSFrederick Mayle     return false;
3830*9712c20fSFrederick Mayle   }
3831*9712c20fSFrederick Mayle 
3832*9712c20fSFrederick Mayle   if (!minidump_->ReadBytes(&system_info_, sizeof(system_info_))) {
3833*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpSystemInfo cannot read system info";
3834*9712c20fSFrederick Mayle     return false;
3835*9712c20fSFrederick Mayle   }
3836*9712c20fSFrederick Mayle 
3837*9712c20fSFrederick Mayle   if (minidump_->swap()) {
3838*9712c20fSFrederick Mayle     Swap(&system_info_.processor_architecture);
3839*9712c20fSFrederick Mayle     Swap(&system_info_.processor_level);
3840*9712c20fSFrederick Mayle     Swap(&system_info_.processor_revision);
3841*9712c20fSFrederick Mayle     // number_of_processors and product_type are 8-bit quantities and need no
3842*9712c20fSFrederick Mayle     // swapping.
3843*9712c20fSFrederick Mayle     Swap(&system_info_.major_version);
3844*9712c20fSFrederick Mayle     Swap(&system_info_.minor_version);
3845*9712c20fSFrederick Mayle     Swap(&system_info_.build_number);
3846*9712c20fSFrederick Mayle     Swap(&system_info_.platform_id);
3847*9712c20fSFrederick Mayle     Swap(&system_info_.csd_version_rva);
3848*9712c20fSFrederick Mayle     Swap(&system_info_.suite_mask);
3849*9712c20fSFrederick Mayle     // Don't swap the reserved2 field because its contents are unknown.
3850*9712c20fSFrederick Mayle 
3851*9712c20fSFrederick Mayle     if (system_info_.processor_architecture == MD_CPU_ARCHITECTURE_X86 ||
3852*9712c20fSFrederick Mayle         system_info_.processor_architecture == MD_CPU_ARCHITECTURE_X86_WIN64) {
3853*9712c20fSFrederick Mayle       for (unsigned int i = 0; i < 3; ++i)
3854*9712c20fSFrederick Mayle         Swap(&system_info_.cpu.x86_cpu_info.vendor_id[i]);
3855*9712c20fSFrederick Mayle       Swap(&system_info_.cpu.x86_cpu_info.version_information);
3856*9712c20fSFrederick Mayle       Swap(&system_info_.cpu.x86_cpu_info.feature_information);
3857*9712c20fSFrederick Mayle       Swap(&system_info_.cpu.x86_cpu_info.amd_extended_cpu_features);
3858*9712c20fSFrederick Mayle     } else {
3859*9712c20fSFrederick Mayle       for (unsigned int i = 0; i < 2; ++i)
3860*9712c20fSFrederick Mayle         Swap(&system_info_.cpu.other_cpu_info.processor_features[i]);
3861*9712c20fSFrederick Mayle     }
3862*9712c20fSFrederick Mayle   }
3863*9712c20fSFrederick Mayle 
3864*9712c20fSFrederick Mayle   valid_ = true;
3865*9712c20fSFrederick Mayle   return true;
3866*9712c20fSFrederick Mayle }
3867*9712c20fSFrederick Mayle 
3868*9712c20fSFrederick Mayle 
GetOS()3869*9712c20fSFrederick Mayle string MinidumpSystemInfo::GetOS() {
3870*9712c20fSFrederick Mayle   string os;
3871*9712c20fSFrederick Mayle 
3872*9712c20fSFrederick Mayle   if (!valid_) {
3873*9712c20fSFrederick Mayle     BPLOG(ERROR) << "Invalid MinidumpSystemInfo for GetOS";
3874*9712c20fSFrederick Mayle     return os;
3875*9712c20fSFrederick Mayle   }
3876*9712c20fSFrederick Mayle 
3877*9712c20fSFrederick Mayle   switch (system_info_.platform_id) {
3878*9712c20fSFrederick Mayle     case MD_OS_WIN32_NT:
3879*9712c20fSFrederick Mayle     case MD_OS_WIN32_WINDOWS:
3880*9712c20fSFrederick Mayle       os = "windows";
3881*9712c20fSFrederick Mayle       break;
3882*9712c20fSFrederick Mayle 
3883*9712c20fSFrederick Mayle     case MD_OS_MAC_OS_X:
3884*9712c20fSFrederick Mayle       os = "mac";
3885*9712c20fSFrederick Mayle       break;
3886*9712c20fSFrederick Mayle 
3887*9712c20fSFrederick Mayle     case MD_OS_IOS:
3888*9712c20fSFrederick Mayle       os = "ios";
3889*9712c20fSFrederick Mayle       break;
3890*9712c20fSFrederick Mayle 
3891*9712c20fSFrederick Mayle     case MD_OS_LINUX:
3892*9712c20fSFrederick Mayle       os = "linux";
3893*9712c20fSFrederick Mayle       break;
3894*9712c20fSFrederick Mayle 
3895*9712c20fSFrederick Mayle     case MD_OS_SOLARIS:
3896*9712c20fSFrederick Mayle       os = "solaris";
3897*9712c20fSFrederick Mayle       break;
3898*9712c20fSFrederick Mayle 
3899*9712c20fSFrederick Mayle     case MD_OS_ANDROID:
3900*9712c20fSFrederick Mayle       os = "android";
3901*9712c20fSFrederick Mayle       break;
3902*9712c20fSFrederick Mayle 
3903*9712c20fSFrederick Mayle     case MD_OS_PS3:
3904*9712c20fSFrederick Mayle       os = "ps3";
3905*9712c20fSFrederick Mayle       break;
3906*9712c20fSFrederick Mayle 
3907*9712c20fSFrederick Mayle     case MD_OS_NACL:
3908*9712c20fSFrederick Mayle       os = "nacl";
3909*9712c20fSFrederick Mayle       break;
3910*9712c20fSFrederick Mayle 
3911*9712c20fSFrederick Mayle     case MD_OS_FUCHSIA:
3912*9712c20fSFrederick Mayle       os = "fuchsia";
3913*9712c20fSFrederick Mayle       break;
3914*9712c20fSFrederick Mayle 
3915*9712c20fSFrederick Mayle     default:
3916*9712c20fSFrederick Mayle       BPLOG(ERROR) << "MinidumpSystemInfo unknown OS for platform " <<
3917*9712c20fSFrederick Mayle                       HexString(system_info_.platform_id);
3918*9712c20fSFrederick Mayle       break;
3919*9712c20fSFrederick Mayle   }
3920*9712c20fSFrederick Mayle 
3921*9712c20fSFrederick Mayle   return os;
3922*9712c20fSFrederick Mayle }
3923*9712c20fSFrederick Mayle 
3924*9712c20fSFrederick Mayle 
GetCPU()3925*9712c20fSFrederick Mayle string MinidumpSystemInfo::GetCPU() {
3926*9712c20fSFrederick Mayle   if (!valid_) {
3927*9712c20fSFrederick Mayle     BPLOG(ERROR) << "Invalid MinidumpSystemInfo for GetCPU";
3928*9712c20fSFrederick Mayle     return "";
3929*9712c20fSFrederick Mayle   }
3930*9712c20fSFrederick Mayle 
3931*9712c20fSFrederick Mayle   string cpu;
3932*9712c20fSFrederick Mayle 
3933*9712c20fSFrederick Mayle   switch (system_info_.processor_architecture) {
3934*9712c20fSFrederick Mayle     case MD_CPU_ARCHITECTURE_X86:
3935*9712c20fSFrederick Mayle     case MD_CPU_ARCHITECTURE_X86_WIN64:
3936*9712c20fSFrederick Mayle       cpu = "x86";
3937*9712c20fSFrederick Mayle       break;
3938*9712c20fSFrederick Mayle 
3939*9712c20fSFrederick Mayle     case MD_CPU_ARCHITECTURE_AMD64:
3940*9712c20fSFrederick Mayle       cpu = "x86-64";
3941*9712c20fSFrederick Mayle       break;
3942*9712c20fSFrederick Mayle 
3943*9712c20fSFrederick Mayle     case MD_CPU_ARCHITECTURE_PPC:
3944*9712c20fSFrederick Mayle       cpu = "ppc";
3945*9712c20fSFrederick Mayle       break;
3946*9712c20fSFrederick Mayle 
3947*9712c20fSFrederick Mayle     case MD_CPU_ARCHITECTURE_PPC64:
3948*9712c20fSFrederick Mayle       cpu = "ppc64";
3949*9712c20fSFrederick Mayle       break;
3950*9712c20fSFrederick Mayle 
3951*9712c20fSFrederick Mayle     case MD_CPU_ARCHITECTURE_SPARC:
3952*9712c20fSFrederick Mayle       cpu = "sparc";
3953*9712c20fSFrederick Mayle       break;
3954*9712c20fSFrederick Mayle 
3955*9712c20fSFrederick Mayle     case MD_CPU_ARCHITECTURE_ARM:
3956*9712c20fSFrederick Mayle       cpu = "arm";
3957*9712c20fSFrederick Mayle       break;
3958*9712c20fSFrederick Mayle 
3959*9712c20fSFrederick Mayle     case MD_CPU_ARCHITECTURE_ARM64:
3960*9712c20fSFrederick Mayle     case MD_CPU_ARCHITECTURE_ARM64_OLD:
3961*9712c20fSFrederick Mayle       cpu = "arm64";
3962*9712c20fSFrederick Mayle       break;
3963*9712c20fSFrederick Mayle 
3964*9712c20fSFrederick Mayle     case MD_CPU_ARCHITECTURE_RISCV:
3965*9712c20fSFrederick Mayle       cpu = "riscv";
3966*9712c20fSFrederick Mayle       break;
3967*9712c20fSFrederick Mayle 
3968*9712c20fSFrederick Mayle     case MD_CPU_ARCHITECTURE_RISCV64:
3969*9712c20fSFrederick Mayle       cpu = "riscv64";
3970*9712c20fSFrederick Mayle       break;
3971*9712c20fSFrederick Mayle 
3972*9712c20fSFrederick Mayle     default:
3973*9712c20fSFrederick Mayle       BPLOG(ERROR) << "MinidumpSystemInfo unknown CPU for architecture " <<
3974*9712c20fSFrederick Mayle                       HexString(system_info_.processor_architecture);
3975*9712c20fSFrederick Mayle       break;
3976*9712c20fSFrederick Mayle   }
3977*9712c20fSFrederick Mayle 
3978*9712c20fSFrederick Mayle   return cpu;
3979*9712c20fSFrederick Mayle }
3980*9712c20fSFrederick Mayle 
3981*9712c20fSFrederick Mayle 
GetCSDVersion()3982*9712c20fSFrederick Mayle const string* MinidumpSystemInfo::GetCSDVersion() {
3983*9712c20fSFrederick Mayle   if (!valid_) {
3984*9712c20fSFrederick Mayle     BPLOG(ERROR) << "Invalid MinidumpSystemInfo for GetCSDVersion";
3985*9712c20fSFrederick Mayle     return NULL;
3986*9712c20fSFrederick Mayle   }
3987*9712c20fSFrederick Mayle 
3988*9712c20fSFrederick Mayle   if (!csd_version_)
3989*9712c20fSFrederick Mayle     csd_version_ = minidump_->ReadString(system_info_.csd_version_rva);
3990*9712c20fSFrederick Mayle 
3991*9712c20fSFrederick Mayle   BPLOG_IF(ERROR, !csd_version_) << "MinidumpSystemInfo could not read "
3992*9712c20fSFrederick Mayle                                     "CSD version";
3993*9712c20fSFrederick Mayle 
3994*9712c20fSFrederick Mayle   return csd_version_;
3995*9712c20fSFrederick Mayle }
3996*9712c20fSFrederick Mayle 
3997*9712c20fSFrederick Mayle 
GetCPUVendor()3998*9712c20fSFrederick Mayle const string* MinidumpSystemInfo::GetCPUVendor() {
3999*9712c20fSFrederick Mayle   if (!valid_) {
4000*9712c20fSFrederick Mayle     BPLOG(ERROR) << "Invalid MinidumpSystemInfo for GetCPUVendor";
4001*9712c20fSFrederick Mayle     return NULL;
4002*9712c20fSFrederick Mayle   }
4003*9712c20fSFrederick Mayle 
4004*9712c20fSFrederick Mayle   // CPU vendor information can only be determined from x86 minidumps.
4005*9712c20fSFrederick Mayle   if (!cpu_vendor_ &&
4006*9712c20fSFrederick Mayle       (system_info_.processor_architecture == MD_CPU_ARCHITECTURE_X86 ||
4007*9712c20fSFrederick Mayle        system_info_.processor_architecture == MD_CPU_ARCHITECTURE_X86_WIN64)) {
4008*9712c20fSFrederick Mayle     char cpu_vendor_string[13];
4009*9712c20fSFrederick Mayle     snprintf(cpu_vendor_string, sizeof(cpu_vendor_string),
4010*9712c20fSFrederick Mayle              "%c%c%c%c%c%c%c%c%c%c%c%c",
4011*9712c20fSFrederick Mayle               system_info_.cpu.x86_cpu_info.vendor_id[0] & 0xff,
4012*9712c20fSFrederick Mayle              (system_info_.cpu.x86_cpu_info.vendor_id[0] >> 8) & 0xff,
4013*9712c20fSFrederick Mayle              (system_info_.cpu.x86_cpu_info.vendor_id[0] >> 16) & 0xff,
4014*9712c20fSFrederick Mayle              (system_info_.cpu.x86_cpu_info.vendor_id[0] >> 24) & 0xff,
4015*9712c20fSFrederick Mayle               system_info_.cpu.x86_cpu_info.vendor_id[1] & 0xff,
4016*9712c20fSFrederick Mayle              (system_info_.cpu.x86_cpu_info.vendor_id[1] >> 8) & 0xff,
4017*9712c20fSFrederick Mayle              (system_info_.cpu.x86_cpu_info.vendor_id[1] >> 16) & 0xff,
4018*9712c20fSFrederick Mayle              (system_info_.cpu.x86_cpu_info.vendor_id[1] >> 24) & 0xff,
4019*9712c20fSFrederick Mayle               system_info_.cpu.x86_cpu_info.vendor_id[2] & 0xff,
4020*9712c20fSFrederick Mayle              (system_info_.cpu.x86_cpu_info.vendor_id[2] >> 8) & 0xff,
4021*9712c20fSFrederick Mayle              (system_info_.cpu.x86_cpu_info.vendor_id[2] >> 16) & 0xff,
4022*9712c20fSFrederick Mayle              (system_info_.cpu.x86_cpu_info.vendor_id[2] >> 24) & 0xff);
4023*9712c20fSFrederick Mayle     cpu_vendor_ = new string(cpu_vendor_string);
4024*9712c20fSFrederick Mayle   }
4025*9712c20fSFrederick Mayle 
4026*9712c20fSFrederick Mayle   return cpu_vendor_;
4027*9712c20fSFrederick Mayle }
4028*9712c20fSFrederick Mayle 
4029*9712c20fSFrederick Mayle 
Print()4030*9712c20fSFrederick Mayle void MinidumpSystemInfo::Print() {
4031*9712c20fSFrederick Mayle   if (!valid_) {
4032*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpSystemInfo cannot print invalid data";
4033*9712c20fSFrederick Mayle     return;
4034*9712c20fSFrederick Mayle   }
4035*9712c20fSFrederick Mayle 
4036*9712c20fSFrederick Mayle   printf("MDRawSystemInfo\n");
4037*9712c20fSFrederick Mayle   printf("  processor_architecture                     = 0x%x (%s)\n",
4038*9712c20fSFrederick Mayle          system_info_.processor_architecture, GetCPU().c_str());
4039*9712c20fSFrederick Mayle   printf("  processor_level                            = %d\n",
4040*9712c20fSFrederick Mayle          system_info_.processor_level);
4041*9712c20fSFrederick Mayle   printf("  processor_revision                         = 0x%x\n",
4042*9712c20fSFrederick Mayle          system_info_.processor_revision);
4043*9712c20fSFrederick Mayle   printf("  number_of_processors                       = %d\n",
4044*9712c20fSFrederick Mayle          system_info_.number_of_processors);
4045*9712c20fSFrederick Mayle   printf("  product_type                               = %d\n",
4046*9712c20fSFrederick Mayle          system_info_.product_type);
4047*9712c20fSFrederick Mayle   printf("  major_version                              = %d\n",
4048*9712c20fSFrederick Mayle          system_info_.major_version);
4049*9712c20fSFrederick Mayle   printf("  minor_version                              = %d\n",
4050*9712c20fSFrederick Mayle          system_info_.minor_version);
4051*9712c20fSFrederick Mayle   printf("  build_number                               = %d\n",
4052*9712c20fSFrederick Mayle          system_info_.build_number);
4053*9712c20fSFrederick Mayle   printf("  platform_id                                = 0x%x (%s)\n",
4054*9712c20fSFrederick Mayle          system_info_.platform_id, GetOS().c_str());
4055*9712c20fSFrederick Mayle   printf("  csd_version_rva                            = 0x%x\n",
4056*9712c20fSFrederick Mayle          system_info_.csd_version_rva);
4057*9712c20fSFrederick Mayle   printf("  suite_mask                                 = 0x%x\n",
4058*9712c20fSFrederick Mayle          system_info_.suite_mask);
4059*9712c20fSFrederick Mayle   if (system_info_.processor_architecture == MD_CPU_ARCHITECTURE_X86 ||
4060*9712c20fSFrederick Mayle       system_info_.processor_architecture == MD_CPU_ARCHITECTURE_X86_WIN64) {
4061*9712c20fSFrederick Mayle     printf("  cpu.x86_cpu_info (valid):\n");
4062*9712c20fSFrederick Mayle   } else {
4063*9712c20fSFrederick Mayle     printf("  cpu.x86_cpu_info (invalid):\n");
4064*9712c20fSFrederick Mayle   }
4065*9712c20fSFrederick Mayle   for (unsigned int i = 0; i < 3; ++i) {
4066*9712c20fSFrederick Mayle     printf("  cpu.x86_cpu_info.vendor_id[%d]              = 0x%x\n",
4067*9712c20fSFrederick Mayle            i, system_info_.cpu.x86_cpu_info.vendor_id[i]);
4068*9712c20fSFrederick Mayle   }
4069*9712c20fSFrederick Mayle   printf("  cpu.x86_cpu_info.version_information       = 0x%x\n",
4070*9712c20fSFrederick Mayle          system_info_.cpu.x86_cpu_info.version_information);
4071*9712c20fSFrederick Mayle   printf("  cpu.x86_cpu_info.feature_information       = 0x%x\n",
4072*9712c20fSFrederick Mayle          system_info_.cpu.x86_cpu_info.feature_information);
4073*9712c20fSFrederick Mayle   printf("  cpu.x86_cpu_info.amd_extended_cpu_features = 0x%x\n",
4074*9712c20fSFrederick Mayle          system_info_.cpu.x86_cpu_info.amd_extended_cpu_features);
4075*9712c20fSFrederick Mayle   if (system_info_.processor_architecture != MD_CPU_ARCHITECTURE_X86 &&
4076*9712c20fSFrederick Mayle       system_info_.processor_architecture != MD_CPU_ARCHITECTURE_X86_WIN64) {
4077*9712c20fSFrederick Mayle     printf("  cpu.other_cpu_info (valid):\n");
4078*9712c20fSFrederick Mayle     for (unsigned int i = 0; i < 2; ++i) {
4079*9712c20fSFrederick Mayle       printf("  cpu.other_cpu_info.processor_features[%d]   = 0x%" PRIx64 "\n",
4080*9712c20fSFrederick Mayle              i, system_info_.cpu.other_cpu_info.processor_features[i]);
4081*9712c20fSFrederick Mayle     }
4082*9712c20fSFrederick Mayle   }
4083*9712c20fSFrederick Mayle   const string* csd_version = GetCSDVersion();
4084*9712c20fSFrederick Mayle   if (csd_version) {
4085*9712c20fSFrederick Mayle     printf("  (csd_version)                              = \"%s\"\n",
4086*9712c20fSFrederick Mayle            csd_version->c_str());
4087*9712c20fSFrederick Mayle   } else {
4088*9712c20fSFrederick Mayle     printf("  (csd_version)                              = (null)\n");
4089*9712c20fSFrederick Mayle   }
4090*9712c20fSFrederick Mayle   const string* cpu_vendor = GetCPUVendor();
4091*9712c20fSFrederick Mayle   if (cpu_vendor) {
4092*9712c20fSFrederick Mayle     printf("  (cpu_vendor)                               = \"%s\"\n",
4093*9712c20fSFrederick Mayle            cpu_vendor->c_str());
4094*9712c20fSFrederick Mayle   } else {
4095*9712c20fSFrederick Mayle     printf("  (cpu_vendor)                               = (null)\n");
4096*9712c20fSFrederick Mayle   }
4097*9712c20fSFrederick Mayle   printf("\n");
4098*9712c20fSFrederick Mayle }
4099*9712c20fSFrederick Mayle 
4100*9712c20fSFrederick Mayle 
4101*9712c20fSFrederick Mayle //
4102*9712c20fSFrederick Mayle // MinidumpUnloadedModule
4103*9712c20fSFrederick Mayle //
4104*9712c20fSFrederick Mayle 
4105*9712c20fSFrederick Mayle 
MinidumpUnloadedModule(Minidump * minidump)4106*9712c20fSFrederick Mayle MinidumpUnloadedModule::MinidumpUnloadedModule(Minidump* minidump)
4107*9712c20fSFrederick Mayle     : MinidumpObject(minidump),
4108*9712c20fSFrederick Mayle       module_valid_(false),
4109*9712c20fSFrederick Mayle       unloaded_module_(),
4110*9712c20fSFrederick Mayle       name_(NULL) {
4111*9712c20fSFrederick Mayle 
4112*9712c20fSFrederick Mayle }
4113*9712c20fSFrederick Mayle 
~MinidumpUnloadedModule()4114*9712c20fSFrederick Mayle MinidumpUnloadedModule::~MinidumpUnloadedModule() {
4115*9712c20fSFrederick Mayle   delete name_;
4116*9712c20fSFrederick Mayle }
4117*9712c20fSFrederick Mayle 
code_file() const4118*9712c20fSFrederick Mayle string MinidumpUnloadedModule::code_file() const {
4119*9712c20fSFrederick Mayle   if (!valid_) {
4120*9712c20fSFrederick Mayle     BPLOG(ERROR) << "Invalid MinidumpUnloadedModule for code_file";
4121*9712c20fSFrederick Mayle     return "";
4122*9712c20fSFrederick Mayle   }
4123*9712c20fSFrederick Mayle 
4124*9712c20fSFrederick Mayle   return *name_;
4125*9712c20fSFrederick Mayle }
4126*9712c20fSFrederick Mayle 
code_identifier() const4127*9712c20fSFrederick Mayle string MinidumpUnloadedModule::code_identifier() const {
4128*9712c20fSFrederick Mayle   if (!valid_) {
4129*9712c20fSFrederick Mayle     BPLOG(ERROR) << "Invalid MinidumpUnloadedModule for code_identifier";
4130*9712c20fSFrederick Mayle     return "";
4131*9712c20fSFrederick Mayle   }
4132*9712c20fSFrederick Mayle 
4133*9712c20fSFrederick Mayle   MinidumpSystemInfo* minidump_system_info = minidump_->GetSystemInfo();
4134*9712c20fSFrederick Mayle   if (!minidump_system_info) {
4135*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpUnloadedModule code_identifier requires "
4136*9712c20fSFrederick Mayle                     "MinidumpSystemInfo";
4137*9712c20fSFrederick Mayle     return "";
4138*9712c20fSFrederick Mayle   }
4139*9712c20fSFrederick Mayle 
4140*9712c20fSFrederick Mayle   const MDRawSystemInfo* raw_system_info = minidump_system_info->system_info();
4141*9712c20fSFrederick Mayle   if (!raw_system_info) {
4142*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpUnloadedModule code_identifier requires "
4143*9712c20fSFrederick Mayle                  << "MDRawSystemInfo";
4144*9712c20fSFrederick Mayle     return "";
4145*9712c20fSFrederick Mayle   }
4146*9712c20fSFrederick Mayle 
4147*9712c20fSFrederick Mayle   string identifier;
4148*9712c20fSFrederick Mayle 
4149*9712c20fSFrederick Mayle   switch (raw_system_info->platform_id) {
4150*9712c20fSFrederick Mayle     case MD_OS_WIN32_NT:
4151*9712c20fSFrederick Mayle     case MD_OS_WIN32_WINDOWS: {
4152*9712c20fSFrederick Mayle       // Use the same format that the MS symbol server uses in filesystem
4153*9712c20fSFrederick Mayle       // hierarchies.
4154*9712c20fSFrederick Mayle       char identifier_string[17];
4155*9712c20fSFrederick Mayle       snprintf(identifier_string, sizeof(identifier_string), "%08X%x",
4156*9712c20fSFrederick Mayle                unloaded_module_.time_date_stamp,
4157*9712c20fSFrederick Mayle                unloaded_module_.size_of_image);
4158*9712c20fSFrederick Mayle       identifier = identifier_string;
4159*9712c20fSFrederick Mayle       break;
4160*9712c20fSFrederick Mayle     }
4161*9712c20fSFrederick Mayle 
4162*9712c20fSFrederick Mayle     case MD_OS_ANDROID:
4163*9712c20fSFrederick Mayle     case MD_OS_LINUX:
4164*9712c20fSFrederick Mayle     case MD_OS_MAC_OS_X:
4165*9712c20fSFrederick Mayle     case MD_OS_IOS:
4166*9712c20fSFrederick Mayle     case MD_OS_SOLARIS:
4167*9712c20fSFrederick Mayle     case MD_OS_NACL:
4168*9712c20fSFrederick Mayle     case MD_OS_PS3: {
4169*9712c20fSFrederick Mayle       // TODO(mmentovai): support uuid extension if present, otherwise fall
4170*9712c20fSFrederick Mayle       // back to version (from LC_ID_DYLIB?), otherwise fall back to something
4171*9712c20fSFrederick Mayle       // else.
4172*9712c20fSFrederick Mayle       identifier = "id";
4173*9712c20fSFrederick Mayle       break;
4174*9712c20fSFrederick Mayle     }
4175*9712c20fSFrederick Mayle 
4176*9712c20fSFrederick Mayle     default: {
4177*9712c20fSFrederick Mayle       // Without knowing what OS generated the dump, we can't generate a good
4178*9712c20fSFrederick Mayle       // identifier.  Return an empty string, signalling failure.
4179*9712c20fSFrederick Mayle       BPLOG(ERROR) << "MinidumpUnloadedModule code_identifier requires known "
4180*9712c20fSFrederick Mayle                    << "platform, found "
4181*9712c20fSFrederick Mayle                    << HexString(raw_system_info->platform_id);
4182*9712c20fSFrederick Mayle       break;
4183*9712c20fSFrederick Mayle     }
4184*9712c20fSFrederick Mayle   }
4185*9712c20fSFrederick Mayle 
4186*9712c20fSFrederick Mayle   return identifier;
4187*9712c20fSFrederick Mayle }
4188*9712c20fSFrederick Mayle 
debug_file() const4189*9712c20fSFrederick Mayle string MinidumpUnloadedModule::debug_file() const {
4190*9712c20fSFrederick Mayle   return "";  // No debug info provided with unloaded modules
4191*9712c20fSFrederick Mayle }
4192*9712c20fSFrederick Mayle 
debug_identifier() const4193*9712c20fSFrederick Mayle string MinidumpUnloadedModule::debug_identifier() const {
4194*9712c20fSFrederick Mayle   return "";  // No debug info provided with unloaded modules
4195*9712c20fSFrederick Mayle }
4196*9712c20fSFrederick Mayle 
version() const4197*9712c20fSFrederick Mayle string MinidumpUnloadedModule::version() const {
4198*9712c20fSFrederick Mayle   return "";  // No version info provided with unloaded modules
4199*9712c20fSFrederick Mayle }
4200*9712c20fSFrederick Mayle 
Copy() const4201*9712c20fSFrederick Mayle CodeModule* MinidumpUnloadedModule::Copy() const {
4202*9712c20fSFrederick Mayle   return new BasicCodeModule(this);
4203*9712c20fSFrederick Mayle }
4204*9712c20fSFrederick Mayle 
shrink_down_delta() const4205*9712c20fSFrederick Mayle uint64_t MinidumpUnloadedModule::shrink_down_delta() const {
4206*9712c20fSFrederick Mayle   return 0;
4207*9712c20fSFrederick Mayle }
4208*9712c20fSFrederick Mayle 
SetShrinkDownDelta(uint64_t shrink_down_delta)4209*9712c20fSFrederick Mayle void MinidumpUnloadedModule::SetShrinkDownDelta(uint64_t shrink_down_delta) {
4210*9712c20fSFrederick Mayle   // Not implemented
4211*9712c20fSFrederick Mayle   assert(false);
4212*9712c20fSFrederick Mayle }
4213*9712c20fSFrederick Mayle 
Read(uint32_t expected_size)4214*9712c20fSFrederick Mayle bool MinidumpUnloadedModule::Read(uint32_t expected_size) {
4215*9712c20fSFrederick Mayle 
4216*9712c20fSFrederick Mayle   delete name_;
4217*9712c20fSFrederick Mayle   valid_ = false;
4218*9712c20fSFrederick Mayle 
4219*9712c20fSFrederick Mayle   if (expected_size < sizeof(unloaded_module_)) {
4220*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpUnloadedModule expected size is less than size "
4221*9712c20fSFrederick Mayle                  << "of struct " << expected_size << " < "
4222*9712c20fSFrederick Mayle                  << sizeof(unloaded_module_);
4223*9712c20fSFrederick Mayle     return false;
4224*9712c20fSFrederick Mayle   }
4225*9712c20fSFrederick Mayle 
4226*9712c20fSFrederick Mayle   if (!minidump_->ReadBytes(&unloaded_module_, sizeof(unloaded_module_))) {
4227*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpUnloadedModule cannot read module";
4228*9712c20fSFrederick Mayle     return false;
4229*9712c20fSFrederick Mayle   }
4230*9712c20fSFrederick Mayle 
4231*9712c20fSFrederick Mayle   if (expected_size > sizeof(unloaded_module_)) {
4232*9712c20fSFrederick Mayle     uint32_t module_bytes_remaining = expected_size - sizeof(unloaded_module_);
4233*9712c20fSFrederick Mayle     off_t pos = minidump_->Tell();
4234*9712c20fSFrederick Mayle     if (!minidump_->SeekSet(pos + module_bytes_remaining)) {
4235*9712c20fSFrederick Mayle       BPLOG(ERROR) << "MinidumpUnloadedModule unable to seek to end of module";
4236*9712c20fSFrederick Mayle       return false;
4237*9712c20fSFrederick Mayle     }
4238*9712c20fSFrederick Mayle   }
4239*9712c20fSFrederick Mayle 
4240*9712c20fSFrederick Mayle   if (minidump_->swap()) {
4241*9712c20fSFrederick Mayle     Swap(&unloaded_module_.base_of_image);
4242*9712c20fSFrederick Mayle     Swap(&unloaded_module_.size_of_image);
4243*9712c20fSFrederick Mayle     Swap(&unloaded_module_.checksum);
4244*9712c20fSFrederick Mayle     Swap(&unloaded_module_.time_date_stamp);
4245*9712c20fSFrederick Mayle     Swap(&unloaded_module_.module_name_rva);
4246*9712c20fSFrederick Mayle   }
4247*9712c20fSFrederick Mayle 
4248*9712c20fSFrederick Mayle   // Check for base + size overflow or undersize.
4249*9712c20fSFrederick Mayle   if (unloaded_module_.size_of_image == 0 ||
4250*9712c20fSFrederick Mayle       unloaded_module_.size_of_image >
4251*9712c20fSFrederick Mayle           numeric_limits<uint64_t>::max() - unloaded_module_.base_of_image) {
4252*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpUnloadedModule has a module problem, " <<
4253*9712c20fSFrederick Mayle                     HexString(unloaded_module_.base_of_image) << "+" <<
4254*9712c20fSFrederick Mayle                     HexString(unloaded_module_.size_of_image);
4255*9712c20fSFrederick Mayle     return false;
4256*9712c20fSFrederick Mayle   }
4257*9712c20fSFrederick Mayle 
4258*9712c20fSFrederick Mayle 
4259*9712c20fSFrederick Mayle   module_valid_ = true;
4260*9712c20fSFrederick Mayle   return true;
4261*9712c20fSFrederick Mayle }
4262*9712c20fSFrederick Mayle 
ReadAuxiliaryData()4263*9712c20fSFrederick Mayle bool MinidumpUnloadedModule::ReadAuxiliaryData() {
4264*9712c20fSFrederick Mayle   if (!module_valid_) {
4265*9712c20fSFrederick Mayle     BPLOG(ERROR) << "Invalid MinidumpUnloadedModule for ReadAuxiliaryData";
4266*9712c20fSFrederick Mayle     return false;
4267*9712c20fSFrederick Mayle   }
4268*9712c20fSFrederick Mayle 
4269*9712c20fSFrederick Mayle   // Each module must have a name.
4270*9712c20fSFrederick Mayle   name_ = minidump_->ReadString(unloaded_module_.module_name_rva);
4271*9712c20fSFrederick Mayle   if (!name_) {
4272*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpUnloadedModule could not read name";
4273*9712c20fSFrederick Mayle     return false;
4274*9712c20fSFrederick Mayle   }
4275*9712c20fSFrederick Mayle 
4276*9712c20fSFrederick Mayle   // At this point, we have enough info for the module to be valid.
4277*9712c20fSFrederick Mayle   valid_ = true;
4278*9712c20fSFrederick Mayle   return true;
4279*9712c20fSFrederick Mayle }
4280*9712c20fSFrederick Mayle 
4281*9712c20fSFrederick Mayle //
4282*9712c20fSFrederick Mayle // MinidumpUnloadedModuleList
4283*9712c20fSFrederick Mayle //
4284*9712c20fSFrederick Mayle 
4285*9712c20fSFrederick Mayle 
4286*9712c20fSFrederick Mayle uint32_t MinidumpUnloadedModuleList::max_modules_ = 2048;
4287*9712c20fSFrederick Mayle 
4288*9712c20fSFrederick Mayle 
MinidumpUnloadedModuleList(Minidump * minidump)4289*9712c20fSFrederick Mayle MinidumpUnloadedModuleList::MinidumpUnloadedModuleList(Minidump* minidump)
4290*9712c20fSFrederick Mayle   : MinidumpStream(minidump),
4291*9712c20fSFrederick Mayle     range_map_(new RangeMap<uint64_t, unsigned int>()),
4292*9712c20fSFrederick Mayle     unloaded_modules_(NULL),
4293*9712c20fSFrederick Mayle     module_count_(0) {
4294*9712c20fSFrederick Mayle   range_map_->SetMergeStrategy(MergeRangeStrategy::kTruncateLower);
4295*9712c20fSFrederick Mayle }
4296*9712c20fSFrederick Mayle 
~MinidumpUnloadedModuleList()4297*9712c20fSFrederick Mayle MinidumpUnloadedModuleList::~MinidumpUnloadedModuleList() {
4298*9712c20fSFrederick Mayle   delete range_map_;
4299*9712c20fSFrederick Mayle   delete unloaded_modules_;
4300*9712c20fSFrederick Mayle }
4301*9712c20fSFrederick Mayle 
4302*9712c20fSFrederick Mayle 
Read(uint32_t expected_size)4303*9712c20fSFrederick Mayle bool MinidumpUnloadedModuleList::Read(uint32_t expected_size) {
4304*9712c20fSFrederick Mayle   range_map_->Clear();
4305*9712c20fSFrederick Mayle   delete unloaded_modules_;
4306*9712c20fSFrederick Mayle   unloaded_modules_ = NULL;
4307*9712c20fSFrederick Mayle   module_count_ = 0;
4308*9712c20fSFrederick Mayle 
4309*9712c20fSFrederick Mayle   valid_ = false;
4310*9712c20fSFrederick Mayle 
4311*9712c20fSFrederick Mayle   uint32_t size_of_header;
4312*9712c20fSFrederick Mayle   if (!minidump_->ReadBytes(&size_of_header, sizeof(size_of_header))) {
4313*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpUnloadedModuleList could not read header size";
4314*9712c20fSFrederick Mayle     return false;
4315*9712c20fSFrederick Mayle   }
4316*9712c20fSFrederick Mayle 
4317*9712c20fSFrederick Mayle   uint32_t size_of_entry;
4318*9712c20fSFrederick Mayle   if (!minidump_->ReadBytes(&size_of_entry, sizeof(size_of_entry))) {
4319*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpUnloadedModuleList could not read entry size";
4320*9712c20fSFrederick Mayle     return false;
4321*9712c20fSFrederick Mayle   }
4322*9712c20fSFrederick Mayle 
4323*9712c20fSFrederick Mayle   uint32_t number_of_entries;
4324*9712c20fSFrederick Mayle   if (!minidump_->ReadBytes(&number_of_entries, sizeof(number_of_entries))) {
4325*9712c20fSFrederick Mayle     BPLOG(ERROR) <<
4326*9712c20fSFrederick Mayle                  "MinidumpUnloadedModuleList could not read number of entries";
4327*9712c20fSFrederick Mayle     return false;
4328*9712c20fSFrederick Mayle   }
4329*9712c20fSFrederick Mayle 
4330*9712c20fSFrederick Mayle   if (minidump_->swap()) {
4331*9712c20fSFrederick Mayle     Swap(&size_of_header);
4332*9712c20fSFrederick Mayle     Swap(&size_of_entry);
4333*9712c20fSFrederick Mayle     Swap(&number_of_entries);
4334*9712c20fSFrederick Mayle   }
4335*9712c20fSFrederick Mayle 
4336*9712c20fSFrederick Mayle   uint32_t header_bytes_remaining = size_of_header - sizeof(size_of_header) -
4337*9712c20fSFrederick Mayle       sizeof(size_of_entry) - sizeof(number_of_entries);
4338*9712c20fSFrederick Mayle   if (header_bytes_remaining) {
4339*9712c20fSFrederick Mayle     off_t pos = minidump_->Tell();
4340*9712c20fSFrederick Mayle     if (!minidump_->SeekSet(pos + header_bytes_remaining)) {
4341*9712c20fSFrederick Mayle       BPLOG(ERROR) << "MinidumpUnloadedModuleList could not read header sized "
4342*9712c20fSFrederick Mayle                    << size_of_header;
4343*9712c20fSFrederick Mayle       return false;
4344*9712c20fSFrederick Mayle     }
4345*9712c20fSFrederick Mayle   }
4346*9712c20fSFrederick Mayle 
4347*9712c20fSFrederick Mayle   if (expected_size != size_of_header + (size_of_entry * number_of_entries)) {
4348*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpUnloadedModuleList expected_size mismatch " <<
4349*9712c20fSFrederick Mayle                  expected_size << " != " << size_of_header << " + (" <<
4350*9712c20fSFrederick Mayle                  size_of_entry << " * " << number_of_entries << ")";
4351*9712c20fSFrederick Mayle     return false;
4352*9712c20fSFrederick Mayle   }
4353*9712c20fSFrederick Mayle 
4354*9712c20fSFrederick Mayle   if (number_of_entries > max_modules_) {
4355*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpUnloadedModuleList count " <<
4356*9712c20fSFrederick Mayle                  number_of_entries << " exceeds maximum " << max_modules_;
4357*9712c20fSFrederick Mayle     return false;
4358*9712c20fSFrederick Mayle   }
4359*9712c20fSFrederick Mayle 
4360*9712c20fSFrederick Mayle   if (number_of_entries != 0) {
4361*9712c20fSFrederick Mayle     scoped_ptr<MinidumpUnloadedModules> modules(
4362*9712c20fSFrederick Mayle         new MinidumpUnloadedModules(number_of_entries,
4363*9712c20fSFrederick Mayle                                     MinidumpUnloadedModule(minidump_)));
4364*9712c20fSFrederick Mayle 
4365*9712c20fSFrederick Mayle     for (unsigned int module_index = 0;
4366*9712c20fSFrederick Mayle          module_index < number_of_entries;
4367*9712c20fSFrederick Mayle          ++module_index) {
4368*9712c20fSFrederick Mayle       MinidumpUnloadedModule* module = &(*modules)[module_index];
4369*9712c20fSFrederick Mayle 
4370*9712c20fSFrederick Mayle       if (!module->Read(size_of_entry)) {
4371*9712c20fSFrederick Mayle         BPLOG(ERROR) << "MinidumpUnloadedModuleList could not read module " <<
4372*9712c20fSFrederick Mayle                      module_index << "/" << number_of_entries;
4373*9712c20fSFrederick Mayle         return false;
4374*9712c20fSFrederick Mayle       }
4375*9712c20fSFrederick Mayle     }
4376*9712c20fSFrederick Mayle 
4377*9712c20fSFrederick Mayle     for (unsigned int module_index = 0;
4378*9712c20fSFrederick Mayle          module_index < number_of_entries;
4379*9712c20fSFrederick Mayle          ++module_index) {
4380*9712c20fSFrederick Mayle       MinidumpUnloadedModule* module = &(*modules)[module_index];
4381*9712c20fSFrederick Mayle 
4382*9712c20fSFrederick Mayle       if (!module->ReadAuxiliaryData()) {
4383*9712c20fSFrederick Mayle         BPLOG(ERROR) << "MinidumpUnloadedModuleList could not read required "
4384*9712c20fSFrederick Mayle                      "module auxiliary data for module " <<
4385*9712c20fSFrederick Mayle                      module_index << "/" << number_of_entries;
4386*9712c20fSFrederick Mayle         return false;
4387*9712c20fSFrederick Mayle       }
4388*9712c20fSFrederick Mayle 
4389*9712c20fSFrederick Mayle       uint64_t base_address = module->base_address();
4390*9712c20fSFrederick Mayle       uint64_t module_size = module->size();
4391*9712c20fSFrederick Mayle 
4392*9712c20fSFrederick Mayle       // Ignore any failures for conflicting address ranges
4393*9712c20fSFrederick Mayle       range_map_->StoreRange(base_address, module_size, module_index);
4394*9712c20fSFrederick Mayle 
4395*9712c20fSFrederick Mayle     }
4396*9712c20fSFrederick Mayle     unloaded_modules_ = modules.release();
4397*9712c20fSFrederick Mayle   }
4398*9712c20fSFrederick Mayle 
4399*9712c20fSFrederick Mayle   module_count_ = number_of_entries;
4400*9712c20fSFrederick Mayle   valid_ = true;
4401*9712c20fSFrederick Mayle   return true;
4402*9712c20fSFrederick Mayle }
4403*9712c20fSFrederick Mayle 
GetModuleForAddress(uint64_t address) const4404*9712c20fSFrederick Mayle const MinidumpUnloadedModule* MinidumpUnloadedModuleList::GetModuleForAddress(
4405*9712c20fSFrederick Mayle     uint64_t address) const {
4406*9712c20fSFrederick Mayle   if (!valid_) {
4407*9712c20fSFrederick Mayle     BPLOG(ERROR)
4408*9712c20fSFrederick Mayle         << "Invalid MinidumpUnloadedModuleList for GetModuleForAddress";
4409*9712c20fSFrederick Mayle     return NULL;
4410*9712c20fSFrederick Mayle   }
4411*9712c20fSFrederick Mayle 
4412*9712c20fSFrederick Mayle   unsigned int module_index;
4413*9712c20fSFrederick Mayle   if (!range_map_->RetrieveRange(address, &module_index, NULL /* base */,
4414*9712c20fSFrederick Mayle                                  NULL /* delta */, NULL /* size */)) {
4415*9712c20fSFrederick Mayle     BPLOG(INFO) << "MinidumpUnloadedModuleList has no module at "
4416*9712c20fSFrederick Mayle                 << HexString(address);
4417*9712c20fSFrederick Mayle     return NULL;
4418*9712c20fSFrederick Mayle   }
4419*9712c20fSFrederick Mayle 
4420*9712c20fSFrederick Mayle   return GetModuleAtIndex(module_index);
4421*9712c20fSFrederick Mayle }
4422*9712c20fSFrederick Mayle 
4423*9712c20fSFrederick Mayle const MinidumpUnloadedModule*
GetMainModule() const4424*9712c20fSFrederick Mayle MinidumpUnloadedModuleList::GetMainModule() const {
4425*9712c20fSFrederick Mayle   return NULL;
4426*9712c20fSFrederick Mayle }
4427*9712c20fSFrederick Mayle 
4428*9712c20fSFrederick Mayle const MinidumpUnloadedModule*
GetModuleAtSequence(unsigned int sequence) const4429*9712c20fSFrederick Mayle MinidumpUnloadedModuleList::GetModuleAtSequence(unsigned int sequence) const {
4430*9712c20fSFrederick Mayle   if (!valid_) {
4431*9712c20fSFrederick Mayle     BPLOG(ERROR)
4432*9712c20fSFrederick Mayle         << "Invalid MinidumpUnloadedModuleList for GetModuleAtSequence";
4433*9712c20fSFrederick Mayle     return NULL;
4434*9712c20fSFrederick Mayle   }
4435*9712c20fSFrederick Mayle 
4436*9712c20fSFrederick Mayle   if (sequence >= module_count_) {
4437*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpUnloadedModuleList sequence out of range: "
4438*9712c20fSFrederick Mayle                  << sequence << "/" << module_count_;
4439*9712c20fSFrederick Mayle     return NULL;
4440*9712c20fSFrederick Mayle   }
4441*9712c20fSFrederick Mayle 
4442*9712c20fSFrederick Mayle   unsigned int module_index;
4443*9712c20fSFrederick Mayle   if (!range_map_->RetrieveRangeAtIndex(sequence, &module_index,
4444*9712c20fSFrederick Mayle                                         NULL /* base */, NULL /* delta */,
4445*9712c20fSFrederick Mayle                                         NULL /* size */)) {
4446*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpUnloadedModuleList has no module at sequence "
4447*9712c20fSFrederick Mayle                  << sequence;
4448*9712c20fSFrederick Mayle     return NULL;
4449*9712c20fSFrederick Mayle   }
4450*9712c20fSFrederick Mayle 
4451*9712c20fSFrederick Mayle   return GetModuleAtIndex(module_index);
4452*9712c20fSFrederick Mayle }
4453*9712c20fSFrederick Mayle 
4454*9712c20fSFrederick Mayle const MinidumpUnloadedModule*
GetModuleAtIndex(unsigned int index) const4455*9712c20fSFrederick Mayle MinidumpUnloadedModuleList::GetModuleAtIndex(
4456*9712c20fSFrederick Mayle     unsigned int index) const {
4457*9712c20fSFrederick Mayle   if (!valid_) {
4458*9712c20fSFrederick Mayle     BPLOG(ERROR) << "Invalid MinidumpUnloadedModuleList for GetModuleAtIndex";
4459*9712c20fSFrederick Mayle     return NULL;
4460*9712c20fSFrederick Mayle   }
4461*9712c20fSFrederick Mayle 
4462*9712c20fSFrederick Mayle   if (index >= module_count_) {
4463*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpUnloadedModuleList index out of range: "
4464*9712c20fSFrederick Mayle                  << index << "/" << module_count_;
4465*9712c20fSFrederick Mayle     return NULL;
4466*9712c20fSFrederick Mayle   }
4467*9712c20fSFrederick Mayle 
4468*9712c20fSFrederick Mayle   return &(*unloaded_modules_)[index];
4469*9712c20fSFrederick Mayle }
4470*9712c20fSFrederick Mayle 
Copy() const4471*9712c20fSFrederick Mayle const CodeModules* MinidumpUnloadedModuleList::Copy() const {
4472*9712c20fSFrederick Mayle   return new BasicCodeModules(this, range_map_->GetMergeStrategy());
4473*9712c20fSFrederick Mayle }
4474*9712c20fSFrederick Mayle 
4475*9712c20fSFrederick Mayle vector<linked_ptr<const CodeModule>>
GetShrunkRangeModules() const4476*9712c20fSFrederick Mayle MinidumpUnloadedModuleList::GetShrunkRangeModules() const {
4477*9712c20fSFrederick Mayle   return vector<linked_ptr<const CodeModule> >();
4478*9712c20fSFrederick Mayle }
4479*9712c20fSFrederick Mayle 
4480*9712c20fSFrederick Mayle 
4481*9712c20fSFrederick Mayle //
4482*9712c20fSFrederick Mayle // MinidumpMiscInfo
4483*9712c20fSFrederick Mayle //
4484*9712c20fSFrederick Mayle 
4485*9712c20fSFrederick Mayle 
MinidumpMiscInfo(Minidump * minidump)4486*9712c20fSFrederick Mayle MinidumpMiscInfo::MinidumpMiscInfo(Minidump* minidump)
4487*9712c20fSFrederick Mayle     : MinidumpStream(minidump),
4488*9712c20fSFrederick Mayle       misc_info_() {
4489*9712c20fSFrederick Mayle }
4490*9712c20fSFrederick Mayle 
4491*9712c20fSFrederick Mayle 
Read(uint32_t expected_size)4492*9712c20fSFrederick Mayle bool MinidumpMiscInfo::Read(uint32_t expected_size) {
4493*9712c20fSFrederick Mayle   valid_ = false;
4494*9712c20fSFrederick Mayle 
4495*9712c20fSFrederick Mayle   size_t padding = 0;
4496*9712c20fSFrederick Mayle   if (expected_size != MD_MISCINFO_SIZE &&
4497*9712c20fSFrederick Mayle       expected_size != MD_MISCINFO2_SIZE &&
4498*9712c20fSFrederick Mayle       expected_size != MD_MISCINFO3_SIZE &&
4499*9712c20fSFrederick Mayle       expected_size != MD_MISCINFO4_SIZE &&
4500*9712c20fSFrederick Mayle       expected_size != MD_MISCINFO5_SIZE) {
4501*9712c20fSFrederick Mayle     if (expected_size > MD_MISCINFO5_SIZE) {
4502*9712c20fSFrederick Mayle       // Only read the part of the misc info structure we know how to handle
4503*9712c20fSFrederick Mayle       BPLOG(INFO) << "MinidumpMiscInfo size larger than expected "
4504*9712c20fSFrederick Mayle                   << expected_size << ", skipping over the unknown part";
4505*9712c20fSFrederick Mayle       padding = expected_size - MD_MISCINFO5_SIZE;
4506*9712c20fSFrederick Mayle       expected_size = MD_MISCINFO5_SIZE;
4507*9712c20fSFrederick Mayle     } else {
4508*9712c20fSFrederick Mayle       BPLOG(ERROR) << "MinidumpMiscInfo size mismatch, " << expected_size
4509*9712c20fSFrederick Mayle                   << " != " << MD_MISCINFO_SIZE << ", " << MD_MISCINFO2_SIZE
4510*9712c20fSFrederick Mayle                   << ", " << MD_MISCINFO3_SIZE << ", " << MD_MISCINFO4_SIZE
4511*9712c20fSFrederick Mayle                   << ", " << MD_MISCINFO5_SIZE << ")";
4512*9712c20fSFrederick Mayle       return false;
4513*9712c20fSFrederick Mayle     }
4514*9712c20fSFrederick Mayle   }
4515*9712c20fSFrederick Mayle 
4516*9712c20fSFrederick Mayle   if (!minidump_->ReadBytes(&misc_info_, expected_size)) {
4517*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpMiscInfo cannot read miscellaneous info";
4518*9712c20fSFrederick Mayle     return false;
4519*9712c20fSFrederick Mayle   }
4520*9712c20fSFrederick Mayle 
4521*9712c20fSFrederick Mayle   if (padding != 0) {
4522*9712c20fSFrederick Mayle     off_t saved_position = minidump_->Tell();
4523*9712c20fSFrederick Mayle     if (saved_position == -1) {
4524*9712c20fSFrederick Mayle       BPLOG(ERROR) << "MinidumpMiscInfo could not tell the current position";
4525*9712c20fSFrederick Mayle       return false;
4526*9712c20fSFrederick Mayle     }
4527*9712c20fSFrederick Mayle 
4528*9712c20fSFrederick Mayle     if (!minidump_->SeekSet(saved_position + static_cast<off_t>(padding))) {
4529*9712c20fSFrederick Mayle       BPLOG(ERROR) << "MinidumpMiscInfo could not seek past the miscellaneous "
4530*9712c20fSFrederick Mayle                    << "info structure";
4531*9712c20fSFrederick Mayle       return false;
4532*9712c20fSFrederick Mayle     }
4533*9712c20fSFrederick Mayle   }
4534*9712c20fSFrederick Mayle 
4535*9712c20fSFrederick Mayle   if (minidump_->swap()) {
4536*9712c20fSFrederick Mayle     // Swap version 1 fields
4537*9712c20fSFrederick Mayle     Swap(&misc_info_.size_of_info);
4538*9712c20fSFrederick Mayle     Swap(&misc_info_.flags1);
4539*9712c20fSFrederick Mayle     Swap(&misc_info_.process_id);
4540*9712c20fSFrederick Mayle     Swap(&misc_info_.process_create_time);
4541*9712c20fSFrederick Mayle     Swap(&misc_info_.process_user_time);
4542*9712c20fSFrederick Mayle     Swap(&misc_info_.process_kernel_time);
4543*9712c20fSFrederick Mayle     if (misc_info_.size_of_info > MD_MISCINFO_SIZE) {
4544*9712c20fSFrederick Mayle       // Swap version 2 fields
4545*9712c20fSFrederick Mayle       Swap(&misc_info_.processor_max_mhz);
4546*9712c20fSFrederick Mayle       Swap(&misc_info_.processor_current_mhz);
4547*9712c20fSFrederick Mayle       Swap(&misc_info_.processor_mhz_limit);
4548*9712c20fSFrederick Mayle       Swap(&misc_info_.processor_max_idle_state);
4549*9712c20fSFrederick Mayle       Swap(&misc_info_.processor_current_idle_state);
4550*9712c20fSFrederick Mayle     }
4551*9712c20fSFrederick Mayle     if (misc_info_.size_of_info > MD_MISCINFO2_SIZE) {
4552*9712c20fSFrederick Mayle       // Swap version 3 fields
4553*9712c20fSFrederick Mayle       Swap(&misc_info_.process_integrity_level);
4554*9712c20fSFrederick Mayle       Swap(&misc_info_.process_execute_flags);
4555*9712c20fSFrederick Mayle       Swap(&misc_info_.protected_process);
4556*9712c20fSFrederick Mayle       Swap(&misc_info_.time_zone_id);
4557*9712c20fSFrederick Mayle       Swap(&misc_info_.time_zone);
4558*9712c20fSFrederick Mayle     }
4559*9712c20fSFrederick Mayle     if (misc_info_.size_of_info > MD_MISCINFO3_SIZE) {
4560*9712c20fSFrederick Mayle       // Swap version 4 fields.
4561*9712c20fSFrederick Mayle       // Do not swap UTF-16 strings.  The swap is done as part of the
4562*9712c20fSFrederick Mayle       // conversion to UTF-8 (code follows below).
4563*9712c20fSFrederick Mayle     }
4564*9712c20fSFrederick Mayle     if (misc_info_.size_of_info > MD_MISCINFO4_SIZE) {
4565*9712c20fSFrederick Mayle       // Swap version 5 fields
4566*9712c20fSFrederick Mayle       Swap(&misc_info_.xstate_data);
4567*9712c20fSFrederick Mayle       Swap(&misc_info_.process_cookie);
4568*9712c20fSFrederick Mayle     }
4569*9712c20fSFrederick Mayle   }
4570*9712c20fSFrederick Mayle 
4571*9712c20fSFrederick Mayle   if (expected_size + padding != misc_info_.size_of_info) {
4572*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpMiscInfo size mismatch, " <<
4573*9712c20fSFrederick Mayle                     expected_size << " != " << misc_info_.size_of_info;
4574*9712c20fSFrederick Mayle     return false;
4575*9712c20fSFrederick Mayle   }
4576*9712c20fSFrederick Mayle 
4577*9712c20fSFrederick Mayle   // Convert UTF-16 strings
4578*9712c20fSFrederick Mayle   if (misc_info_.size_of_info > MD_MISCINFO2_SIZE) {
4579*9712c20fSFrederick Mayle     // Convert UTF-16 strings in version 3 fields
4580*9712c20fSFrederick Mayle     ConvertUTF16BufferToUTF8String(misc_info_.time_zone.standard_name,
4581*9712c20fSFrederick Mayle                                    sizeof(misc_info_.time_zone.standard_name),
4582*9712c20fSFrederick Mayle                                    &standard_name_, minidump_->swap());
4583*9712c20fSFrederick Mayle     ConvertUTF16BufferToUTF8String(misc_info_.time_zone.daylight_name,
4584*9712c20fSFrederick Mayle                                    sizeof(misc_info_.time_zone.daylight_name),
4585*9712c20fSFrederick Mayle                                    &daylight_name_, minidump_->swap());
4586*9712c20fSFrederick Mayle   }
4587*9712c20fSFrederick Mayle   if (misc_info_.size_of_info > MD_MISCINFO3_SIZE) {
4588*9712c20fSFrederick Mayle     // Convert UTF-16 strings in version 4 fields
4589*9712c20fSFrederick Mayle     ConvertUTF16BufferToUTF8String(misc_info_.build_string,
4590*9712c20fSFrederick Mayle                                    sizeof(misc_info_.build_string),
4591*9712c20fSFrederick Mayle                                    &build_string_, minidump_->swap());
4592*9712c20fSFrederick Mayle     ConvertUTF16BufferToUTF8String(misc_info_.dbg_bld_str,
4593*9712c20fSFrederick Mayle                                    sizeof(misc_info_.dbg_bld_str),
4594*9712c20fSFrederick Mayle                                    &dbg_bld_str_, minidump_->swap());
4595*9712c20fSFrederick Mayle   }
4596*9712c20fSFrederick Mayle 
4597*9712c20fSFrederick Mayle   valid_ = true;
4598*9712c20fSFrederick Mayle   return true;
4599*9712c20fSFrederick Mayle }
4600*9712c20fSFrederick Mayle 
4601*9712c20fSFrederick Mayle 
Print()4602*9712c20fSFrederick Mayle void MinidumpMiscInfo::Print() {
4603*9712c20fSFrederick Mayle   if (!valid_) {
4604*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpMiscInfo cannot print invalid data";
4605*9712c20fSFrederick Mayle     return;
4606*9712c20fSFrederick Mayle   }
4607*9712c20fSFrederick Mayle 
4608*9712c20fSFrederick Mayle   printf("MDRawMiscInfo\n");
4609*9712c20fSFrederick Mayle   // Print version 1 fields
4610*9712c20fSFrederick Mayle   printf("  size_of_info                 = %d\n",   misc_info_.size_of_info);
4611*9712c20fSFrederick Mayle   printf("  flags1                       = 0x%x\n", misc_info_.flags1);
4612*9712c20fSFrederick Mayle   printf("  process_id                   = ");
4613*9712c20fSFrederick Mayle   PrintValueOrInvalid(misc_info_.flags1 & MD_MISCINFO_FLAGS1_PROCESS_ID,
4614*9712c20fSFrederick Mayle                       kNumberFormatDecimal, misc_info_.process_id);
4615*9712c20fSFrederick Mayle   if (misc_info_.flags1 & MD_MISCINFO_FLAGS1_PROCESS_TIMES) {
4616*9712c20fSFrederick Mayle     printf("  process_create_time          = 0x%x %s\n",
4617*9712c20fSFrederick Mayle            misc_info_.process_create_time,
4618*9712c20fSFrederick Mayle            TimeTToUTCString(misc_info_.process_create_time).c_str());
4619*9712c20fSFrederick Mayle   } else {
4620*9712c20fSFrederick Mayle     printf("  process_create_time          = (invalid)\n");
4621*9712c20fSFrederick Mayle   }
4622*9712c20fSFrederick Mayle   printf("  process_user_time            = ");
4623*9712c20fSFrederick Mayle   PrintValueOrInvalid(misc_info_.flags1 & MD_MISCINFO_FLAGS1_PROCESS_TIMES,
4624*9712c20fSFrederick Mayle                       kNumberFormatDecimal, misc_info_.process_user_time);
4625*9712c20fSFrederick Mayle   printf("  process_kernel_time          = ");
4626*9712c20fSFrederick Mayle   PrintValueOrInvalid(misc_info_.flags1 & MD_MISCINFO_FLAGS1_PROCESS_TIMES,
4627*9712c20fSFrederick Mayle                       kNumberFormatDecimal, misc_info_.process_kernel_time);
4628*9712c20fSFrederick Mayle   if (misc_info_.size_of_info > MD_MISCINFO_SIZE) {
4629*9712c20fSFrederick Mayle     // Print version 2 fields
4630*9712c20fSFrederick Mayle     printf("  processor_max_mhz            = ");
4631*9712c20fSFrederick Mayle     PrintValueOrInvalid(misc_info_.flags1 &
4632*9712c20fSFrederick Mayle                             MD_MISCINFO_FLAGS1_PROCESSOR_POWER_INFO,
4633*9712c20fSFrederick Mayle                         kNumberFormatDecimal, misc_info_.processor_max_mhz);
4634*9712c20fSFrederick Mayle     printf("  processor_current_mhz        = ");
4635*9712c20fSFrederick Mayle     PrintValueOrInvalid(misc_info_.flags1 &
4636*9712c20fSFrederick Mayle                             MD_MISCINFO_FLAGS1_PROCESSOR_POWER_INFO,
4637*9712c20fSFrederick Mayle                         kNumberFormatDecimal, misc_info_.processor_current_mhz);
4638*9712c20fSFrederick Mayle     printf("  processor_mhz_limit          = ");
4639*9712c20fSFrederick Mayle     PrintValueOrInvalid(misc_info_.flags1 &
4640*9712c20fSFrederick Mayle                             MD_MISCINFO_FLAGS1_PROCESSOR_POWER_INFO,
4641*9712c20fSFrederick Mayle                         kNumberFormatDecimal, misc_info_.processor_mhz_limit);
4642*9712c20fSFrederick Mayle     printf("  processor_max_idle_state     = ");
4643*9712c20fSFrederick Mayle     PrintValueOrInvalid(misc_info_.flags1 &
4644*9712c20fSFrederick Mayle                             MD_MISCINFO_FLAGS1_PROCESSOR_POWER_INFO,
4645*9712c20fSFrederick Mayle                         kNumberFormatDecimal,
4646*9712c20fSFrederick Mayle                         misc_info_.processor_max_idle_state);
4647*9712c20fSFrederick Mayle     printf("  processor_current_idle_state = ");
4648*9712c20fSFrederick Mayle     PrintValueOrInvalid(misc_info_.flags1 &
4649*9712c20fSFrederick Mayle                             MD_MISCINFO_FLAGS1_PROCESSOR_POWER_INFO,
4650*9712c20fSFrederick Mayle                         kNumberFormatDecimal,
4651*9712c20fSFrederick Mayle                         misc_info_.processor_current_idle_state);
4652*9712c20fSFrederick Mayle   }
4653*9712c20fSFrederick Mayle   if (misc_info_.size_of_info > MD_MISCINFO2_SIZE) {
4654*9712c20fSFrederick Mayle     // Print version 3 fields
4655*9712c20fSFrederick Mayle     printf("  process_integrity_level      = ");
4656*9712c20fSFrederick Mayle     PrintValueOrInvalid(misc_info_.flags1 &
4657*9712c20fSFrederick Mayle                             MD_MISCINFO_FLAGS1_PROCESS_INTEGRITY,
4658*9712c20fSFrederick Mayle                         kNumberFormatHexadecimal,
4659*9712c20fSFrederick Mayle                         misc_info_.process_integrity_level);
4660*9712c20fSFrederick Mayle     printf("  process_execute_flags        = ");
4661*9712c20fSFrederick Mayle     PrintValueOrInvalid(misc_info_.flags1 &
4662*9712c20fSFrederick Mayle                             MD_MISCINFO_FLAGS1_PROCESS_EXECUTE_FLAGS,
4663*9712c20fSFrederick Mayle                         kNumberFormatHexadecimal,
4664*9712c20fSFrederick Mayle                         misc_info_.process_execute_flags);
4665*9712c20fSFrederick Mayle     printf("  protected_process            = ");
4666*9712c20fSFrederick Mayle     PrintValueOrInvalid(misc_info_.flags1 &
4667*9712c20fSFrederick Mayle                             MD_MISCINFO_FLAGS1_PROTECTED_PROCESS,
4668*9712c20fSFrederick Mayle                         kNumberFormatDecimal, misc_info_.protected_process);
4669*9712c20fSFrederick Mayle     printf("  time_zone_id                 = ");
4670*9712c20fSFrederick Mayle     PrintValueOrInvalid(misc_info_.flags1 & MD_MISCINFO_FLAGS1_TIMEZONE,
4671*9712c20fSFrederick Mayle                         kNumberFormatDecimal, misc_info_.time_zone_id);
4672*9712c20fSFrederick Mayle     if (misc_info_.flags1 & MD_MISCINFO_FLAGS1_TIMEZONE) {
4673*9712c20fSFrederick Mayle       printf("  time_zone.bias               = %d\n",
4674*9712c20fSFrederick Mayle              misc_info_.time_zone.bias);
4675*9712c20fSFrederick Mayle       printf("  time_zone.standard_name      = %s\n", standard_name_.c_str());
4676*9712c20fSFrederick Mayle       printf("  time_zone.standard_date      = "
4677*9712c20fSFrederick Mayle                  "%04d-%02d-%02d (%d) %02d:%02d:%02d.%03d\n",
4678*9712c20fSFrederick Mayle              misc_info_.time_zone.standard_date.year,
4679*9712c20fSFrederick Mayle              misc_info_.time_zone.standard_date.month,
4680*9712c20fSFrederick Mayle              misc_info_.time_zone.standard_date.day,
4681*9712c20fSFrederick Mayle              misc_info_.time_zone.standard_date.day_of_week,
4682*9712c20fSFrederick Mayle              misc_info_.time_zone.standard_date.hour,
4683*9712c20fSFrederick Mayle              misc_info_.time_zone.standard_date.minute,
4684*9712c20fSFrederick Mayle              misc_info_.time_zone.standard_date.second,
4685*9712c20fSFrederick Mayle              misc_info_.time_zone.standard_date.milliseconds);
4686*9712c20fSFrederick Mayle       printf("  time_zone.standard_bias      = %d\n",
4687*9712c20fSFrederick Mayle              misc_info_.time_zone.standard_bias);
4688*9712c20fSFrederick Mayle       printf("  time_zone.daylight_name      = %s\n", daylight_name_.c_str());
4689*9712c20fSFrederick Mayle       printf("  time_zone.daylight_date      = "
4690*9712c20fSFrederick Mayle                  "%04d-%02d-%02d (%d) %02d:%02d:%02d.%03d\n",
4691*9712c20fSFrederick Mayle              misc_info_.time_zone.daylight_date.year,
4692*9712c20fSFrederick Mayle              misc_info_.time_zone.daylight_date.month,
4693*9712c20fSFrederick Mayle              misc_info_.time_zone.daylight_date.day,
4694*9712c20fSFrederick Mayle              misc_info_.time_zone.daylight_date.day_of_week,
4695*9712c20fSFrederick Mayle              misc_info_.time_zone.daylight_date.hour,
4696*9712c20fSFrederick Mayle              misc_info_.time_zone.daylight_date.minute,
4697*9712c20fSFrederick Mayle              misc_info_.time_zone.daylight_date.second,
4698*9712c20fSFrederick Mayle              misc_info_.time_zone.daylight_date.milliseconds);
4699*9712c20fSFrederick Mayle       printf("  time_zone.daylight_bias      = %d\n",
4700*9712c20fSFrederick Mayle              misc_info_.time_zone.daylight_bias);
4701*9712c20fSFrederick Mayle     } else {
4702*9712c20fSFrederick Mayle       printf("  time_zone.bias               = (invalid)\n");
4703*9712c20fSFrederick Mayle       printf("  time_zone.standard_name      = (invalid)\n");
4704*9712c20fSFrederick Mayle       printf("  time_zone.standard_date      = (invalid)\n");
4705*9712c20fSFrederick Mayle       printf("  time_zone.standard_bias      = (invalid)\n");
4706*9712c20fSFrederick Mayle       printf("  time_zone.daylight_name      = (invalid)\n");
4707*9712c20fSFrederick Mayle       printf("  time_zone.daylight_date      = (invalid)\n");
4708*9712c20fSFrederick Mayle       printf("  time_zone.daylight_bias      = (invalid)\n");
4709*9712c20fSFrederick Mayle     }
4710*9712c20fSFrederick Mayle   }
4711*9712c20fSFrederick Mayle   if (misc_info_.size_of_info > MD_MISCINFO3_SIZE) {
4712*9712c20fSFrederick Mayle     // Print version 4 fields
4713*9712c20fSFrederick Mayle     if (misc_info_.flags1 & MD_MISCINFO_FLAGS1_BUILDSTRING) {
4714*9712c20fSFrederick Mayle       printf("  build_string                 = %s\n", build_string_.c_str());
4715*9712c20fSFrederick Mayle       printf("  dbg_bld_str                  = %s\n", dbg_bld_str_.c_str());
4716*9712c20fSFrederick Mayle     } else {
4717*9712c20fSFrederick Mayle       printf("  build_string                 = (invalid)\n");
4718*9712c20fSFrederick Mayle       printf("  dbg_bld_str                  = (invalid)\n");
4719*9712c20fSFrederick Mayle     }
4720*9712c20fSFrederick Mayle   }
4721*9712c20fSFrederick Mayle   if (misc_info_.size_of_info > MD_MISCINFO4_SIZE) {
4722*9712c20fSFrederick Mayle     // Print version 5 fields
4723*9712c20fSFrederick Mayle     if (misc_info_.flags1 & MD_MISCINFO_FLAGS1_PROCESS_COOKIE) {
4724*9712c20fSFrederick Mayle       printf("  xstate_data.size_of_info     = %d\n",
4725*9712c20fSFrederick Mayle              misc_info_.xstate_data.size_of_info);
4726*9712c20fSFrederick Mayle       printf("  xstate_data.context_size     = %d\n",
4727*9712c20fSFrederick Mayle              misc_info_.xstate_data.context_size);
4728*9712c20fSFrederick Mayle       printf("  xstate_data.enabled_features = 0x%" PRIx64 "\n",
4729*9712c20fSFrederick Mayle              misc_info_.xstate_data.enabled_features);
4730*9712c20fSFrederick Mayle       for (size_t i = 0; i < MD_MAXIMUM_XSTATE_FEATURES; i++) {
4731*9712c20fSFrederick Mayle         if ((misc_info_.xstate_data.enabled_features >> i) & 1) {
4732*9712c20fSFrederick Mayle           printf("  xstate_data.features[%02zu]     = { %d, %d }\n", i,
4733*9712c20fSFrederick Mayle                  misc_info_.xstate_data.features[i].offset,
4734*9712c20fSFrederick Mayle                  misc_info_.xstate_data.features[i].size);
4735*9712c20fSFrederick Mayle         }
4736*9712c20fSFrederick Mayle       }
4737*9712c20fSFrederick Mayle       if (misc_info_.xstate_data.enabled_features == 0) {
4738*9712c20fSFrederick Mayle         printf("  xstate_data.features[]       = (empty)\n");
4739*9712c20fSFrederick Mayle       }
4740*9712c20fSFrederick Mayle       printf("  process_cookie               = %d\n",
4741*9712c20fSFrederick Mayle              misc_info_.process_cookie);
4742*9712c20fSFrederick Mayle     } else {
4743*9712c20fSFrederick Mayle       printf("  xstate_data.size_of_info     = (invalid)\n");
4744*9712c20fSFrederick Mayle       printf("  xstate_data.context_size     = (invalid)\n");
4745*9712c20fSFrederick Mayle       printf("  xstate_data.enabled_features = (invalid)\n");
4746*9712c20fSFrederick Mayle       printf("  xstate_data.features[]       = (invalid)\n");
4747*9712c20fSFrederick Mayle       printf("  process_cookie               = (invalid)\n");
4748*9712c20fSFrederick Mayle     }
4749*9712c20fSFrederick Mayle   }
4750*9712c20fSFrederick Mayle   printf("\n");
4751*9712c20fSFrederick Mayle }
4752*9712c20fSFrederick Mayle 
4753*9712c20fSFrederick Mayle 
4754*9712c20fSFrederick Mayle //
4755*9712c20fSFrederick Mayle // MinidumpBreakpadInfo
4756*9712c20fSFrederick Mayle //
4757*9712c20fSFrederick Mayle 
4758*9712c20fSFrederick Mayle 
MinidumpBreakpadInfo(Minidump * minidump)4759*9712c20fSFrederick Mayle MinidumpBreakpadInfo::MinidumpBreakpadInfo(Minidump* minidump)
4760*9712c20fSFrederick Mayle     : MinidumpStream(minidump),
4761*9712c20fSFrederick Mayle       breakpad_info_() {
4762*9712c20fSFrederick Mayle }
4763*9712c20fSFrederick Mayle 
4764*9712c20fSFrederick Mayle 
Read(uint32_t expected_size)4765*9712c20fSFrederick Mayle bool MinidumpBreakpadInfo::Read(uint32_t expected_size) {
4766*9712c20fSFrederick Mayle   valid_ = false;
4767*9712c20fSFrederick Mayle 
4768*9712c20fSFrederick Mayle   if (expected_size != sizeof(breakpad_info_)) {
4769*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpBreakpadInfo size mismatch, " << expected_size <<
4770*9712c20fSFrederick Mayle                     " != " << sizeof(breakpad_info_);
4771*9712c20fSFrederick Mayle     return false;
4772*9712c20fSFrederick Mayle   }
4773*9712c20fSFrederick Mayle 
4774*9712c20fSFrederick Mayle   if (!minidump_->ReadBytes(&breakpad_info_, sizeof(breakpad_info_))) {
4775*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpBreakpadInfo cannot read Breakpad info";
4776*9712c20fSFrederick Mayle     return false;
4777*9712c20fSFrederick Mayle   }
4778*9712c20fSFrederick Mayle 
4779*9712c20fSFrederick Mayle   if (minidump_->swap()) {
4780*9712c20fSFrederick Mayle     Swap(&breakpad_info_.validity);
4781*9712c20fSFrederick Mayle     Swap(&breakpad_info_.dump_thread_id);
4782*9712c20fSFrederick Mayle     Swap(&breakpad_info_.requesting_thread_id);
4783*9712c20fSFrederick Mayle   }
4784*9712c20fSFrederick Mayle 
4785*9712c20fSFrederick Mayle   valid_ = true;
4786*9712c20fSFrederick Mayle   return true;
4787*9712c20fSFrederick Mayle }
4788*9712c20fSFrederick Mayle 
4789*9712c20fSFrederick Mayle 
GetDumpThreadID(uint32_t * thread_id) const4790*9712c20fSFrederick Mayle bool MinidumpBreakpadInfo::GetDumpThreadID(uint32_t* thread_id) const {
4791*9712c20fSFrederick Mayle   BPLOG_IF(ERROR, !thread_id) << "MinidumpBreakpadInfo::GetDumpThreadID "
4792*9712c20fSFrederick Mayle                                  "requires |thread_id|";
4793*9712c20fSFrederick Mayle   assert(thread_id);
4794*9712c20fSFrederick Mayle   *thread_id = 0;
4795*9712c20fSFrederick Mayle 
4796*9712c20fSFrederick Mayle   if (!valid_) {
4797*9712c20fSFrederick Mayle     BPLOG(ERROR) << "Invalid MinidumpBreakpadInfo for GetDumpThreadID";
4798*9712c20fSFrederick Mayle     return false;
4799*9712c20fSFrederick Mayle   }
4800*9712c20fSFrederick Mayle 
4801*9712c20fSFrederick Mayle   if (!(breakpad_info_.validity & MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID)) {
4802*9712c20fSFrederick Mayle     BPLOG(INFO) << "MinidumpBreakpadInfo has no dump thread";
4803*9712c20fSFrederick Mayle     return false;
4804*9712c20fSFrederick Mayle   }
4805*9712c20fSFrederick Mayle 
4806*9712c20fSFrederick Mayle   *thread_id = breakpad_info_.dump_thread_id;
4807*9712c20fSFrederick Mayle   return true;
4808*9712c20fSFrederick Mayle }
4809*9712c20fSFrederick Mayle 
4810*9712c20fSFrederick Mayle 
GetRequestingThreadID(uint32_t * thread_id) const4811*9712c20fSFrederick Mayle bool MinidumpBreakpadInfo::GetRequestingThreadID(uint32_t* thread_id)
4812*9712c20fSFrederick Mayle     const {
4813*9712c20fSFrederick Mayle   BPLOG_IF(ERROR, !thread_id) << "MinidumpBreakpadInfo::GetRequestingThreadID "
4814*9712c20fSFrederick Mayle                                  "requires |thread_id|";
4815*9712c20fSFrederick Mayle   assert(thread_id);
4816*9712c20fSFrederick Mayle   *thread_id = 0;
4817*9712c20fSFrederick Mayle 
4818*9712c20fSFrederick Mayle   if (!thread_id || !valid_) {
4819*9712c20fSFrederick Mayle     BPLOG(ERROR) << "Invalid MinidumpBreakpadInfo for GetRequestingThreadID";
4820*9712c20fSFrederick Mayle     return false;
4821*9712c20fSFrederick Mayle   }
4822*9712c20fSFrederick Mayle 
4823*9712c20fSFrederick Mayle   if (!(breakpad_info_.validity &
4824*9712c20fSFrederick Mayle             MD_BREAKPAD_INFO_VALID_REQUESTING_THREAD_ID)) {
4825*9712c20fSFrederick Mayle     BPLOG(INFO) << "MinidumpBreakpadInfo has no requesting thread";
4826*9712c20fSFrederick Mayle     return false;
4827*9712c20fSFrederick Mayle   }
4828*9712c20fSFrederick Mayle 
4829*9712c20fSFrederick Mayle   *thread_id = breakpad_info_.requesting_thread_id;
4830*9712c20fSFrederick Mayle   return true;
4831*9712c20fSFrederick Mayle }
4832*9712c20fSFrederick Mayle 
4833*9712c20fSFrederick Mayle 
Print()4834*9712c20fSFrederick Mayle void MinidumpBreakpadInfo::Print() {
4835*9712c20fSFrederick Mayle   if (!valid_) {
4836*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpBreakpadInfo cannot print invalid data";
4837*9712c20fSFrederick Mayle     return;
4838*9712c20fSFrederick Mayle   }
4839*9712c20fSFrederick Mayle 
4840*9712c20fSFrederick Mayle   printf("MDRawBreakpadInfo\n");
4841*9712c20fSFrederick Mayle   printf("  validity             = 0x%x\n", breakpad_info_.validity);
4842*9712c20fSFrederick Mayle   printf("  dump_thread_id       = ");
4843*9712c20fSFrederick Mayle   PrintValueOrInvalid(breakpad_info_.validity &
4844*9712c20fSFrederick Mayle                           MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID,
4845*9712c20fSFrederick Mayle                       kNumberFormatHexadecimal, breakpad_info_.dump_thread_id);
4846*9712c20fSFrederick Mayle   printf("  requesting_thread_id = ");
4847*9712c20fSFrederick Mayle   PrintValueOrInvalid(breakpad_info_.validity &
4848*9712c20fSFrederick Mayle                           MD_BREAKPAD_INFO_VALID_REQUESTING_THREAD_ID,
4849*9712c20fSFrederick Mayle                       kNumberFormatHexadecimal,
4850*9712c20fSFrederick Mayle                       breakpad_info_.requesting_thread_id);
4851*9712c20fSFrederick Mayle 
4852*9712c20fSFrederick Mayle   printf("\n");
4853*9712c20fSFrederick Mayle }
4854*9712c20fSFrederick Mayle 
4855*9712c20fSFrederick Mayle 
4856*9712c20fSFrederick Mayle //
4857*9712c20fSFrederick Mayle // MinidumpMemoryInfo
4858*9712c20fSFrederick Mayle //
4859*9712c20fSFrederick Mayle 
4860*9712c20fSFrederick Mayle 
MinidumpMemoryInfo(Minidump * minidump)4861*9712c20fSFrederick Mayle MinidumpMemoryInfo::MinidumpMemoryInfo(Minidump* minidump)
4862*9712c20fSFrederick Mayle     : MinidumpObject(minidump),
4863*9712c20fSFrederick Mayle       memory_info_() {
4864*9712c20fSFrederick Mayle }
4865*9712c20fSFrederick Mayle 
4866*9712c20fSFrederick Mayle 
IsExecutable() const4867*9712c20fSFrederick Mayle bool MinidumpMemoryInfo::IsExecutable() const {
4868*9712c20fSFrederick Mayle   uint32_t protection =
4869*9712c20fSFrederick Mayle       memory_info_.protection & MD_MEMORY_PROTECTION_ACCESS_MASK;
4870*9712c20fSFrederick Mayle   return protection == MD_MEMORY_PROTECT_EXECUTE ||
4871*9712c20fSFrederick Mayle       protection == MD_MEMORY_PROTECT_EXECUTE_READ ||
4872*9712c20fSFrederick Mayle       protection == MD_MEMORY_PROTECT_EXECUTE_READWRITE;
4873*9712c20fSFrederick Mayle }
4874*9712c20fSFrederick Mayle 
4875*9712c20fSFrederick Mayle 
IsWritable() const4876*9712c20fSFrederick Mayle bool MinidumpMemoryInfo::IsWritable() const {
4877*9712c20fSFrederick Mayle   uint32_t protection =
4878*9712c20fSFrederick Mayle       memory_info_.protection & MD_MEMORY_PROTECTION_ACCESS_MASK;
4879*9712c20fSFrederick Mayle   return protection == MD_MEMORY_PROTECT_READWRITE ||
4880*9712c20fSFrederick Mayle     protection == MD_MEMORY_PROTECT_WRITECOPY ||
4881*9712c20fSFrederick Mayle     protection == MD_MEMORY_PROTECT_EXECUTE_READWRITE ||
4882*9712c20fSFrederick Mayle     protection == MD_MEMORY_PROTECT_EXECUTE_WRITECOPY;
4883*9712c20fSFrederick Mayle }
4884*9712c20fSFrederick Mayle 
4885*9712c20fSFrederick Mayle 
Read()4886*9712c20fSFrederick Mayle bool MinidumpMemoryInfo::Read() {
4887*9712c20fSFrederick Mayle   valid_ = false;
4888*9712c20fSFrederick Mayle 
4889*9712c20fSFrederick Mayle   if (!minidump_->ReadBytes(&memory_info_, sizeof(memory_info_))) {
4890*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpMemoryInfo cannot read memory info";
4891*9712c20fSFrederick Mayle     return false;
4892*9712c20fSFrederick Mayle   }
4893*9712c20fSFrederick Mayle 
4894*9712c20fSFrederick Mayle   if (minidump_->swap()) {
4895*9712c20fSFrederick Mayle     Swap(&memory_info_.base_address);
4896*9712c20fSFrederick Mayle     Swap(&memory_info_.allocation_base);
4897*9712c20fSFrederick Mayle     Swap(&memory_info_.allocation_protection);
4898*9712c20fSFrederick Mayle     Swap(&memory_info_.region_size);
4899*9712c20fSFrederick Mayle     Swap(&memory_info_.state);
4900*9712c20fSFrederick Mayle     Swap(&memory_info_.protection);
4901*9712c20fSFrederick Mayle     Swap(&memory_info_.type);
4902*9712c20fSFrederick Mayle   }
4903*9712c20fSFrederick Mayle 
4904*9712c20fSFrederick Mayle   // Check for base + size overflow or undersize.
4905*9712c20fSFrederick Mayle   if (memory_info_.region_size == 0 ||
4906*9712c20fSFrederick Mayle       memory_info_.region_size > numeric_limits<uint64_t>::max() -
4907*9712c20fSFrederick Mayle                                      memory_info_.base_address) {
4908*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpMemoryInfo has a memory region problem, " <<
4909*9712c20fSFrederick Mayle                     HexString(memory_info_.base_address) << "+" <<
4910*9712c20fSFrederick Mayle                     HexString(memory_info_.region_size);
4911*9712c20fSFrederick Mayle     return false;
4912*9712c20fSFrederick Mayle   }
4913*9712c20fSFrederick Mayle 
4914*9712c20fSFrederick Mayle   valid_ = true;
4915*9712c20fSFrederick Mayle   return true;
4916*9712c20fSFrederick Mayle }
4917*9712c20fSFrederick Mayle 
4918*9712c20fSFrederick Mayle 
Print()4919*9712c20fSFrederick Mayle void MinidumpMemoryInfo::Print() {
4920*9712c20fSFrederick Mayle   if (!valid_) {
4921*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpMemoryInfo cannot print invalid data";
4922*9712c20fSFrederick Mayle     return;
4923*9712c20fSFrederick Mayle   }
4924*9712c20fSFrederick Mayle 
4925*9712c20fSFrederick Mayle   printf("MDRawMemoryInfo\n");
4926*9712c20fSFrederick Mayle   printf("  base_address          = 0x%" PRIx64 "\n",
4927*9712c20fSFrederick Mayle          memory_info_.base_address);
4928*9712c20fSFrederick Mayle   printf("  allocation_base       = 0x%" PRIx64 "\n",
4929*9712c20fSFrederick Mayle          memory_info_.allocation_base);
4930*9712c20fSFrederick Mayle   printf("  allocation_protection = 0x%x\n",
4931*9712c20fSFrederick Mayle          memory_info_.allocation_protection);
4932*9712c20fSFrederick Mayle   printf("  region_size           = 0x%" PRIx64 "\n", memory_info_.region_size);
4933*9712c20fSFrederick Mayle   printf("  state                 = 0x%x\n", memory_info_.state);
4934*9712c20fSFrederick Mayle   printf("  protection            = 0x%x\n", memory_info_.protection);
4935*9712c20fSFrederick Mayle   printf("  type                  = 0x%x\n", memory_info_.type);
4936*9712c20fSFrederick Mayle }
4937*9712c20fSFrederick Mayle 
4938*9712c20fSFrederick Mayle 
4939*9712c20fSFrederick Mayle //
4940*9712c20fSFrederick Mayle // MinidumpMemoryInfoList
4941*9712c20fSFrederick Mayle //
4942*9712c20fSFrederick Mayle 
4943*9712c20fSFrederick Mayle 
MinidumpMemoryInfoList(Minidump * minidump)4944*9712c20fSFrederick Mayle MinidumpMemoryInfoList::MinidumpMemoryInfoList(Minidump* minidump)
4945*9712c20fSFrederick Mayle     : MinidumpStream(minidump),
4946*9712c20fSFrederick Mayle       range_map_(new RangeMap<uint64_t, unsigned int>()),
4947*9712c20fSFrederick Mayle       infos_(NULL),
4948*9712c20fSFrederick Mayle       info_count_(0) {
4949*9712c20fSFrederick Mayle }
4950*9712c20fSFrederick Mayle 
4951*9712c20fSFrederick Mayle 
~MinidumpMemoryInfoList()4952*9712c20fSFrederick Mayle MinidumpMemoryInfoList::~MinidumpMemoryInfoList() {
4953*9712c20fSFrederick Mayle   delete range_map_;
4954*9712c20fSFrederick Mayle   delete infos_;
4955*9712c20fSFrederick Mayle }
4956*9712c20fSFrederick Mayle 
4957*9712c20fSFrederick Mayle 
Read(uint32_t expected_size)4958*9712c20fSFrederick Mayle bool MinidumpMemoryInfoList::Read(uint32_t expected_size) {
4959*9712c20fSFrederick Mayle   // Invalidate cached data.
4960*9712c20fSFrederick Mayle   delete infos_;
4961*9712c20fSFrederick Mayle   infos_ = NULL;
4962*9712c20fSFrederick Mayle   range_map_->Clear();
4963*9712c20fSFrederick Mayle   info_count_ = 0;
4964*9712c20fSFrederick Mayle 
4965*9712c20fSFrederick Mayle   valid_ = false;
4966*9712c20fSFrederick Mayle 
4967*9712c20fSFrederick Mayle   MDRawMemoryInfoList header;
4968*9712c20fSFrederick Mayle   if (expected_size < sizeof(MDRawMemoryInfoList)) {
4969*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpMemoryInfoList header size mismatch, " <<
4970*9712c20fSFrederick Mayle                     expected_size << " < " << sizeof(MDRawMemoryInfoList);
4971*9712c20fSFrederick Mayle     return false;
4972*9712c20fSFrederick Mayle   }
4973*9712c20fSFrederick Mayle   if (!minidump_->ReadBytes(&header, sizeof(header))) {
4974*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpMemoryInfoList could not read header";
4975*9712c20fSFrederick Mayle     return false;
4976*9712c20fSFrederick Mayle   }
4977*9712c20fSFrederick Mayle 
4978*9712c20fSFrederick Mayle   if (minidump_->swap()) {
4979*9712c20fSFrederick Mayle     Swap(&header.size_of_header);
4980*9712c20fSFrederick Mayle     Swap(&header.size_of_entry);
4981*9712c20fSFrederick Mayle     Swap(&header.number_of_entries);
4982*9712c20fSFrederick Mayle   }
4983*9712c20fSFrederick Mayle 
4984*9712c20fSFrederick Mayle   // Sanity check that the header is the expected size.
4985*9712c20fSFrederick Mayle   // TODO(ted): could possibly handle this more gracefully, assuming
4986*9712c20fSFrederick Mayle   // that future versions of the structs would be backwards-compatible.
4987*9712c20fSFrederick Mayle   if (header.size_of_header != sizeof(MDRawMemoryInfoList)) {
4988*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpMemoryInfoList header size mismatch, " <<
4989*9712c20fSFrederick Mayle                     header.size_of_header << " != " <<
4990*9712c20fSFrederick Mayle                     sizeof(MDRawMemoryInfoList);
4991*9712c20fSFrederick Mayle     return false;
4992*9712c20fSFrederick Mayle   }
4993*9712c20fSFrederick Mayle 
4994*9712c20fSFrederick Mayle   // Sanity check that the entries are the expected size.
4995*9712c20fSFrederick Mayle   if (header.size_of_entry != sizeof(MDRawMemoryInfo)) {
4996*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpMemoryInfoList entry size mismatch, " <<
4997*9712c20fSFrederick Mayle                     header.size_of_entry << " != " <<
4998*9712c20fSFrederick Mayle                     sizeof(MDRawMemoryInfo);
4999*9712c20fSFrederick Mayle     return false;
5000*9712c20fSFrederick Mayle   }
5001*9712c20fSFrederick Mayle 
5002*9712c20fSFrederick Mayle   if (header.number_of_entries >
5003*9712c20fSFrederick Mayle           numeric_limits<uint32_t>::max() / sizeof(MDRawMemoryInfo)) {
5004*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpMemoryInfoList info count " <<
5005*9712c20fSFrederick Mayle                     header.number_of_entries <<
5006*9712c20fSFrederick Mayle                     " would cause multiplication overflow";
5007*9712c20fSFrederick Mayle     return false;
5008*9712c20fSFrederick Mayle   }
5009*9712c20fSFrederick Mayle 
5010*9712c20fSFrederick Mayle   if (expected_size != sizeof(MDRawMemoryInfoList) +
5011*9712c20fSFrederick Mayle                         header.number_of_entries * sizeof(MDRawMemoryInfo)) {
5012*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpMemoryInfoList size mismatch, " << expected_size <<
5013*9712c20fSFrederick Mayle                     " != " << sizeof(MDRawMemoryInfoList) +
5014*9712c20fSFrederick Mayle                         header.number_of_entries * sizeof(MDRawMemoryInfo);
5015*9712c20fSFrederick Mayle     return false;
5016*9712c20fSFrederick Mayle   }
5017*9712c20fSFrederick Mayle 
5018*9712c20fSFrederick Mayle   // Check for data loss when converting header.number_of_entries from
5019*9712c20fSFrederick Mayle   // uint64_t into MinidumpMemoryInfos::size_type (uint32_t)
5020*9712c20fSFrederick Mayle   MinidumpMemoryInfos::size_type header_number_of_entries =
5021*9712c20fSFrederick Mayle       static_cast<unsigned int>(header.number_of_entries);
5022*9712c20fSFrederick Mayle   if (static_cast<uint64_t>(header_number_of_entries) !=
5023*9712c20fSFrederick Mayle       header.number_of_entries) {
5024*9712c20fSFrederick Mayle     BPLOG(ERROR) << "Data loss detected when converting "
5025*9712c20fSFrederick Mayle                     "the header's number_of_entries";
5026*9712c20fSFrederick Mayle     return false;
5027*9712c20fSFrederick Mayle   }
5028*9712c20fSFrederick Mayle 
5029*9712c20fSFrederick Mayle   if (header.number_of_entries != 0) {
5030*9712c20fSFrederick Mayle     scoped_ptr<MinidumpMemoryInfos> infos(
5031*9712c20fSFrederick Mayle         new MinidumpMemoryInfos(header_number_of_entries,
5032*9712c20fSFrederick Mayle                                 MinidumpMemoryInfo(minidump_)));
5033*9712c20fSFrederick Mayle 
5034*9712c20fSFrederick Mayle     for (unsigned int index = 0;
5035*9712c20fSFrederick Mayle          index < header.number_of_entries;
5036*9712c20fSFrederick Mayle          ++index) {
5037*9712c20fSFrederick Mayle       MinidumpMemoryInfo* info = &(*infos)[index];
5038*9712c20fSFrederick Mayle 
5039*9712c20fSFrederick Mayle       // Assume that the file offset is correct after the last read.
5040*9712c20fSFrederick Mayle       if (!info->Read()) {
5041*9712c20fSFrederick Mayle         BPLOG(ERROR) << "MinidumpMemoryInfoList cannot read info " <<
5042*9712c20fSFrederick Mayle                         index << "/" << header.number_of_entries;
5043*9712c20fSFrederick Mayle         return false;
5044*9712c20fSFrederick Mayle       }
5045*9712c20fSFrederick Mayle 
5046*9712c20fSFrederick Mayle       uint64_t base_address = info->GetBase();
5047*9712c20fSFrederick Mayle       uint64_t region_size = info->GetSize();
5048*9712c20fSFrederick Mayle 
5049*9712c20fSFrederick Mayle       if (!range_map_->StoreRange(base_address, region_size, index)) {
5050*9712c20fSFrederick Mayle         BPLOG(ERROR) << "MinidumpMemoryInfoList could not store"
5051*9712c20fSFrederick Mayle                         " memory region " <<
5052*9712c20fSFrederick Mayle                         index << "/" << header.number_of_entries << ", " <<
5053*9712c20fSFrederick Mayle                         HexString(base_address) << "+" <<
5054*9712c20fSFrederick Mayle                         HexString(region_size);
5055*9712c20fSFrederick Mayle         return false;
5056*9712c20fSFrederick Mayle       }
5057*9712c20fSFrederick Mayle     }
5058*9712c20fSFrederick Mayle 
5059*9712c20fSFrederick Mayle     infos_ = infos.release();
5060*9712c20fSFrederick Mayle   }
5061*9712c20fSFrederick Mayle 
5062*9712c20fSFrederick Mayle   info_count_ = static_cast<uint32_t>(header_number_of_entries);
5063*9712c20fSFrederick Mayle 
5064*9712c20fSFrederick Mayle   valid_ = true;
5065*9712c20fSFrederick Mayle   return true;
5066*9712c20fSFrederick Mayle }
5067*9712c20fSFrederick Mayle 
5068*9712c20fSFrederick Mayle 
GetMemoryInfoAtIndex(unsigned int index) const5069*9712c20fSFrederick Mayle const MinidumpMemoryInfo* MinidumpMemoryInfoList::GetMemoryInfoAtIndex(
5070*9712c20fSFrederick Mayle       unsigned int index) const {
5071*9712c20fSFrederick Mayle   if (!valid_) {
5072*9712c20fSFrederick Mayle     BPLOG(ERROR) << "Invalid MinidumpMemoryInfoList for GetMemoryInfoAtIndex";
5073*9712c20fSFrederick Mayle     return NULL;
5074*9712c20fSFrederick Mayle   }
5075*9712c20fSFrederick Mayle 
5076*9712c20fSFrederick Mayle   if (index >= info_count_) {
5077*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpMemoryInfoList index out of range: " <<
5078*9712c20fSFrederick Mayle                     index << "/" << info_count_;
5079*9712c20fSFrederick Mayle     return NULL;
5080*9712c20fSFrederick Mayle   }
5081*9712c20fSFrederick Mayle 
5082*9712c20fSFrederick Mayle   return &(*infos_)[index];
5083*9712c20fSFrederick Mayle }
5084*9712c20fSFrederick Mayle 
5085*9712c20fSFrederick Mayle 
GetMemoryInfoForAddress(uint64_t address) const5086*9712c20fSFrederick Mayle const MinidumpMemoryInfo* MinidumpMemoryInfoList::GetMemoryInfoForAddress(
5087*9712c20fSFrederick Mayle     uint64_t address) const {
5088*9712c20fSFrederick Mayle   if (!valid_) {
5089*9712c20fSFrederick Mayle     BPLOG(ERROR) << "Invalid MinidumpMemoryInfoList for"
5090*9712c20fSFrederick Mayle                     " GetMemoryInfoForAddress";
5091*9712c20fSFrederick Mayle     return NULL;
5092*9712c20fSFrederick Mayle   }
5093*9712c20fSFrederick Mayle 
5094*9712c20fSFrederick Mayle   unsigned int info_index;
5095*9712c20fSFrederick Mayle   if (!range_map_->RetrieveRange(address, &info_index, NULL /* base */,
5096*9712c20fSFrederick Mayle                                  NULL /* delta */, NULL /* size */)) {
5097*9712c20fSFrederick Mayle     BPLOG(INFO) << "MinidumpMemoryInfoList has no memory info at " <<
5098*9712c20fSFrederick Mayle                    HexString(address);
5099*9712c20fSFrederick Mayle     return NULL;
5100*9712c20fSFrederick Mayle   }
5101*9712c20fSFrederick Mayle 
5102*9712c20fSFrederick Mayle   return GetMemoryInfoAtIndex(info_index);
5103*9712c20fSFrederick Mayle }
5104*9712c20fSFrederick Mayle 
5105*9712c20fSFrederick Mayle 
Print()5106*9712c20fSFrederick Mayle void MinidumpMemoryInfoList::Print() {
5107*9712c20fSFrederick Mayle   if (!valid_) {
5108*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpMemoryInfoList cannot print invalid data";
5109*9712c20fSFrederick Mayle     return;
5110*9712c20fSFrederick Mayle   }
5111*9712c20fSFrederick Mayle 
5112*9712c20fSFrederick Mayle   printf("MinidumpMemoryInfoList\n");
5113*9712c20fSFrederick Mayle   printf("  info_count = %d\n", info_count_);
5114*9712c20fSFrederick Mayle   printf("\n");
5115*9712c20fSFrederick Mayle 
5116*9712c20fSFrederick Mayle   for (unsigned int info_index = 0;
5117*9712c20fSFrederick Mayle        info_index < info_count_;
5118*9712c20fSFrederick Mayle        ++info_index) {
5119*9712c20fSFrederick Mayle     printf("info[%d]\n", info_index);
5120*9712c20fSFrederick Mayle     (*infos_)[info_index].Print();
5121*9712c20fSFrederick Mayle     printf("\n");
5122*9712c20fSFrederick Mayle   }
5123*9712c20fSFrederick Mayle }
5124*9712c20fSFrederick Mayle 
5125*9712c20fSFrederick Mayle //
5126*9712c20fSFrederick Mayle // MinidumpLinuxMaps
5127*9712c20fSFrederick Mayle //
5128*9712c20fSFrederick Mayle 
MinidumpLinuxMaps(Minidump * minidump)5129*9712c20fSFrederick Mayle MinidumpLinuxMaps::MinidumpLinuxMaps(Minidump* minidump)
5130*9712c20fSFrederick Mayle     : MinidumpObject(minidump) {
5131*9712c20fSFrederick Mayle }
5132*9712c20fSFrederick Mayle 
Print() const5133*9712c20fSFrederick Mayle void MinidumpLinuxMaps::Print() const {
5134*9712c20fSFrederick Mayle   if (!valid_) {
5135*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpLinuxMaps cannot print invalid data";
5136*9712c20fSFrederick Mayle     return;
5137*9712c20fSFrederick Mayle   }
5138*9712c20fSFrederick Mayle   std::cout << region_.line << std::endl;
5139*9712c20fSFrederick Mayle }
5140*9712c20fSFrederick Mayle 
5141*9712c20fSFrederick Mayle //
5142*9712c20fSFrederick Mayle // MinidumpLinuxMapsList
5143*9712c20fSFrederick Mayle //
5144*9712c20fSFrederick Mayle 
MinidumpLinuxMapsList(Minidump * minidump)5145*9712c20fSFrederick Mayle MinidumpLinuxMapsList::MinidumpLinuxMapsList(Minidump* minidump)
5146*9712c20fSFrederick Mayle     : MinidumpStream(minidump),
5147*9712c20fSFrederick Mayle       maps_(NULL),
5148*9712c20fSFrederick Mayle       maps_count_(0) {
5149*9712c20fSFrederick Mayle }
5150*9712c20fSFrederick Mayle 
~MinidumpLinuxMapsList()5151*9712c20fSFrederick Mayle MinidumpLinuxMapsList::~MinidumpLinuxMapsList() {
5152*9712c20fSFrederick Mayle   if (maps_) {
5153*9712c20fSFrederick Mayle     for (unsigned int i = 0; i < maps_->size(); i++) {
5154*9712c20fSFrederick Mayle       delete (*maps_)[i];
5155*9712c20fSFrederick Mayle     }
5156*9712c20fSFrederick Mayle     delete maps_;
5157*9712c20fSFrederick Mayle   }
5158*9712c20fSFrederick Mayle }
5159*9712c20fSFrederick Mayle 
GetLinuxMapsForAddress(uint64_t address) const5160*9712c20fSFrederick Mayle const MinidumpLinuxMaps* MinidumpLinuxMapsList::GetLinuxMapsForAddress(
5161*9712c20fSFrederick Mayle     uint64_t address) const {
5162*9712c20fSFrederick Mayle   if (!valid_ || (maps_ == NULL)) {
5163*9712c20fSFrederick Mayle     BPLOG(ERROR) << "Invalid MinidumpLinuxMapsList for GetLinuxMapsForAddress";
5164*9712c20fSFrederick Mayle     return NULL;
5165*9712c20fSFrederick Mayle   }
5166*9712c20fSFrederick Mayle 
5167*9712c20fSFrederick Mayle   // Search every memory mapping.
5168*9712c20fSFrederick Mayle   for (unsigned int index = 0; index < maps_count_; index++) {
5169*9712c20fSFrederick Mayle     // Check if address is within bounds of the current memory region.
5170*9712c20fSFrederick Mayle     if ((*maps_)[index]->GetBase() <= address &&
5171*9712c20fSFrederick Mayle         (*maps_)[index]->GetBase() + (*maps_)[index]->GetSize() > address) {
5172*9712c20fSFrederick Mayle       return (*maps_)[index];
5173*9712c20fSFrederick Mayle     }
5174*9712c20fSFrederick Mayle   }
5175*9712c20fSFrederick Mayle 
5176*9712c20fSFrederick Mayle   // No mapping encloses the memory address.
5177*9712c20fSFrederick Mayle   BPLOG(ERROR) << "MinidumpLinuxMapsList has no mapping at "
5178*9712c20fSFrederick Mayle                << HexString(address);
5179*9712c20fSFrederick Mayle   return NULL;
5180*9712c20fSFrederick Mayle }
5181*9712c20fSFrederick Mayle 
GetLinuxMapsAtIndex(unsigned int index) const5182*9712c20fSFrederick Mayle const MinidumpLinuxMaps* MinidumpLinuxMapsList::GetLinuxMapsAtIndex(
5183*9712c20fSFrederick Mayle     unsigned int index) const {
5184*9712c20fSFrederick Mayle   if (!valid_ || (maps_ == NULL)) {
5185*9712c20fSFrederick Mayle     BPLOG(ERROR) << "Invalid MinidumpLinuxMapsList for GetLinuxMapsAtIndex";
5186*9712c20fSFrederick Mayle     return NULL;
5187*9712c20fSFrederick Mayle   }
5188*9712c20fSFrederick Mayle 
5189*9712c20fSFrederick Mayle   // Index out of bounds.
5190*9712c20fSFrederick Mayle   if (index >= maps_count_ || (maps_ == NULL)) {
5191*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpLinuxMapsList index of out range: "
5192*9712c20fSFrederick Mayle                  << index
5193*9712c20fSFrederick Mayle                  << "/"
5194*9712c20fSFrederick Mayle                  << maps_count_;
5195*9712c20fSFrederick Mayle     return NULL;
5196*9712c20fSFrederick Mayle   }
5197*9712c20fSFrederick Mayle   return (*maps_)[index];
5198*9712c20fSFrederick Mayle }
5199*9712c20fSFrederick Mayle 
Read(uint32_t expected_size)5200*9712c20fSFrederick Mayle bool MinidumpLinuxMapsList::Read(uint32_t expected_size) {
5201*9712c20fSFrederick Mayle   // Invalidate cached data.
5202*9712c20fSFrederick Mayle   if (maps_) {
5203*9712c20fSFrederick Mayle     for (unsigned int i = 0; i < maps_->size(); i++) {
5204*9712c20fSFrederick Mayle       delete (*maps_)[i];
5205*9712c20fSFrederick Mayle     }
5206*9712c20fSFrederick Mayle     delete maps_;
5207*9712c20fSFrederick Mayle   }
5208*9712c20fSFrederick Mayle   maps_ = NULL;
5209*9712c20fSFrederick Mayle   maps_count_ = 0;
5210*9712c20fSFrederick Mayle 
5211*9712c20fSFrederick Mayle   valid_ = false;
5212*9712c20fSFrederick Mayle 
5213*9712c20fSFrederick Mayle   // Load and check expected stream length.
5214*9712c20fSFrederick Mayle   uint32_t length = 0;
5215*9712c20fSFrederick Mayle   if (!minidump_->SeekToStreamType(MD_LINUX_MAPS, &length)) {
5216*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpLinuxMapsList stream type not found";
5217*9712c20fSFrederick Mayle     return false;
5218*9712c20fSFrederick Mayle   }
5219*9712c20fSFrederick Mayle   if (expected_size != length) {
5220*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpLinuxMapsList size mismatch: "
5221*9712c20fSFrederick Mayle                  << expected_size
5222*9712c20fSFrederick Mayle                  << " != "
5223*9712c20fSFrederick Mayle                  << length;
5224*9712c20fSFrederick Mayle     return false;
5225*9712c20fSFrederick Mayle   }
5226*9712c20fSFrederick Mayle 
5227*9712c20fSFrederick Mayle   // Create a vector to read stream data. The vector needs to have
5228*9712c20fSFrederick Mayle   // at least enough capacity to read all the data.
5229*9712c20fSFrederick Mayle   vector<char> mapping_bytes(length);
5230*9712c20fSFrederick Mayle   if (!minidump_->ReadBytes(&mapping_bytes[0], length)) {
5231*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpLinuxMapsList failed to read bytes";
5232*9712c20fSFrederick Mayle     return false;
5233*9712c20fSFrederick Mayle   }
5234*9712c20fSFrederick Mayle   string map_string(mapping_bytes.begin(), mapping_bytes.end());
5235*9712c20fSFrederick Mayle   vector<MappedMemoryRegion> all_regions;
5236*9712c20fSFrederick Mayle 
5237*9712c20fSFrederick Mayle   // Parse string into mapping data.
5238*9712c20fSFrederick Mayle   if (!ParseProcMaps(map_string, &all_regions)) {
5239*9712c20fSFrederick Mayle     return false;
5240*9712c20fSFrederick Mayle   }
5241*9712c20fSFrederick Mayle 
5242*9712c20fSFrederick Mayle   scoped_ptr<MinidumpLinuxMappings> maps(new MinidumpLinuxMappings());
5243*9712c20fSFrederick Mayle 
5244*9712c20fSFrederick Mayle   // Push mapping data into wrapper classes.
5245*9712c20fSFrederick Mayle   for (size_t i = 0; i < all_regions.size(); i++) {
5246*9712c20fSFrederick Mayle     scoped_ptr<MinidumpLinuxMaps> ele(new MinidumpLinuxMaps(minidump_));
5247*9712c20fSFrederick Mayle     ele->region_ = all_regions[i];
5248*9712c20fSFrederick Mayle     ele->valid_ = true;
5249*9712c20fSFrederick Mayle     maps->push_back(ele.release());
5250*9712c20fSFrederick Mayle   }
5251*9712c20fSFrederick Mayle 
5252*9712c20fSFrederick Mayle   // Set instance variables.
5253*9712c20fSFrederick Mayle   maps_ = maps.release();
5254*9712c20fSFrederick Mayle   maps_count_ = static_cast<uint32_t>(maps_->size());
5255*9712c20fSFrederick Mayle   valid_ = true;
5256*9712c20fSFrederick Mayle   return true;
5257*9712c20fSFrederick Mayle }
5258*9712c20fSFrederick Mayle 
Print() const5259*9712c20fSFrederick Mayle void MinidumpLinuxMapsList::Print() const {
5260*9712c20fSFrederick Mayle   if (!valid_ || (maps_ == NULL)) {
5261*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpLinuxMapsList cannot print valid data";
5262*9712c20fSFrederick Mayle     return;
5263*9712c20fSFrederick Mayle   }
5264*9712c20fSFrederick Mayle   for (size_t i = 0; i < maps_->size(); i++) {
5265*9712c20fSFrederick Mayle     (*maps_)[i]->Print();
5266*9712c20fSFrederick Mayle   }
5267*9712c20fSFrederick Mayle }
5268*9712c20fSFrederick Mayle 
5269*9712c20fSFrederick Mayle //
5270*9712c20fSFrederick Mayle // MinidumpCrashpadInfo
5271*9712c20fSFrederick Mayle //
5272*9712c20fSFrederick Mayle 
5273*9712c20fSFrederick Mayle 
MinidumpCrashpadInfo(Minidump * minidump)5274*9712c20fSFrederick Mayle MinidumpCrashpadInfo::MinidumpCrashpadInfo(Minidump* minidump)
5275*9712c20fSFrederick Mayle     : MinidumpStream(minidump),
5276*9712c20fSFrederick Mayle       crashpad_info_(),
5277*9712c20fSFrederick Mayle       module_crashpad_info_links_(),
5278*9712c20fSFrederick Mayle       module_crashpad_info_(),
5279*9712c20fSFrederick Mayle       module_crashpad_info_list_annotations_(),
5280*9712c20fSFrederick Mayle       module_crashpad_info_simple_annotations_(),
5281*9712c20fSFrederick Mayle       module_crashpad_info_annotation_objects_(),
5282*9712c20fSFrederick Mayle       simple_annotations_() {
5283*9712c20fSFrederick Mayle }
5284*9712c20fSFrederick Mayle 
5285*9712c20fSFrederick Mayle 
Read(uint32_t expected_size)5286*9712c20fSFrederick Mayle bool MinidumpCrashpadInfo::Read(uint32_t expected_size) {
5287*9712c20fSFrederick Mayle   valid_ = false;
5288*9712c20fSFrederick Mayle 
5289*9712c20fSFrederick Mayle   // Support old minidumps that do not implement newer crashpad_info_
5290*9712c20fSFrederick Mayle   // fields, currently limited to the address mask.
5291*9712c20fSFrederick Mayle   static_assert(sizeof(crashpad_info_) == 64,
5292*9712c20fSFrederick Mayle                 "Updated ::Read for new crashpad_info field.");
5293*9712c20fSFrederick Mayle 
5294*9712c20fSFrederick Mayle   constexpr size_t crashpad_info_min_size =
5295*9712c20fSFrederick Mayle       offsetof(decltype(crashpad_info_), reserved);
5296*9712c20fSFrederick Mayle   if (expected_size < crashpad_info_min_size) {
5297*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpCrashpadInfo size mismatch, " << expected_size
5298*9712c20fSFrederick Mayle                  << " < " << crashpad_info_min_size;
5299*9712c20fSFrederick Mayle     return false;
5300*9712c20fSFrederick Mayle   }
5301*9712c20fSFrederick Mayle 
5302*9712c20fSFrederick Mayle   if (!minidump_->ReadBytes(&crashpad_info_, crashpad_info_min_size)) {
5303*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpCrashpadInfo cannot read Crashpad info";
5304*9712c20fSFrederick Mayle     return false;
5305*9712c20fSFrederick Mayle   }
5306*9712c20fSFrederick Mayle   expected_size -= crashpad_info_min_size;
5307*9712c20fSFrederick Mayle 
5308*9712c20fSFrederick Mayle   // Read `reserved` if available.
5309*9712c20fSFrederick Mayle   size_t crashpad_reserved_size = sizeof(crashpad_info_.reserved);
5310*9712c20fSFrederick Mayle   if (expected_size >= crashpad_reserved_size) {
5311*9712c20fSFrederick Mayle     if (!minidump_->ReadBytes(
5312*9712c20fSFrederick Mayle             &crashpad_info_.reserved,
5313*9712c20fSFrederick Mayle             crashpad_reserved_size)) {
5314*9712c20fSFrederick Mayle       BPLOG(ERROR) << "MinidumpCrashpadInfo cannot read reserved";
5315*9712c20fSFrederick Mayle       return false;
5316*9712c20fSFrederick Mayle     }
5317*9712c20fSFrederick Mayle     expected_size -= crashpad_reserved_size;
5318*9712c20fSFrederick Mayle   } else {
5319*9712c20fSFrederick Mayle     crashpad_info_.reserved = 0;
5320*9712c20fSFrederick Mayle   }
5321*9712c20fSFrederick Mayle 
5322*9712c20fSFrederick Mayle   // Read `address_mask` if available.
5323*9712c20fSFrederick Mayle   size_t crashpad_address_mask_size = sizeof(crashpad_info_.address_mask);
5324*9712c20fSFrederick Mayle   if (expected_size >= crashpad_address_mask_size) {
5325*9712c20fSFrederick Mayle     if (!minidump_->ReadBytes(
5326*9712c20fSFrederick Mayle             &crashpad_info_.address_mask,
5327*9712c20fSFrederick Mayle             crashpad_address_mask_size)) {
5328*9712c20fSFrederick Mayle       BPLOG(ERROR) << "MinidumpCrashpadInfo cannot read address mask";
5329*9712c20fSFrederick Mayle       return false;
5330*9712c20fSFrederick Mayle     }
5331*9712c20fSFrederick Mayle     expected_size -= crashpad_address_mask_size;
5332*9712c20fSFrederick Mayle   } else {
5333*9712c20fSFrederick Mayle     crashpad_info_.address_mask = 0;
5334*9712c20fSFrederick Mayle   }
5335*9712c20fSFrederick Mayle 
5336*9712c20fSFrederick Mayle   if (minidump_->swap()) {
5337*9712c20fSFrederick Mayle     Swap(&crashpad_info_.version);
5338*9712c20fSFrederick Mayle     Swap(&crashpad_info_.report_id);
5339*9712c20fSFrederick Mayle     Swap(&crashpad_info_.client_id);
5340*9712c20fSFrederick Mayle     Swap(&crashpad_info_.simple_annotations);
5341*9712c20fSFrederick Mayle     Swap(&crashpad_info_.module_list);
5342*9712c20fSFrederick Mayle     Swap(&crashpad_info_.reserved);
5343*9712c20fSFrederick Mayle     Swap(&crashpad_info_.address_mask);
5344*9712c20fSFrederick Mayle   }
5345*9712c20fSFrederick Mayle 
5346*9712c20fSFrederick Mayle   if (crashpad_info_.simple_annotations.data_size) {
5347*9712c20fSFrederick Mayle     if (!minidump_->ReadSimpleStringDictionary(
5348*9712c20fSFrederick Mayle         crashpad_info_.simple_annotations.rva,
5349*9712c20fSFrederick Mayle         &simple_annotations_)) {
5350*9712c20fSFrederick Mayle       BPLOG(ERROR) << "MinidumpCrashpadInfo cannot read simple_annotations";
5351*9712c20fSFrederick Mayle       return false;
5352*9712c20fSFrederick Mayle     }
5353*9712c20fSFrederick Mayle   }
5354*9712c20fSFrederick Mayle 
5355*9712c20fSFrederick Mayle   if (crashpad_info_.module_list.data_size) {
5356*9712c20fSFrederick Mayle     if (!minidump_->SeekSet(crashpad_info_.module_list.rva)) {
5357*9712c20fSFrederick Mayle       BPLOG(ERROR) << "MinidumpCrashpadInfo cannot seek to module_list";
5358*9712c20fSFrederick Mayle       return false;
5359*9712c20fSFrederick Mayle     }
5360*9712c20fSFrederick Mayle 
5361*9712c20fSFrederick Mayle     uint32_t count;
5362*9712c20fSFrederick Mayle     if (!minidump_->ReadBytes(&count, sizeof(count))) {
5363*9712c20fSFrederick Mayle       BPLOG(ERROR) << "MinidumpCrashpadInfo cannot read module_list count";
5364*9712c20fSFrederick Mayle       return false;
5365*9712c20fSFrederick Mayle     }
5366*9712c20fSFrederick Mayle 
5367*9712c20fSFrederick Mayle     if (minidump_->swap()) {
5368*9712c20fSFrederick Mayle       Swap(&count);
5369*9712c20fSFrederick Mayle     }
5370*9712c20fSFrederick Mayle 
5371*9712c20fSFrederick Mayle     scoped_array<MDRawModuleCrashpadInfoLink> module_crashpad_info_links(
5372*9712c20fSFrederick Mayle         new MDRawModuleCrashpadInfoLink[count]);
5373*9712c20fSFrederick Mayle 
5374*9712c20fSFrederick Mayle     // Read the entire array in one fell swoop, instead of reading one entry
5375*9712c20fSFrederick Mayle     // at a time in the loop.
5376*9712c20fSFrederick Mayle     if (!minidump_->ReadBytes(
5377*9712c20fSFrederick Mayle             &module_crashpad_info_links[0],
5378*9712c20fSFrederick Mayle             sizeof(MDRawModuleCrashpadInfoLink) * count)) {
5379*9712c20fSFrederick Mayle       BPLOG(ERROR)
5380*9712c20fSFrederick Mayle           << "MinidumpCrashpadInfo could not read Crashpad module links";
5381*9712c20fSFrederick Mayle       return false;
5382*9712c20fSFrederick Mayle     }
5383*9712c20fSFrederick Mayle 
5384*9712c20fSFrederick Mayle     for (uint32_t index = 0; index < count; ++index) {
5385*9712c20fSFrederick Mayle       if (minidump_->swap()) {
5386*9712c20fSFrederick Mayle         Swap(&module_crashpad_info_links[index].minidump_module_list_index);
5387*9712c20fSFrederick Mayle         Swap(&module_crashpad_info_links[index].location);
5388*9712c20fSFrederick Mayle       }
5389*9712c20fSFrederick Mayle 
5390*9712c20fSFrederick Mayle       if (!minidump_->SeekSet(module_crashpad_info_links[index].location.rva)) {
5391*9712c20fSFrederick Mayle         BPLOG(ERROR)
5392*9712c20fSFrederick Mayle             << "MinidumpCrashpadInfo cannot seek to Crashpad module info";
5393*9712c20fSFrederick Mayle         return false;
5394*9712c20fSFrederick Mayle       }
5395*9712c20fSFrederick Mayle 
5396*9712c20fSFrederick Mayle       MDRawModuleCrashpadInfo module_crashpad_info;
5397*9712c20fSFrederick Mayle       if (!minidump_->ReadBytes(&module_crashpad_info,
5398*9712c20fSFrederick Mayle                                 sizeof(module_crashpad_info))) {
5399*9712c20fSFrederick Mayle         BPLOG(ERROR) << "MinidumpCrashpadInfo cannot read Crashpad module info";
5400*9712c20fSFrederick Mayle         return false;
5401*9712c20fSFrederick Mayle       }
5402*9712c20fSFrederick Mayle 
5403*9712c20fSFrederick Mayle       if (minidump_->swap()) {
5404*9712c20fSFrederick Mayle         Swap(&module_crashpad_info.version);
5405*9712c20fSFrederick Mayle         Swap(&module_crashpad_info.list_annotations);
5406*9712c20fSFrederick Mayle         Swap(&module_crashpad_info.simple_annotations);
5407*9712c20fSFrederick Mayle         Swap(&module_crashpad_info.annotation_objects);
5408*9712c20fSFrederick Mayle       }
5409*9712c20fSFrederick Mayle 
5410*9712c20fSFrederick Mayle       std::vector<std::string> list_annotations;
5411*9712c20fSFrederick Mayle       if (module_crashpad_info.list_annotations.data_size) {
5412*9712c20fSFrederick Mayle         if (!minidump_->ReadStringList(
5413*9712c20fSFrederick Mayle                 module_crashpad_info.list_annotations.rva,
5414*9712c20fSFrederick Mayle                 &list_annotations)) {
5415*9712c20fSFrederick Mayle           BPLOG(ERROR) << "MinidumpCrashpadInfo cannot read Crashpad module "
5416*9712c20fSFrederick Mayle               "info list annotations";
5417*9712c20fSFrederick Mayle           return false;
5418*9712c20fSFrederick Mayle         }
5419*9712c20fSFrederick Mayle       }
5420*9712c20fSFrederick Mayle 
5421*9712c20fSFrederick Mayle       std::map<std::string, std::string> simple_annotations;
5422*9712c20fSFrederick Mayle       if (module_crashpad_info.simple_annotations.data_size) {
5423*9712c20fSFrederick Mayle         if (!minidump_->ReadSimpleStringDictionary(
5424*9712c20fSFrederick Mayle                 module_crashpad_info.simple_annotations.rva,
5425*9712c20fSFrederick Mayle                 &simple_annotations)) {
5426*9712c20fSFrederick Mayle           BPLOG(ERROR) << "MinidumpCrashpadInfo cannot read Crashpad module "
5427*9712c20fSFrederick Mayle               "info simple annotations";
5428*9712c20fSFrederick Mayle           return false;
5429*9712c20fSFrederick Mayle         }
5430*9712c20fSFrederick Mayle       }
5431*9712c20fSFrederick Mayle 
5432*9712c20fSFrederick Mayle       std::vector<MinidumpCrashpadInfo::AnnotationObject> annotation_objects;
5433*9712c20fSFrederick Mayle       if (module_crashpad_info.annotation_objects.data_size) {
5434*9712c20fSFrederick Mayle         if (!minidump_->ReadCrashpadAnnotationsList(
5435*9712c20fSFrederick Mayle                 module_crashpad_info.annotation_objects.rva,
5436*9712c20fSFrederick Mayle                 &annotation_objects)) {
5437*9712c20fSFrederick Mayle           BPLOG(ERROR)
5438*9712c20fSFrederick Mayle               << "MinidumpCrashpadInfo cannot read Crashpad annotations list";
5439*9712c20fSFrederick Mayle           return false;
5440*9712c20fSFrederick Mayle         }
5441*9712c20fSFrederick Mayle       }
5442*9712c20fSFrederick Mayle 
5443*9712c20fSFrederick Mayle       module_crashpad_info_links_.push_back(
5444*9712c20fSFrederick Mayle           module_crashpad_info_links[index].minidump_module_list_index);
5445*9712c20fSFrederick Mayle       module_crashpad_info_.push_back(module_crashpad_info);
5446*9712c20fSFrederick Mayle       module_crashpad_info_list_annotations_.push_back(list_annotations);
5447*9712c20fSFrederick Mayle       module_crashpad_info_simple_annotations_.push_back(simple_annotations);
5448*9712c20fSFrederick Mayle       module_crashpad_info_annotation_objects_.push_back(annotation_objects);
5449*9712c20fSFrederick Mayle     }
5450*9712c20fSFrederick Mayle   }
5451*9712c20fSFrederick Mayle 
5452*9712c20fSFrederick Mayle   valid_ = true;
5453*9712c20fSFrederick Mayle   return true;
5454*9712c20fSFrederick Mayle }
5455*9712c20fSFrederick Mayle 
5456*9712c20fSFrederick Mayle 
Print()5457*9712c20fSFrederick Mayle void MinidumpCrashpadInfo::Print() {
5458*9712c20fSFrederick Mayle   if (!valid_) {
5459*9712c20fSFrederick Mayle     BPLOG(ERROR) << "MinidumpCrashpadInfo cannot print invalid data";
5460*9712c20fSFrederick Mayle     return;
5461*9712c20fSFrederick Mayle   }
5462*9712c20fSFrederick Mayle 
5463*9712c20fSFrederick Mayle   printf("MDRawCrashpadInfo\n");
5464*9712c20fSFrederick Mayle   printf("  version = %d\n", crashpad_info_.version);
5465*9712c20fSFrederick Mayle   printf("  report_id = %s\n",
5466*9712c20fSFrederick Mayle          MDGUIDToString(crashpad_info_.report_id).c_str());
5467*9712c20fSFrederick Mayle   printf("  client_id = %s\n",
5468*9712c20fSFrederick Mayle          MDGUIDToString(crashpad_info_.client_id).c_str());
5469*9712c20fSFrederick Mayle   for (const auto& annot : simple_annotations_) {
5470*9712c20fSFrederick Mayle     printf("  simple_annotations[\"%s\"] = %s\n", annot.first.c_str(),
5471*9712c20fSFrederick Mayle            annot.second.c_str());
5472*9712c20fSFrederick Mayle   }
5473*9712c20fSFrederick Mayle   for (uint32_t module_index = 0;
5474*9712c20fSFrederick Mayle        module_index < module_crashpad_info_links_.size();
5475*9712c20fSFrederick Mayle        ++module_index) {
5476*9712c20fSFrederick Mayle     printf("  module_list[%d].minidump_module_list_index = %d\n",
5477*9712c20fSFrederick Mayle            module_index, module_crashpad_info_links_[module_index]);
5478*9712c20fSFrederick Mayle     printf("  module_list[%d].version = %d\n",
5479*9712c20fSFrederick Mayle            module_index, module_crashpad_info_[module_index].version);
5480*9712c20fSFrederick Mayle     const auto& list_annots =
5481*9712c20fSFrederick Mayle         module_crashpad_info_list_annotations_[module_index];
5482*9712c20fSFrederick Mayle     for (uint32_t annotation_index = 0; annotation_index < list_annots.size();
5483*9712c20fSFrederick Mayle          ++annotation_index) {
5484*9712c20fSFrederick Mayle       printf("  module_list[%d].list_annotations[%d] = %s\n", module_index,
5485*9712c20fSFrederick Mayle              annotation_index, list_annots[annotation_index].c_str());
5486*9712c20fSFrederick Mayle     }
5487*9712c20fSFrederick Mayle     const auto& simple_annots =
5488*9712c20fSFrederick Mayle         module_crashpad_info_simple_annotations_[module_index];
5489*9712c20fSFrederick Mayle     for (const auto& annot : simple_annots) {
5490*9712c20fSFrederick Mayle       printf("  module_list[%d].simple_annotations[\"%s\"] = %s\n",
5491*9712c20fSFrederick Mayle              module_index, annot.first.c_str(), annot.second.c_str());
5492*9712c20fSFrederick Mayle     }
5493*9712c20fSFrederick Mayle     const auto& crashpad_annots =
5494*9712c20fSFrederick Mayle         module_crashpad_info_annotation_objects_[module_index];
5495*9712c20fSFrederick Mayle     for (const AnnotationObject& annot : crashpad_annots) {
5496*9712c20fSFrederick Mayle       std::string str_value;
5497*9712c20fSFrederick Mayle       if (annot.type == 1) {
5498*9712c20fSFrederick Mayle         // Value represents a C-style string.
5499*9712c20fSFrederick Mayle         for (const uint8_t& v : annot.value) {
5500*9712c20fSFrederick Mayle           str_value.append(1, static_cast<char>(v));
5501*9712c20fSFrederick Mayle         }
5502*9712c20fSFrederick Mayle       } else {
5503*9712c20fSFrederick Mayle         // Value represents something else.
5504*9712c20fSFrederick Mayle         char buffer[3];
5505*9712c20fSFrederick Mayle         for (const uint8_t& v : annot.value) {
5506*9712c20fSFrederick Mayle           snprintf(buffer, sizeof(buffer), "%02X", v);
5507*9712c20fSFrederick Mayle           str_value.append(buffer);
5508*9712c20fSFrederick Mayle         }
5509*9712c20fSFrederick Mayle       }
5510*9712c20fSFrederick Mayle       printf(
5511*9712c20fSFrederick Mayle           "  module_list[%d].crashpad_annotations[\"%s\"] (type = %u) = %s\n",
5512*9712c20fSFrederick Mayle           module_index, annot.name.c_str(), annot.type, str_value.c_str());
5513*9712c20fSFrederick Mayle     }
5514*9712c20fSFrederick Mayle     printf("  address_mask = %" PRIu64 "\n", crashpad_info_.address_mask);
5515*9712c20fSFrederick Mayle   }
5516*9712c20fSFrederick Mayle 
5517*9712c20fSFrederick Mayle   printf("\n");
5518*9712c20fSFrederick Mayle }
5519*9712c20fSFrederick Mayle 
5520*9712c20fSFrederick Mayle 
5521*9712c20fSFrederick Mayle //
5522*9712c20fSFrederick Mayle // Minidump
5523*9712c20fSFrederick Mayle //
5524*9712c20fSFrederick Mayle 
5525*9712c20fSFrederick Mayle 
5526*9712c20fSFrederick Mayle uint32_t Minidump::max_streams_ = 128;
5527*9712c20fSFrederick Mayle unsigned int Minidump::max_string_length_ = 1024;
5528*9712c20fSFrederick Mayle 
5529*9712c20fSFrederick Mayle 
Minidump(const string & path,bool hexdump,unsigned int hexdump_width)5530*9712c20fSFrederick Mayle Minidump::Minidump(const string& path, bool hexdump, unsigned int hexdump_width)
5531*9712c20fSFrederick Mayle     : header_(),
5532*9712c20fSFrederick Mayle       directory_(NULL),
5533*9712c20fSFrederick Mayle       stream_map_(new MinidumpStreamMap()),
5534*9712c20fSFrederick Mayle       path_(path),
5535*9712c20fSFrederick Mayle       stream_(NULL),
5536*9712c20fSFrederick Mayle       swap_(false),
5537*9712c20fSFrederick Mayle       is_big_endian_(false),
5538*9712c20fSFrederick Mayle       valid_(false),
5539*9712c20fSFrederick Mayle       hexdump_(hexdump),
5540*9712c20fSFrederick Mayle       hexdump_width_(hexdump_width) {
5541*9712c20fSFrederick Mayle }
5542*9712c20fSFrederick Mayle 
Minidump(istream & stream)5543*9712c20fSFrederick Mayle Minidump::Minidump(istream& stream)
5544*9712c20fSFrederick Mayle     : header_(),
5545*9712c20fSFrederick Mayle       directory_(NULL),
5546*9712c20fSFrederick Mayle       stream_map_(new MinidumpStreamMap()),
5547*9712c20fSFrederick Mayle       path_(),
5548*9712c20fSFrederick Mayle       stream_(&stream),
5549*9712c20fSFrederick Mayle       swap_(false),
5550*9712c20fSFrederick Mayle       is_big_endian_(false),
5551*9712c20fSFrederick Mayle       valid_(false),
5552*9712c20fSFrederick Mayle       hexdump_(false),
5553*9712c20fSFrederick Mayle       hexdump_width_(0) {
5554*9712c20fSFrederick Mayle }
5555*9712c20fSFrederick Mayle 
~Minidump()5556*9712c20fSFrederick Mayle Minidump::~Minidump() {
5557*9712c20fSFrederick Mayle   if (stream_) {
5558*9712c20fSFrederick Mayle     BPLOG(INFO) << "Minidump closing minidump";
5559*9712c20fSFrederick Mayle   }
5560*9712c20fSFrederick Mayle   if (!path_.empty()) {
5561*9712c20fSFrederick Mayle     delete stream_;
5562*9712c20fSFrederick Mayle   }
5563*9712c20fSFrederick Mayle   delete directory_;
5564*9712c20fSFrederick Mayle   delete stream_map_;
5565*9712c20fSFrederick Mayle }
5566*9712c20fSFrederick Mayle 
5567*9712c20fSFrederick Mayle 
Open()5568*9712c20fSFrederick Mayle bool Minidump::Open() {
5569*9712c20fSFrederick Mayle   if (stream_ != NULL) {
5570*9712c20fSFrederick Mayle     BPLOG(INFO) << "Minidump reopening minidump " << path_;
5571*9712c20fSFrederick Mayle 
5572*9712c20fSFrederick Mayle     // The file is already open.  Seek to the beginning, which is the position
5573*9712c20fSFrederick Mayle     // the file would be at if it were opened anew.
5574*9712c20fSFrederick Mayle     return SeekSet(0);
5575*9712c20fSFrederick Mayle   }
5576*9712c20fSFrederick Mayle 
5577*9712c20fSFrederick Mayle   stream_ = new ifstream(path_.c_str(), std::ios::in | std::ios::binary);
5578*9712c20fSFrederick Mayle   if (!stream_ || !stream_->good()) {
5579*9712c20fSFrederick Mayle     string error_string;
5580*9712c20fSFrederick Mayle     int error_code = ErrnoString(&error_string);
5581*9712c20fSFrederick Mayle     BPLOG(ERROR) << "Minidump could not open minidump " << path_ <<
5582*9712c20fSFrederick Mayle                     ", error " << error_code << ": " << error_string;
5583*9712c20fSFrederick Mayle     return false;
5584*9712c20fSFrederick Mayle   }
5585*9712c20fSFrederick Mayle 
5586*9712c20fSFrederick Mayle   BPLOG(INFO) << "Minidump opened minidump " << path_;
5587*9712c20fSFrederick Mayle   return true;
5588*9712c20fSFrederick Mayle }
5589*9712c20fSFrederick Mayle 
GetContextCPUFlagsFromSystemInfo(uint32_t * context_cpu_flags)5590*9712c20fSFrederick Mayle bool Minidump::GetContextCPUFlagsFromSystemInfo(uint32_t* context_cpu_flags) {
5591*9712c20fSFrederick Mayle   // Initialize output parameters
5592*9712c20fSFrederick Mayle   *context_cpu_flags = 0;
5593*9712c20fSFrederick Mayle 
5594*9712c20fSFrederick Mayle   // Save the current stream position
5595*9712c20fSFrederick Mayle   off_t saved_position = Tell();
5596*9712c20fSFrederick Mayle   if (saved_position == -1) {
5597*9712c20fSFrederick Mayle     // Failed to save the current stream position.
5598*9712c20fSFrederick Mayle     // Returns true because the current position of the stream is preserved.
5599*9712c20fSFrederick Mayle     return true;
5600*9712c20fSFrederick Mayle   }
5601*9712c20fSFrederick Mayle 
5602*9712c20fSFrederick Mayle   const MDRawSystemInfo* system_info =
5603*9712c20fSFrederick Mayle     GetSystemInfo() ? GetSystemInfo()->system_info() : NULL;
5604*9712c20fSFrederick Mayle 
5605*9712c20fSFrederick Mayle   if (system_info != NULL) {
5606*9712c20fSFrederick Mayle     switch (system_info->processor_architecture) {
5607*9712c20fSFrederick Mayle       case MD_CPU_ARCHITECTURE_X86:
5608*9712c20fSFrederick Mayle         *context_cpu_flags = MD_CONTEXT_X86;
5609*9712c20fSFrederick Mayle         break;
5610*9712c20fSFrederick Mayle       case MD_CPU_ARCHITECTURE_MIPS:
5611*9712c20fSFrederick Mayle         *context_cpu_flags = MD_CONTEXT_MIPS;
5612*9712c20fSFrederick Mayle         break;
5613*9712c20fSFrederick Mayle       case MD_CPU_ARCHITECTURE_MIPS64:
5614*9712c20fSFrederick Mayle         *context_cpu_flags = MD_CONTEXT_MIPS64;
5615*9712c20fSFrederick Mayle         break;
5616*9712c20fSFrederick Mayle       case MD_CPU_ARCHITECTURE_ALPHA:
5617*9712c20fSFrederick Mayle         *context_cpu_flags = MD_CONTEXT_ALPHA;
5618*9712c20fSFrederick Mayle         break;
5619*9712c20fSFrederick Mayle       case MD_CPU_ARCHITECTURE_PPC:
5620*9712c20fSFrederick Mayle         *context_cpu_flags = MD_CONTEXT_PPC;
5621*9712c20fSFrederick Mayle         break;
5622*9712c20fSFrederick Mayle       case MD_CPU_ARCHITECTURE_PPC64:
5623*9712c20fSFrederick Mayle         *context_cpu_flags = MD_CONTEXT_PPC64;
5624*9712c20fSFrederick Mayle         break;
5625*9712c20fSFrederick Mayle       case MD_CPU_ARCHITECTURE_SHX:
5626*9712c20fSFrederick Mayle         *context_cpu_flags = MD_CONTEXT_SHX;
5627*9712c20fSFrederick Mayle         break;
5628*9712c20fSFrederick Mayle       case MD_CPU_ARCHITECTURE_ARM:
5629*9712c20fSFrederick Mayle         *context_cpu_flags = MD_CONTEXT_ARM;
5630*9712c20fSFrederick Mayle         break;
5631*9712c20fSFrederick Mayle       case MD_CPU_ARCHITECTURE_ARM64:
5632*9712c20fSFrederick Mayle         *context_cpu_flags = MD_CONTEXT_ARM64;
5633*9712c20fSFrederick Mayle         break;
5634*9712c20fSFrederick Mayle       case MD_CPU_ARCHITECTURE_ARM64_OLD:
5635*9712c20fSFrederick Mayle         *context_cpu_flags = MD_CONTEXT_ARM64_OLD;
5636*9712c20fSFrederick Mayle         break;
5637*9712c20fSFrederick Mayle       case MD_CPU_ARCHITECTURE_IA64:
5638*9712c20fSFrederick Mayle         *context_cpu_flags = MD_CONTEXT_IA64;
5639*9712c20fSFrederick Mayle         break;
5640*9712c20fSFrederick Mayle       case MD_CPU_ARCHITECTURE_ALPHA64:
5641*9712c20fSFrederick Mayle         *context_cpu_flags = 0;
5642*9712c20fSFrederick Mayle         break;
5643*9712c20fSFrederick Mayle       case MD_CPU_ARCHITECTURE_MSIL:
5644*9712c20fSFrederick Mayle         *context_cpu_flags = 0;
5645*9712c20fSFrederick Mayle         break;
5646*9712c20fSFrederick Mayle       case MD_CPU_ARCHITECTURE_AMD64:
5647*9712c20fSFrederick Mayle         *context_cpu_flags = MD_CONTEXT_AMD64;
5648*9712c20fSFrederick Mayle         break;
5649*9712c20fSFrederick Mayle       case MD_CPU_ARCHITECTURE_X86_WIN64:
5650*9712c20fSFrederick Mayle         *context_cpu_flags = 0;
5651*9712c20fSFrederick Mayle         break;
5652*9712c20fSFrederick Mayle       case MD_CPU_ARCHITECTURE_SPARC:
5653*9712c20fSFrederick Mayle         *context_cpu_flags = MD_CONTEXT_SPARC;
5654*9712c20fSFrederick Mayle         break;
5655*9712c20fSFrederick Mayle       case MD_CPU_ARCHITECTURE_RISCV:
5656*9712c20fSFrederick Mayle         *context_cpu_flags = MD_CONTEXT_RISCV;
5657*9712c20fSFrederick Mayle         break;
5658*9712c20fSFrederick Mayle       case MD_CPU_ARCHITECTURE_RISCV64:
5659*9712c20fSFrederick Mayle         *context_cpu_flags = MD_CONTEXT_RISCV64;
5660*9712c20fSFrederick Mayle         break;
5661*9712c20fSFrederick Mayle       case MD_CPU_ARCHITECTURE_UNKNOWN:
5662*9712c20fSFrederick Mayle         *context_cpu_flags = 0;
5663*9712c20fSFrederick Mayle         break;
5664*9712c20fSFrederick Mayle       default:
5665*9712c20fSFrederick Mayle         *context_cpu_flags = 0;
5666*9712c20fSFrederick Mayle         break;
5667*9712c20fSFrederick Mayle     }
5668*9712c20fSFrederick Mayle   }
5669*9712c20fSFrederick Mayle 
5670*9712c20fSFrederick Mayle   // Restore position and return
5671*9712c20fSFrederick Mayle   return SeekSet(saved_position);
5672*9712c20fSFrederick Mayle }
5673*9712c20fSFrederick Mayle 
5674*9712c20fSFrederick Mayle 
Read()5675*9712c20fSFrederick Mayle bool Minidump::Read() {
5676*9712c20fSFrederick Mayle   // Invalidate cached data.
5677*9712c20fSFrederick Mayle   delete directory_;
5678*9712c20fSFrederick Mayle   directory_ = NULL;
5679*9712c20fSFrederick Mayle   stream_map_->clear();
5680*9712c20fSFrederick Mayle 
5681*9712c20fSFrederick Mayle   valid_ = false;
5682*9712c20fSFrederick Mayle 
5683*9712c20fSFrederick Mayle   if (!Open()) {
5684*9712c20fSFrederick Mayle     BPLOG(ERROR) << "Minidump cannot open minidump";
5685*9712c20fSFrederick Mayle     return false;
5686*9712c20fSFrederick Mayle   }
5687*9712c20fSFrederick Mayle 
5688*9712c20fSFrederick Mayle   if (!ReadBytes(&header_, sizeof(MDRawHeader))) {
5689*9712c20fSFrederick Mayle     BPLOG(ERROR) << "Minidump cannot read header";
5690*9712c20fSFrederick Mayle     return false;
5691*9712c20fSFrederick Mayle   }
5692*9712c20fSFrederick Mayle 
5693*9712c20fSFrederick Mayle   if (header_.signature != MD_HEADER_SIGNATURE) {
5694*9712c20fSFrederick Mayle     // The file may be byte-swapped.  Under the present architecture, these
5695*9712c20fSFrederick Mayle     // classes don't know or need to know what CPU (or endianness) the
5696*9712c20fSFrederick Mayle     // minidump was produced on in order to parse it.  Use the signature as
5697*9712c20fSFrederick Mayle     // a byte order marker.
5698*9712c20fSFrederick Mayle     uint32_t signature_swapped = header_.signature;
5699*9712c20fSFrederick Mayle     Swap(&signature_swapped);
5700*9712c20fSFrederick Mayle     if (signature_swapped != MD_HEADER_SIGNATURE) {
5701*9712c20fSFrederick Mayle       // This isn't a minidump or a byte-swapped minidump.
5702*9712c20fSFrederick Mayle       BPLOG(ERROR) << "Minidump header signature mismatch: (" <<
5703*9712c20fSFrederick Mayle                       HexString(header_.signature) << ", " <<
5704*9712c20fSFrederick Mayle                       HexString(signature_swapped) << ") != " <<
5705*9712c20fSFrederick Mayle                       HexString(MD_HEADER_SIGNATURE);
5706*9712c20fSFrederick Mayle       return false;
5707*9712c20fSFrederick Mayle     }
5708*9712c20fSFrederick Mayle     swap_ = true;
5709*9712c20fSFrederick Mayle   } else {
5710*9712c20fSFrederick Mayle     // The file is not byte-swapped.  Set swap_ false (it may have been true
5711*9712c20fSFrederick Mayle     // if the object is being reused?)
5712*9712c20fSFrederick Mayle     swap_ = false;
5713*9712c20fSFrederick Mayle   }
5714*9712c20fSFrederick Mayle 
5715*9712c20fSFrederick Mayle #if defined(__BIG_ENDIAN__) || \
5716*9712c20fSFrederick Mayle   (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
5717*9712c20fSFrederick Mayle   is_big_endian_ = !swap_;
5718*9712c20fSFrederick Mayle #else
5719*9712c20fSFrederick Mayle   is_big_endian_ = swap_;
5720*9712c20fSFrederick Mayle #endif
5721*9712c20fSFrederick Mayle 
5722*9712c20fSFrederick Mayle   BPLOG(INFO) << "Minidump " << (swap_ ? "" : "not ") <<
5723*9712c20fSFrederick Mayle                  "byte-swapping minidump";
5724*9712c20fSFrederick Mayle 
5725*9712c20fSFrederick Mayle   if (swap_) {
5726*9712c20fSFrederick Mayle     Swap(&header_.signature);
5727*9712c20fSFrederick Mayle     Swap(&header_.version);
5728*9712c20fSFrederick Mayle     Swap(&header_.stream_count);
5729*9712c20fSFrederick Mayle     Swap(&header_.stream_directory_rva);
5730*9712c20fSFrederick Mayle     Swap(&header_.checksum);
5731*9712c20fSFrederick Mayle     Swap(&header_.time_date_stamp);
5732*9712c20fSFrederick Mayle     Swap(&header_.flags);
5733*9712c20fSFrederick Mayle   }
5734*9712c20fSFrederick Mayle 
5735*9712c20fSFrederick Mayle   // Version check.  The high 16 bits of header_.version contain something
5736*9712c20fSFrederick Mayle   // else "implementation specific."
5737*9712c20fSFrederick Mayle   if ((header_.version & 0x0000ffff) != MD_HEADER_VERSION) {
5738*9712c20fSFrederick Mayle     BPLOG(ERROR) << "Minidump version mismatch: " <<
5739*9712c20fSFrederick Mayle                     HexString(header_.version & 0x0000ffff) << " != " <<
5740*9712c20fSFrederick Mayle                     HexString(MD_HEADER_VERSION);
5741*9712c20fSFrederick Mayle     return false;
5742*9712c20fSFrederick Mayle   }
5743*9712c20fSFrederick Mayle 
5744*9712c20fSFrederick Mayle   if (!SeekSet(header_.stream_directory_rva)) {
5745*9712c20fSFrederick Mayle     BPLOG(ERROR) << "Minidump cannot seek to stream directory";
5746*9712c20fSFrederick Mayle     return false;
5747*9712c20fSFrederick Mayle   }
5748*9712c20fSFrederick Mayle 
5749*9712c20fSFrederick Mayle   if (header_.stream_count > max_streams_) {
5750*9712c20fSFrederick Mayle     BPLOG(ERROR) << "Minidump stream count " << header_.stream_count <<
5751*9712c20fSFrederick Mayle                     " exceeds maximum " << max_streams_;
5752*9712c20fSFrederick Mayle     return false;
5753*9712c20fSFrederick Mayle   }
5754*9712c20fSFrederick Mayle 
5755*9712c20fSFrederick Mayle   if (header_.stream_count != 0) {
5756*9712c20fSFrederick Mayle     scoped_ptr<MinidumpDirectoryEntries> directory(
5757*9712c20fSFrederick Mayle         new MinidumpDirectoryEntries(header_.stream_count));
5758*9712c20fSFrederick Mayle 
5759*9712c20fSFrederick Mayle     // Read the entire array in one fell swoop, instead of reading one entry
5760*9712c20fSFrederick Mayle     // at a time in the loop.
5761*9712c20fSFrederick Mayle     if (!ReadBytes(&(*directory)[0],
5762*9712c20fSFrederick Mayle                    sizeof(MDRawDirectory) * header_.stream_count)) {
5763*9712c20fSFrederick Mayle       BPLOG(ERROR) << "Minidump cannot read stream directory";
5764*9712c20fSFrederick Mayle       return false;
5765*9712c20fSFrederick Mayle     }
5766*9712c20fSFrederick Mayle 
5767*9712c20fSFrederick Mayle     for (unsigned int stream_index = 0;
5768*9712c20fSFrederick Mayle          stream_index < header_.stream_count;
5769*9712c20fSFrederick Mayle          ++stream_index) {
5770*9712c20fSFrederick Mayle       MDRawDirectory* directory_entry = &(*directory)[stream_index];
5771*9712c20fSFrederick Mayle 
5772*9712c20fSFrederick Mayle       if (swap_) {
5773*9712c20fSFrederick Mayle         Swap(&directory_entry->stream_type);
5774*9712c20fSFrederick Mayle         Swap(&directory_entry->location);
5775*9712c20fSFrederick Mayle       }
5776*9712c20fSFrederick Mayle 
5777*9712c20fSFrederick Mayle       // Initialize the stream_map_ map, which speeds locating a stream by
5778*9712c20fSFrederick Mayle       // type.
5779*9712c20fSFrederick Mayle       unsigned int stream_type = directory_entry->stream_type;
5780*9712c20fSFrederick Mayle       switch (stream_type) {
5781*9712c20fSFrederick Mayle         case MD_THREAD_LIST_STREAM:
5782*9712c20fSFrederick Mayle         case MD_THREAD_NAME_LIST_STREAM:
5783*9712c20fSFrederick Mayle         case MD_MODULE_LIST_STREAM:
5784*9712c20fSFrederick Mayle         case MD_MEMORY_LIST_STREAM:
5785*9712c20fSFrederick Mayle         case MD_EXCEPTION_STREAM:
5786*9712c20fSFrederick Mayle         case MD_SYSTEM_INFO_STREAM:
5787*9712c20fSFrederick Mayle         case MD_MISC_INFO_STREAM:
5788*9712c20fSFrederick Mayle         case MD_BREAKPAD_INFO_STREAM:
5789*9712c20fSFrederick Mayle         case MD_CRASHPAD_INFO_STREAM: {
5790*9712c20fSFrederick Mayle           if (stream_map_->find(stream_type) != stream_map_->end()) {
5791*9712c20fSFrederick Mayle             // Another stream with this type was already found.  A minidump
5792*9712c20fSFrederick Mayle             // file should contain at most one of each of these stream types.
5793*9712c20fSFrederick Mayle             BPLOG(ERROR) << "Minidump found multiple streams of type " <<
5794*9712c20fSFrederick Mayle                             stream_type << ", but can only deal with one";
5795*9712c20fSFrederick Mayle             return false;
5796*9712c20fSFrederick Mayle           }
5797*9712c20fSFrederick Mayle           BP_FALLTHROUGH;
5798*9712c20fSFrederick Mayle         }
5799*9712c20fSFrederick Mayle 
5800*9712c20fSFrederick Mayle         default: {
5801*9712c20fSFrederick Mayle           // Overwrites for stream types other than those above, but it's
5802*9712c20fSFrederick Mayle           // expected to be the user's burden in that case.
5803*9712c20fSFrederick Mayle           (*stream_map_)[stream_type].stream_index = stream_index;
5804*9712c20fSFrederick Mayle         }
5805*9712c20fSFrederick Mayle       }
5806*9712c20fSFrederick Mayle     }
5807*9712c20fSFrederick Mayle 
5808*9712c20fSFrederick Mayle     directory_ = directory.release();
5809*9712c20fSFrederick Mayle   }
5810*9712c20fSFrederick Mayle 
5811*9712c20fSFrederick Mayle   valid_ = true;
5812*9712c20fSFrederick Mayle   return true;
5813*9712c20fSFrederick Mayle }
5814*9712c20fSFrederick Mayle 
5815*9712c20fSFrederick Mayle 
GetThreadList()5816*9712c20fSFrederick Mayle MinidumpThreadList* Minidump::GetThreadList() {
5817*9712c20fSFrederick Mayle   MinidumpThreadList* thread_list;
5818*9712c20fSFrederick Mayle   return GetStream(&thread_list);
5819*9712c20fSFrederick Mayle }
5820*9712c20fSFrederick Mayle 
GetThreadNameList()5821*9712c20fSFrederick Mayle MinidumpThreadNameList* Minidump::GetThreadNameList() {
5822*9712c20fSFrederick Mayle   MinidumpThreadNameList* thread_name_list;
5823*9712c20fSFrederick Mayle   return GetStream(&thread_name_list);
5824*9712c20fSFrederick Mayle }
5825*9712c20fSFrederick Mayle 
GetModuleList()5826*9712c20fSFrederick Mayle MinidumpModuleList* Minidump::GetModuleList() {
5827*9712c20fSFrederick Mayle   MinidumpModuleList* module_list;
5828*9712c20fSFrederick Mayle   return GetStream(&module_list);
5829*9712c20fSFrederick Mayle }
5830*9712c20fSFrederick Mayle 
5831*9712c20fSFrederick Mayle 
GetMemoryList()5832*9712c20fSFrederick Mayle MinidumpMemoryList* Minidump::GetMemoryList() {
5833*9712c20fSFrederick Mayle   MinidumpMemoryList* memory_list;
5834*9712c20fSFrederick Mayle   return GetStream(&memory_list);
5835*9712c20fSFrederick Mayle }
5836*9712c20fSFrederick Mayle 
5837*9712c20fSFrederick Mayle 
GetException()5838*9712c20fSFrederick Mayle MinidumpException* Minidump::GetException() {
5839*9712c20fSFrederick Mayle   MinidumpException* exception;
5840*9712c20fSFrederick Mayle   return GetStream(&exception);
5841*9712c20fSFrederick Mayle }
5842*9712c20fSFrederick Mayle 
GetAssertion()5843*9712c20fSFrederick Mayle MinidumpAssertion* Minidump::GetAssertion() {
5844*9712c20fSFrederick Mayle   MinidumpAssertion* assertion;
5845*9712c20fSFrederick Mayle   return GetStream(&assertion);
5846*9712c20fSFrederick Mayle }
5847*9712c20fSFrederick Mayle 
5848*9712c20fSFrederick Mayle 
GetSystemInfo()5849*9712c20fSFrederick Mayle MinidumpSystemInfo* Minidump::GetSystemInfo() {
5850*9712c20fSFrederick Mayle   MinidumpSystemInfo* system_info;
5851*9712c20fSFrederick Mayle   return GetStream(&system_info);
5852*9712c20fSFrederick Mayle }
5853*9712c20fSFrederick Mayle 
5854*9712c20fSFrederick Mayle 
GetUnloadedModuleList()5855*9712c20fSFrederick Mayle MinidumpUnloadedModuleList* Minidump::GetUnloadedModuleList() {
5856*9712c20fSFrederick Mayle   MinidumpUnloadedModuleList* unloaded_module_list;
5857*9712c20fSFrederick Mayle   return GetStream(&unloaded_module_list);
5858*9712c20fSFrederick Mayle }
5859*9712c20fSFrederick Mayle 
5860*9712c20fSFrederick Mayle 
GetMiscInfo()5861*9712c20fSFrederick Mayle MinidumpMiscInfo* Minidump::GetMiscInfo() {
5862*9712c20fSFrederick Mayle   MinidumpMiscInfo* misc_info;
5863*9712c20fSFrederick Mayle   return GetStream(&misc_info);
5864*9712c20fSFrederick Mayle }
5865*9712c20fSFrederick Mayle 
5866*9712c20fSFrederick Mayle 
GetBreakpadInfo()5867*9712c20fSFrederick Mayle MinidumpBreakpadInfo* Minidump::GetBreakpadInfo() {
5868*9712c20fSFrederick Mayle   MinidumpBreakpadInfo* breakpad_info;
5869*9712c20fSFrederick Mayle   return GetStream(&breakpad_info);
5870*9712c20fSFrederick Mayle }
5871*9712c20fSFrederick Mayle 
GetMemoryInfoList()5872*9712c20fSFrederick Mayle MinidumpMemoryInfoList* Minidump::GetMemoryInfoList() {
5873*9712c20fSFrederick Mayle   MinidumpMemoryInfoList* memory_info_list;
5874*9712c20fSFrederick Mayle   return GetStream(&memory_info_list);
5875*9712c20fSFrederick Mayle }
5876*9712c20fSFrederick Mayle 
GetLinuxMapsList()5877*9712c20fSFrederick Mayle MinidumpLinuxMapsList* Minidump::GetLinuxMapsList() {
5878*9712c20fSFrederick Mayle   MinidumpLinuxMapsList* linux_maps_list;
5879*9712c20fSFrederick Mayle   return GetStream(&linux_maps_list);
5880*9712c20fSFrederick Mayle }
5881*9712c20fSFrederick Mayle 
IsAndroid()5882*9712c20fSFrederick Mayle bool Minidump::IsAndroid() {
5883*9712c20fSFrederick Mayle   MDOSPlatform platform;
5884*9712c20fSFrederick Mayle   return GetPlatform(&platform) && platform == MD_OS_ANDROID;
5885*9712c20fSFrederick Mayle }
5886*9712c20fSFrederick Mayle 
GetPlatform(MDOSPlatform * platform)5887*9712c20fSFrederick Mayle bool Minidump::GetPlatform(MDOSPlatform* platform) {
5888*9712c20fSFrederick Mayle   // Save the current stream position
5889*9712c20fSFrederick Mayle   off_t saved_position = Tell();
5890*9712c20fSFrederick Mayle   if (saved_position == -1) {
5891*9712c20fSFrederick Mayle     return false;
5892*9712c20fSFrederick Mayle   }
5893*9712c20fSFrederick Mayle   const MDRawSystemInfo* system_info =
5894*9712c20fSFrederick Mayle     GetSystemInfo() ? GetSystemInfo()->system_info() : NULL;
5895*9712c20fSFrederick Mayle 
5896*9712c20fSFrederick Mayle   // Restore position and return
5897*9712c20fSFrederick Mayle   if (!SeekSet(saved_position)) {
5898*9712c20fSFrederick Mayle     BPLOG(ERROR) << "Couldn't seek back to saved position";
5899*9712c20fSFrederick Mayle     return false;
5900*9712c20fSFrederick Mayle   }
5901*9712c20fSFrederick Mayle 
5902*9712c20fSFrederick Mayle   if (!system_info) {
5903*9712c20fSFrederick Mayle     return false;
5904*9712c20fSFrederick Mayle   }
5905*9712c20fSFrederick Mayle   *platform = static_cast<MDOSPlatform>(system_info->platform_id);
5906*9712c20fSFrederick Mayle   return true;
5907*9712c20fSFrederick Mayle }
5908*9712c20fSFrederick Mayle 
GetCrashpadInfo()5909*9712c20fSFrederick Mayle MinidumpCrashpadInfo* Minidump::GetCrashpadInfo() {
5910*9712c20fSFrederick Mayle   MinidumpCrashpadInfo* crashpad_info;
5911*9712c20fSFrederick Mayle   return GetStream(&crashpad_info);
5912*9712c20fSFrederick Mayle }
5913*9712c20fSFrederick Mayle 
get_stream_name(uint32_t stream_type)5914*9712c20fSFrederick Mayle static const char* get_stream_name(uint32_t stream_type) {
5915*9712c20fSFrederick Mayle   switch (stream_type) {
5916*9712c20fSFrederick Mayle   case MD_UNUSED_STREAM:
5917*9712c20fSFrederick Mayle     return "MD_UNUSED_STREAM";
5918*9712c20fSFrederick Mayle   case MD_RESERVED_STREAM_0:
5919*9712c20fSFrederick Mayle     return "MD_RESERVED_STREAM_0";
5920*9712c20fSFrederick Mayle   case MD_RESERVED_STREAM_1:
5921*9712c20fSFrederick Mayle     return "MD_RESERVED_STREAM_1";
5922*9712c20fSFrederick Mayle   case MD_THREAD_LIST_STREAM:
5923*9712c20fSFrederick Mayle     return "MD_THREAD_LIST_STREAM";
5924*9712c20fSFrederick Mayle   case MD_THREAD_NAME_LIST_STREAM:
5925*9712c20fSFrederick Mayle     return "MD_THREAD_NAME_LIST_STREAM";
5926*9712c20fSFrederick Mayle   case MD_MODULE_LIST_STREAM:
5927*9712c20fSFrederick Mayle     return "MD_MODULE_LIST_STREAM";
5928*9712c20fSFrederick Mayle   case MD_MEMORY_LIST_STREAM:
5929*9712c20fSFrederick Mayle     return "MD_MEMORY_LIST_STREAM";
5930*9712c20fSFrederick Mayle   case MD_EXCEPTION_STREAM:
5931*9712c20fSFrederick Mayle     return "MD_EXCEPTION_STREAM";
5932*9712c20fSFrederick Mayle   case MD_SYSTEM_INFO_STREAM:
5933*9712c20fSFrederick Mayle     return "MD_SYSTEM_INFO_STREAM";
5934*9712c20fSFrederick Mayle   case MD_THREAD_EX_LIST_STREAM:
5935*9712c20fSFrederick Mayle     return "MD_THREAD_EX_LIST_STREAM";
5936*9712c20fSFrederick Mayle   case MD_MEMORY_64_LIST_STREAM:
5937*9712c20fSFrederick Mayle     return "MD_MEMORY_64_LIST_STREAM";
5938*9712c20fSFrederick Mayle   case MD_COMMENT_STREAM_A:
5939*9712c20fSFrederick Mayle     return "MD_COMMENT_STREAM_A";
5940*9712c20fSFrederick Mayle   case MD_COMMENT_STREAM_W:
5941*9712c20fSFrederick Mayle     return "MD_COMMENT_STREAM_W";
5942*9712c20fSFrederick Mayle   case MD_HANDLE_DATA_STREAM:
5943*9712c20fSFrederick Mayle     return "MD_HANDLE_DATA_STREAM";
5944*9712c20fSFrederick Mayle   case MD_FUNCTION_TABLE_STREAM:
5945*9712c20fSFrederick Mayle     return "MD_FUNCTION_TABLE_STREAM";
5946*9712c20fSFrederick Mayle   case MD_UNLOADED_MODULE_LIST_STREAM:
5947*9712c20fSFrederick Mayle     return "MD_UNLOADED_MODULE_LIST_STREAM";
5948*9712c20fSFrederick Mayle   case MD_MISC_INFO_STREAM:
5949*9712c20fSFrederick Mayle     return "MD_MISC_INFO_STREAM";
5950*9712c20fSFrederick Mayle   case MD_MEMORY_INFO_LIST_STREAM:
5951*9712c20fSFrederick Mayle     return "MD_MEMORY_INFO_LIST_STREAM";
5952*9712c20fSFrederick Mayle   case MD_THREAD_INFO_LIST_STREAM:
5953*9712c20fSFrederick Mayle     return "MD_THREAD_INFO_LIST_STREAM";
5954*9712c20fSFrederick Mayle   case MD_HANDLE_OPERATION_LIST_STREAM:
5955*9712c20fSFrederick Mayle     return "MD_HANDLE_OPERATION_LIST_STREAM";
5956*9712c20fSFrederick Mayle   case MD_TOKEN_STREAM:
5957*9712c20fSFrederick Mayle     return "MD_TOKEN_STREAM";
5958*9712c20fSFrederick Mayle   case MD_JAVASCRIPT_DATA_STREAM:
5959*9712c20fSFrederick Mayle     return "MD_JAVASCRIPT_DATA_STREAM";
5960*9712c20fSFrederick Mayle   case MD_SYSTEM_MEMORY_INFO_STREAM:
5961*9712c20fSFrederick Mayle     return "MD_SYSTEM_MEMORY_INFO_STREAM";
5962*9712c20fSFrederick Mayle   case MD_PROCESS_VM_COUNTERS_STREAM:
5963*9712c20fSFrederick Mayle     return "MD_PROCESS_VM_COUNTERS_STREAM";
5964*9712c20fSFrederick Mayle   case MD_LAST_RESERVED_STREAM:
5965*9712c20fSFrederick Mayle     return "MD_LAST_RESERVED_STREAM";
5966*9712c20fSFrederick Mayle   case MD_BREAKPAD_INFO_STREAM:
5967*9712c20fSFrederick Mayle     return "MD_BREAKPAD_INFO_STREAM";
5968*9712c20fSFrederick Mayle   case MD_ASSERTION_INFO_STREAM:
5969*9712c20fSFrederick Mayle     return "MD_ASSERTION_INFO_STREAM";
5970*9712c20fSFrederick Mayle   case MD_LINUX_CPU_INFO:
5971*9712c20fSFrederick Mayle     return "MD_LINUX_CPU_INFO";
5972*9712c20fSFrederick Mayle   case MD_LINUX_PROC_STATUS:
5973*9712c20fSFrederick Mayle     return "MD_LINUX_PROC_STATUS";
5974*9712c20fSFrederick Mayle   case MD_LINUX_LSB_RELEASE:
5975*9712c20fSFrederick Mayle     return "MD_LINUX_LSB_RELEASE";
5976*9712c20fSFrederick Mayle   case MD_LINUX_CMD_LINE:
5977*9712c20fSFrederick Mayle     return "MD_LINUX_CMD_LINE";
5978*9712c20fSFrederick Mayle   case MD_LINUX_ENVIRON:
5979*9712c20fSFrederick Mayle     return "MD_LINUX_ENVIRON";
5980*9712c20fSFrederick Mayle   case MD_LINUX_AUXV:
5981*9712c20fSFrederick Mayle     return "MD_LINUX_AUXV";
5982*9712c20fSFrederick Mayle   case MD_LINUX_MAPS:
5983*9712c20fSFrederick Mayle     return "MD_LINUX_MAPS";
5984*9712c20fSFrederick Mayle   case MD_LINUX_DSO_DEBUG:
5985*9712c20fSFrederick Mayle     return "MD_LINUX_DSO_DEBUG";
5986*9712c20fSFrederick Mayle   case MD_CRASHPAD_INFO_STREAM:
5987*9712c20fSFrederick Mayle     return "MD_CRASHPAD_INFO_STREAM";
5988*9712c20fSFrederick Mayle   default:
5989*9712c20fSFrederick Mayle     return "unknown";
5990*9712c20fSFrederick Mayle   }
5991*9712c20fSFrederick Mayle }
5992*9712c20fSFrederick Mayle 
Print()5993*9712c20fSFrederick Mayle void Minidump::Print() {
5994*9712c20fSFrederick Mayle   if (!valid_) {
5995*9712c20fSFrederick Mayle     BPLOG(ERROR) << "Minidump cannot print invalid data";
5996*9712c20fSFrederick Mayle     return;
5997*9712c20fSFrederick Mayle   }
5998*9712c20fSFrederick Mayle 
5999*9712c20fSFrederick Mayle   printf("MDRawHeader\n");
6000*9712c20fSFrederick Mayle   printf("  signature            = 0x%x\n",    header_.signature);
6001*9712c20fSFrederick Mayle   printf("  version              = 0x%x\n",    header_.version);
6002*9712c20fSFrederick Mayle   printf("  stream_count         = %d\n",      header_.stream_count);
6003*9712c20fSFrederick Mayle   printf("  stream_directory_rva = 0x%x\n",    header_.stream_directory_rva);
6004*9712c20fSFrederick Mayle   printf("  checksum             = 0x%x\n",    header_.checksum);
6005*9712c20fSFrederick Mayle   printf("  time_date_stamp      = 0x%x %s\n",
6006*9712c20fSFrederick Mayle          header_.time_date_stamp,
6007*9712c20fSFrederick Mayle          TimeTToUTCString(header_.time_date_stamp).c_str());
6008*9712c20fSFrederick Mayle   printf("  flags                = 0x%" PRIx64 "\n",  header_.flags);
6009*9712c20fSFrederick Mayle   printf("\n");
6010*9712c20fSFrederick Mayle 
6011*9712c20fSFrederick Mayle   for (unsigned int stream_index = 0;
6012*9712c20fSFrederick Mayle        stream_index < header_.stream_count;
6013*9712c20fSFrederick Mayle        ++stream_index) {
6014*9712c20fSFrederick Mayle     MDRawDirectory* directory_entry = &(*directory_)[stream_index];
6015*9712c20fSFrederick Mayle 
6016*9712c20fSFrederick Mayle     printf("mDirectory[%d]\n", stream_index);
6017*9712c20fSFrederick Mayle     printf("MDRawDirectory\n");
6018*9712c20fSFrederick Mayle     printf("  stream_type        = 0x%x (%s)\n", directory_entry->stream_type,
6019*9712c20fSFrederick Mayle            get_stream_name(directory_entry->stream_type));
6020*9712c20fSFrederick Mayle     printf("  location.data_size = %d\n",
6021*9712c20fSFrederick Mayle            directory_entry->location.data_size);
6022*9712c20fSFrederick Mayle     printf("  location.rva       = 0x%x\n", directory_entry->location.rva);
6023*9712c20fSFrederick Mayle     printf("\n");
6024*9712c20fSFrederick Mayle   }
6025*9712c20fSFrederick Mayle 
6026*9712c20fSFrederick Mayle   printf("Streams:\n");
6027*9712c20fSFrederick Mayle   for (MinidumpStreamMap::const_iterator iterator = stream_map_->begin();
6028*9712c20fSFrederick Mayle        iterator != stream_map_->end();
6029*9712c20fSFrederick Mayle        ++iterator) {
6030*9712c20fSFrederick Mayle     uint32_t stream_type = iterator->first;
6031*9712c20fSFrederick Mayle     const MinidumpStreamInfo& info = iterator->second;
6032*9712c20fSFrederick Mayle     printf("  stream type 0x%x (%s) at index %d\n", stream_type,
6033*9712c20fSFrederick Mayle            get_stream_name(stream_type),
6034*9712c20fSFrederick Mayle            info.stream_index);
6035*9712c20fSFrederick Mayle   }
6036*9712c20fSFrederick Mayle   printf("\n");
6037*9712c20fSFrederick Mayle }
6038*9712c20fSFrederick Mayle 
6039*9712c20fSFrederick Mayle 
GetDirectoryEntryAtIndex(unsigned int index) const6040*9712c20fSFrederick Mayle const MDRawDirectory* Minidump::GetDirectoryEntryAtIndex(unsigned int index)
6041*9712c20fSFrederick Mayle       const {
6042*9712c20fSFrederick Mayle   if (!valid_) {
6043*9712c20fSFrederick Mayle     BPLOG(ERROR) << "Invalid Minidump for GetDirectoryEntryAtIndex";
6044*9712c20fSFrederick Mayle     return NULL;
6045*9712c20fSFrederick Mayle   }
6046*9712c20fSFrederick Mayle 
6047*9712c20fSFrederick Mayle   if (index >= header_.stream_count) {
6048*9712c20fSFrederick Mayle     BPLOG(ERROR) << "Minidump stream directory index out of range: " <<
6049*9712c20fSFrederick Mayle                     index << "/" << header_.stream_count;
6050*9712c20fSFrederick Mayle     return NULL;
6051*9712c20fSFrederick Mayle   }
6052*9712c20fSFrederick Mayle 
6053*9712c20fSFrederick Mayle   return &(*directory_)[index];
6054*9712c20fSFrederick Mayle }
6055*9712c20fSFrederick Mayle 
6056*9712c20fSFrederick Mayle 
ReadBytes(void * bytes,size_t count)6057*9712c20fSFrederick Mayle bool Minidump::ReadBytes(void* bytes, size_t count) {
6058*9712c20fSFrederick Mayle   // Can't check valid_ because Read needs to call this method before
6059*9712c20fSFrederick Mayle   // validity can be determined.
6060*9712c20fSFrederick Mayle   if (!stream_) {
6061*9712c20fSFrederick Mayle     return false;
6062*9712c20fSFrederick Mayle   }
6063*9712c20fSFrederick Mayle   stream_->read(static_cast<char*>(bytes), count);
6064*9712c20fSFrederick Mayle   std::streamsize bytes_read = stream_->gcount();
6065*9712c20fSFrederick Mayle   if (bytes_read == -1) {
6066*9712c20fSFrederick Mayle     string error_string;
6067*9712c20fSFrederick Mayle     int error_code = ErrnoString(&error_string);
6068*9712c20fSFrederick Mayle     BPLOG(ERROR) << "ReadBytes: error " << error_code << ": " << error_string;
6069*9712c20fSFrederick Mayle     return false;
6070*9712c20fSFrederick Mayle   }
6071*9712c20fSFrederick Mayle 
6072*9712c20fSFrederick Mayle   // Convert to size_t and check for data loss
6073*9712c20fSFrederick Mayle   size_t bytes_read_converted = static_cast<size_t>(bytes_read);
6074*9712c20fSFrederick Mayle   if (static_cast<std::streamsize>(bytes_read_converted) != bytes_read) {
6075*9712c20fSFrederick Mayle     BPLOG(ERROR) << "ReadBytes: conversion data loss detected when converting "
6076*9712c20fSFrederick Mayle                  << bytes_read << " to " << bytes_read_converted;
6077*9712c20fSFrederick Mayle     return false;
6078*9712c20fSFrederick Mayle   }
6079*9712c20fSFrederick Mayle 
6080*9712c20fSFrederick Mayle   if (bytes_read_converted != count) {
6081*9712c20fSFrederick Mayle     BPLOG(ERROR) << "ReadBytes: read " << bytes_read_converted << "/" << count;
6082*9712c20fSFrederick Mayle     return false;
6083*9712c20fSFrederick Mayle   }
6084*9712c20fSFrederick Mayle 
6085*9712c20fSFrederick Mayle   return true;
6086*9712c20fSFrederick Mayle }
6087*9712c20fSFrederick Mayle 
6088*9712c20fSFrederick Mayle 
SeekSet(off_t offset)6089*9712c20fSFrederick Mayle bool Minidump::SeekSet(off_t offset) {
6090*9712c20fSFrederick Mayle   // Can't check valid_ because Read needs to call this method before
6091*9712c20fSFrederick Mayle   // validity can be determined.
6092*9712c20fSFrederick Mayle   if (!stream_) {
6093*9712c20fSFrederick Mayle     return false;
6094*9712c20fSFrederick Mayle   }
6095*9712c20fSFrederick Mayle   stream_->seekg(offset, std::ios_base::beg);
6096*9712c20fSFrederick Mayle   if (!stream_->good()) {
6097*9712c20fSFrederick Mayle     string error_string;
6098*9712c20fSFrederick Mayle     int error_code = ErrnoString(&error_string);
6099*9712c20fSFrederick Mayle     BPLOG(ERROR) << "SeekSet: error " << error_code << ": " << error_string;
6100*9712c20fSFrederick Mayle     return false;
6101*9712c20fSFrederick Mayle   }
6102*9712c20fSFrederick Mayle   return true;
6103*9712c20fSFrederick Mayle }
6104*9712c20fSFrederick Mayle 
Tell()6105*9712c20fSFrederick Mayle off_t Minidump::Tell() {
6106*9712c20fSFrederick Mayle   if (!valid_ || !stream_) {
6107*9712c20fSFrederick Mayle     return (off_t)-1;
6108*9712c20fSFrederick Mayle   }
6109*9712c20fSFrederick Mayle 
6110*9712c20fSFrederick Mayle   // Check for conversion data loss
6111*9712c20fSFrederick Mayle   std::streamoff std_streamoff = stream_->tellg();
6112*9712c20fSFrederick Mayle   off_t rv = static_cast<off_t>(std_streamoff);
6113*9712c20fSFrederick Mayle   if (static_cast<std::streamoff>(rv) == std_streamoff) {
6114*9712c20fSFrederick Mayle     return rv;
6115*9712c20fSFrederick Mayle   } else {
6116*9712c20fSFrederick Mayle     BPLOG(ERROR) << "Data loss detected";
6117*9712c20fSFrederick Mayle     return (off_t)-1;
6118*9712c20fSFrederick Mayle   }
6119*9712c20fSFrederick Mayle }
6120*9712c20fSFrederick Mayle 
6121*9712c20fSFrederick Mayle 
ReadString(off_t offset)6122*9712c20fSFrederick Mayle string* Minidump::ReadString(off_t offset) {
6123*9712c20fSFrederick Mayle   if (!valid_) {
6124*9712c20fSFrederick Mayle     BPLOG(ERROR) << "Invalid Minidump for ReadString";
6125*9712c20fSFrederick Mayle     return NULL;
6126*9712c20fSFrederick Mayle   }
6127*9712c20fSFrederick Mayle   if (!SeekSet(offset)) {
6128*9712c20fSFrederick Mayle     BPLOG(ERROR) << "ReadString could not seek to string at offset " << offset;
6129*9712c20fSFrederick Mayle     return NULL;
6130*9712c20fSFrederick Mayle   }
6131*9712c20fSFrederick Mayle 
6132*9712c20fSFrederick Mayle   uint32_t bytes;
6133*9712c20fSFrederick Mayle   if (!ReadBytes(&bytes, sizeof(bytes))) {
6134*9712c20fSFrederick Mayle     BPLOG(ERROR) << "ReadString could not read string size at offset " <<
6135*9712c20fSFrederick Mayle                     offset;
6136*9712c20fSFrederick Mayle     return NULL;
6137*9712c20fSFrederick Mayle   }
6138*9712c20fSFrederick Mayle   if (swap_)
6139*9712c20fSFrederick Mayle     Swap(&bytes);
6140*9712c20fSFrederick Mayle 
6141*9712c20fSFrederick Mayle   if (bytes % 2 != 0) {
6142*9712c20fSFrederick Mayle     BPLOG(ERROR) << "ReadString found odd-sized " << bytes <<
6143*9712c20fSFrederick Mayle                     "-byte string at offset " << offset;
6144*9712c20fSFrederick Mayle     return NULL;
6145*9712c20fSFrederick Mayle   }
6146*9712c20fSFrederick Mayle   unsigned int utf16_words = bytes / 2;
6147*9712c20fSFrederick Mayle 
6148*9712c20fSFrederick Mayle   if (utf16_words > max_string_length_) {
6149*9712c20fSFrederick Mayle     BPLOG(ERROR) << "ReadString string length " << utf16_words <<
6150*9712c20fSFrederick Mayle                     " exceeds maximum " << max_string_length_ <<
6151*9712c20fSFrederick Mayle                     " at offset " << offset;
6152*9712c20fSFrederick Mayle     return NULL;
6153*9712c20fSFrederick Mayle   }
6154*9712c20fSFrederick Mayle 
6155*9712c20fSFrederick Mayle   vector<uint16_t> string_utf16(utf16_words);
6156*9712c20fSFrederick Mayle 
6157*9712c20fSFrederick Mayle   if (utf16_words) {
6158*9712c20fSFrederick Mayle     if (!ReadBytes(&string_utf16[0], bytes)) {
6159*9712c20fSFrederick Mayle       BPLOG(ERROR) << "ReadString could not read " << bytes <<
6160*9712c20fSFrederick Mayle                       "-byte string at offset " << offset;
6161*9712c20fSFrederick Mayle       return NULL;
6162*9712c20fSFrederick Mayle     }
6163*9712c20fSFrederick Mayle   }
6164*9712c20fSFrederick Mayle 
6165*9712c20fSFrederick Mayle   return UTF16ToUTF8(string_utf16, swap_);
6166*9712c20fSFrederick Mayle }
6167*9712c20fSFrederick Mayle 
6168*9712c20fSFrederick Mayle 
ReadUTF8String(off_t offset,string * string_utf8)6169*9712c20fSFrederick Mayle bool Minidump::ReadUTF8String(off_t offset, string* string_utf8) {
6170*9712c20fSFrederick Mayle   if (!valid_) {
6171*9712c20fSFrederick Mayle     BPLOG(ERROR) << "Invalid Minidump for ReadString";
6172*9712c20fSFrederick Mayle     return false;
6173*9712c20fSFrederick Mayle   }
6174*9712c20fSFrederick Mayle   if (!SeekSet(offset)) {
6175*9712c20fSFrederick Mayle     BPLOG(ERROR) << "ReadUTF8String could not seek to string at offset "
6176*9712c20fSFrederick Mayle                  << offset;
6177*9712c20fSFrederick Mayle     return false;
6178*9712c20fSFrederick Mayle   }
6179*9712c20fSFrederick Mayle 
6180*9712c20fSFrederick Mayle   uint32_t bytes;
6181*9712c20fSFrederick Mayle   if (!ReadBytes(&bytes, sizeof(bytes))) {
6182*9712c20fSFrederick Mayle     BPLOG(ERROR) << "ReadUTF8String could not read string size at offset " <<
6183*9712c20fSFrederick Mayle                     offset;
6184*9712c20fSFrederick Mayle     return false;
6185*9712c20fSFrederick Mayle   }
6186*9712c20fSFrederick Mayle 
6187*9712c20fSFrederick Mayle   if (swap_) {
6188*9712c20fSFrederick Mayle     Swap(&bytes);
6189*9712c20fSFrederick Mayle   }
6190*9712c20fSFrederick Mayle 
6191*9712c20fSFrederick Mayle   if (bytes > max_string_length_) {
6192*9712c20fSFrederick Mayle     BPLOG(ERROR) << "ReadUTF8String string length " << bytes <<
6193*9712c20fSFrederick Mayle                     " exceeds maximum " << max_string_length_ <<
6194*9712c20fSFrederick Mayle                     " at offset " << offset;
6195*9712c20fSFrederick Mayle     return false;
6196*9712c20fSFrederick Mayle   }
6197*9712c20fSFrederick Mayle 
6198*9712c20fSFrederick Mayle   string_utf8->resize(bytes);
6199*9712c20fSFrederick Mayle 
6200*9712c20fSFrederick Mayle   if (!ReadBytes(&(*string_utf8)[0], bytes)) {
6201*9712c20fSFrederick Mayle     BPLOG(ERROR) << "ReadUTF8String could not read " << bytes <<
6202*9712c20fSFrederick Mayle                     "-byte string at offset " << offset;
6203*9712c20fSFrederick Mayle     return false;
6204*9712c20fSFrederick Mayle   }
6205*9712c20fSFrederick Mayle 
6206*9712c20fSFrederick Mayle   return true;
6207*9712c20fSFrederick Mayle }
6208*9712c20fSFrederick Mayle 
6209*9712c20fSFrederick Mayle 
ReadStringList(off_t offset,std::vector<std::string> * string_list)6210*9712c20fSFrederick Mayle bool Minidump::ReadStringList(
6211*9712c20fSFrederick Mayle     off_t offset,
6212*9712c20fSFrederick Mayle     std::vector<std::string>* string_list) {
6213*9712c20fSFrederick Mayle   string_list->clear();
6214*9712c20fSFrederick Mayle 
6215*9712c20fSFrederick Mayle   if (!SeekSet(offset)) {
6216*9712c20fSFrederick Mayle     BPLOG(ERROR) << "Minidump cannot seek to string_list";
6217*9712c20fSFrederick Mayle     return false;
6218*9712c20fSFrederick Mayle   }
6219*9712c20fSFrederick Mayle 
6220*9712c20fSFrederick Mayle   uint32_t count;
6221*9712c20fSFrederick Mayle   if (!ReadBytes(&count, sizeof(count))) {
6222*9712c20fSFrederick Mayle     BPLOG(ERROR) << "Minidump cannot read string_list count";
6223*9712c20fSFrederick Mayle     return false;
6224*9712c20fSFrederick Mayle   }
6225*9712c20fSFrederick Mayle 
6226*9712c20fSFrederick Mayle   if (swap_) {
6227*9712c20fSFrederick Mayle     Swap(&count);
6228*9712c20fSFrederick Mayle   }
6229*9712c20fSFrederick Mayle 
6230*9712c20fSFrederick Mayle   scoped_array<MDRVA> rvas(new MDRVA[count]);
6231*9712c20fSFrederick Mayle 
6232*9712c20fSFrederick Mayle   // Read the entire array in one fell swoop, instead of reading one entry
6233*9712c20fSFrederick Mayle   // at a time in the loop.
6234*9712c20fSFrederick Mayle   if (!ReadBytes(&rvas[0], sizeof(MDRVA) * count)) {
6235*9712c20fSFrederick Mayle     BPLOG(ERROR) << "Minidump could not read string_list";
6236*9712c20fSFrederick Mayle     return false;
6237*9712c20fSFrederick Mayle   }
6238*9712c20fSFrederick Mayle 
6239*9712c20fSFrederick Mayle   for (uint32_t index = 0; index < count; ++index) {
6240*9712c20fSFrederick Mayle     if (swap()) {
6241*9712c20fSFrederick Mayle       Swap(&rvas[index]);
6242*9712c20fSFrederick Mayle     }
6243*9712c20fSFrederick Mayle 
6244*9712c20fSFrederick Mayle     string entry;
6245*9712c20fSFrederick Mayle     if (!ReadUTF8String(rvas[index], &entry)) {
6246*9712c20fSFrederick Mayle       BPLOG(ERROR) << "Minidump could not read string_list entry";
6247*9712c20fSFrederick Mayle       return false;
6248*9712c20fSFrederick Mayle     }
6249*9712c20fSFrederick Mayle 
6250*9712c20fSFrederick Mayle     string_list->push_back(entry);
6251*9712c20fSFrederick Mayle   }
6252*9712c20fSFrederick Mayle 
6253*9712c20fSFrederick Mayle   return true;
6254*9712c20fSFrederick Mayle }
6255*9712c20fSFrederick Mayle 
6256*9712c20fSFrederick Mayle 
ReadSimpleStringDictionary(off_t offset,std::map<std::string,std::string> * simple_string_dictionary)6257*9712c20fSFrederick Mayle bool Minidump::ReadSimpleStringDictionary(
6258*9712c20fSFrederick Mayle     off_t offset,
6259*9712c20fSFrederick Mayle     std::map<std::string, std::string>* simple_string_dictionary) {
6260*9712c20fSFrederick Mayle   simple_string_dictionary->clear();
6261*9712c20fSFrederick Mayle 
6262*9712c20fSFrederick Mayle   if (!SeekSet(offset)) {
6263*9712c20fSFrederick Mayle     BPLOG(ERROR) << "Minidump cannot seek to simple_string_dictionary";
6264*9712c20fSFrederick Mayle     return false;
6265*9712c20fSFrederick Mayle   }
6266*9712c20fSFrederick Mayle 
6267*9712c20fSFrederick Mayle   uint32_t count;
6268*9712c20fSFrederick Mayle   if (!ReadBytes(&count, sizeof(count))) {
6269*9712c20fSFrederick Mayle     BPLOG(ERROR)
6270*9712c20fSFrederick Mayle         << "Minidump cannot read simple_string_dictionary count";
6271*9712c20fSFrederick Mayle     return false;
6272*9712c20fSFrederick Mayle   }
6273*9712c20fSFrederick Mayle 
6274*9712c20fSFrederick Mayle   if (swap()) {
6275*9712c20fSFrederick Mayle     Swap(&count);
6276*9712c20fSFrederick Mayle   }
6277*9712c20fSFrederick Mayle 
6278*9712c20fSFrederick Mayle   scoped_array<MDRawSimpleStringDictionaryEntry> entries(
6279*9712c20fSFrederick Mayle       new MDRawSimpleStringDictionaryEntry[count]);
6280*9712c20fSFrederick Mayle 
6281*9712c20fSFrederick Mayle   // Read the entire array in one fell swoop, instead of reading one entry
6282*9712c20fSFrederick Mayle   // at a time in the loop.
6283*9712c20fSFrederick Mayle   if (!ReadBytes(
6284*9712c20fSFrederick Mayle           &entries[0],
6285*9712c20fSFrederick Mayle           sizeof(MDRawSimpleStringDictionaryEntry) * count)) {
6286*9712c20fSFrederick Mayle     BPLOG(ERROR) << "Minidump could not read simple_string_dictionary";
6287*9712c20fSFrederick Mayle     return false;
6288*9712c20fSFrederick Mayle   }
6289*9712c20fSFrederick Mayle 
6290*9712c20fSFrederick Mayle   for (uint32_t index = 0; index < count; ++index) {
6291*9712c20fSFrederick Mayle     if (swap()) {
6292*9712c20fSFrederick Mayle       Swap(&entries[index]);
6293*9712c20fSFrederick Mayle     }
6294*9712c20fSFrederick Mayle 
6295*9712c20fSFrederick Mayle     string key;
6296*9712c20fSFrederick Mayle     if (!ReadUTF8String(entries[index].key, &key)) {
6297*9712c20fSFrederick Mayle       BPLOG(ERROR) << "Minidump could not read simple_string_dictionary key";
6298*9712c20fSFrederick Mayle       return false;
6299*9712c20fSFrederick Mayle     }
6300*9712c20fSFrederick Mayle 
6301*9712c20fSFrederick Mayle     string value;
6302*9712c20fSFrederick Mayle     if (!ReadUTF8String(entries[index].value, &value)) {
6303*9712c20fSFrederick Mayle       BPLOG(ERROR) << "Minidump could not read simple_string_dictionary value";
6304*9712c20fSFrederick Mayle       return false;
6305*9712c20fSFrederick Mayle     }
6306*9712c20fSFrederick Mayle 
6307*9712c20fSFrederick Mayle     if (simple_string_dictionary->find(key) !=
6308*9712c20fSFrederick Mayle         simple_string_dictionary->end()) {
6309*9712c20fSFrederick Mayle       BPLOG(ERROR)
6310*9712c20fSFrederick Mayle           << "Minidump: discarding duplicate simple_string_dictionary value "
6311*9712c20fSFrederick Mayle           << value << " for key " << key;
6312*9712c20fSFrederick Mayle     } else {
6313*9712c20fSFrederick Mayle       simple_string_dictionary->insert(std::make_pair(key, value));
6314*9712c20fSFrederick Mayle     }
6315*9712c20fSFrederick Mayle   }
6316*9712c20fSFrederick Mayle 
6317*9712c20fSFrederick Mayle   return true;
6318*9712c20fSFrederick Mayle }
6319*9712c20fSFrederick Mayle 
ReadCrashpadAnnotationsList(off_t offset,std::vector<MinidumpCrashpadInfo::AnnotationObject> * annotations_list)6320*9712c20fSFrederick Mayle bool Minidump::ReadCrashpadAnnotationsList(
6321*9712c20fSFrederick Mayle     off_t offset,
6322*9712c20fSFrederick Mayle     std::vector<MinidumpCrashpadInfo::AnnotationObject>* annotations_list) {
6323*9712c20fSFrederick Mayle   annotations_list->clear();
6324*9712c20fSFrederick Mayle 
6325*9712c20fSFrederick Mayle   if (!SeekSet(offset)) {
6326*9712c20fSFrederick Mayle     BPLOG(ERROR) << "Minidump cannot seek to annotations_list";
6327*9712c20fSFrederick Mayle     return false;
6328*9712c20fSFrederick Mayle   }
6329*9712c20fSFrederick Mayle 
6330*9712c20fSFrederick Mayle   uint32_t count;
6331*9712c20fSFrederick Mayle   if (!ReadBytes(&count, sizeof(count))) {
6332*9712c20fSFrederick Mayle     BPLOG(ERROR) << "Minidump cannot read annotations_list count";
6333*9712c20fSFrederick Mayle     return false;
6334*9712c20fSFrederick Mayle   }
6335*9712c20fSFrederick Mayle 
6336*9712c20fSFrederick Mayle   if (swap_) {
6337*9712c20fSFrederick Mayle     Swap(&count);
6338*9712c20fSFrederick Mayle   }
6339*9712c20fSFrederick Mayle 
6340*9712c20fSFrederick Mayle   scoped_array<MDRawCrashpadAnnotation> objects(
6341*9712c20fSFrederick Mayle       new MDRawCrashpadAnnotation[count]);
6342*9712c20fSFrederick Mayle 
6343*9712c20fSFrederick Mayle   // Read the entire array in one fell swoop, instead of reading one entry
6344*9712c20fSFrederick Mayle   // at a time in the loop.
6345*9712c20fSFrederick Mayle   if (!ReadBytes(&objects[0], sizeof(MDRawCrashpadAnnotation) * count)) {
6346*9712c20fSFrederick Mayle     BPLOG(ERROR) << "Minidump could not read annotations_list";
6347*9712c20fSFrederick Mayle     return false;
6348*9712c20fSFrederick Mayle   }
6349*9712c20fSFrederick Mayle 
6350*9712c20fSFrederick Mayle   for (uint32_t index = 0; index < count; ++index) {
6351*9712c20fSFrederick Mayle     MDRawCrashpadAnnotation annotation = objects[index];
6352*9712c20fSFrederick Mayle 
6353*9712c20fSFrederick Mayle     if (swap_) {
6354*9712c20fSFrederick Mayle       Swap(&annotation);
6355*9712c20fSFrederick Mayle     }
6356*9712c20fSFrederick Mayle 
6357*9712c20fSFrederick Mayle     string name;
6358*9712c20fSFrederick Mayle     if (!ReadUTF8String(annotation.name, &name)) {
6359*9712c20fSFrederick Mayle       BPLOG(ERROR) << "Minidump could not read annotation name";
6360*9712c20fSFrederick Mayle       return false;
6361*9712c20fSFrederick Mayle     }
6362*9712c20fSFrederick Mayle 
6363*9712c20fSFrederick Mayle     if (!SeekSet(annotation.value)) {
6364*9712c20fSFrederick Mayle       BPLOG(ERROR) << "Minidump cannot seek to annotations value";
6365*9712c20fSFrederick Mayle       return false;
6366*9712c20fSFrederick Mayle     }
6367*9712c20fSFrederick Mayle 
6368*9712c20fSFrederick Mayle     uint32_t value_length;
6369*9712c20fSFrederick Mayle     if (!ReadBytes(&value_length, sizeof(value_length))) {
6370*9712c20fSFrederick Mayle       BPLOG(ERROR) << "Minidump could not read annotation value length";
6371*9712c20fSFrederick Mayle       return false;
6372*9712c20fSFrederick Mayle     }
6373*9712c20fSFrederick Mayle 
6374*9712c20fSFrederick Mayle     std::vector<uint8_t> value_data(value_length);
6375*9712c20fSFrederick Mayle     if (!ReadBytes(value_data.data(), value_length)) {
6376*9712c20fSFrederick Mayle       BPLOG(ERROR) << "Minidump could not read annotation value";
6377*9712c20fSFrederick Mayle       return false;
6378*9712c20fSFrederick Mayle     }
6379*9712c20fSFrederick Mayle 
6380*9712c20fSFrederick Mayle     MinidumpCrashpadInfo::AnnotationObject object = {annotation.type, name,
6381*9712c20fSFrederick Mayle                                                      value_data};
6382*9712c20fSFrederick Mayle     annotations_list->push_back(object);
6383*9712c20fSFrederick Mayle   }
6384*9712c20fSFrederick Mayle 
6385*9712c20fSFrederick Mayle   return true;
6386*9712c20fSFrederick Mayle }
6387*9712c20fSFrederick Mayle 
SeekToStreamType(uint32_t stream_type,uint32_t * stream_length)6388*9712c20fSFrederick Mayle bool Minidump::SeekToStreamType(uint32_t  stream_type,
6389*9712c20fSFrederick Mayle                                 uint32_t* stream_length) {
6390*9712c20fSFrederick Mayle   BPLOG_IF(ERROR, !stream_length) << "Minidump::SeekToStreamType requires "
6391*9712c20fSFrederick Mayle                                      "|stream_length|";
6392*9712c20fSFrederick Mayle   assert(stream_length);
6393*9712c20fSFrederick Mayle   *stream_length = 0;
6394*9712c20fSFrederick Mayle 
6395*9712c20fSFrederick Mayle   if (!valid_) {
6396*9712c20fSFrederick Mayle     BPLOG(ERROR) << "Invalid Mindump for SeekToStreamType";
6397*9712c20fSFrederick Mayle     return false;
6398*9712c20fSFrederick Mayle   }
6399*9712c20fSFrederick Mayle 
6400*9712c20fSFrederick Mayle   MinidumpStreamMap::const_iterator iterator = stream_map_->find(stream_type);
6401*9712c20fSFrederick Mayle   if (iterator == stream_map_->end()) {
6402*9712c20fSFrederick Mayle     // This stream type didn't exist in the directory.
6403*9712c20fSFrederick Mayle     BPLOG(INFO) << "SeekToStreamType: type " << stream_type << " not present";
6404*9712c20fSFrederick Mayle     return false;
6405*9712c20fSFrederick Mayle   }
6406*9712c20fSFrederick Mayle 
6407*9712c20fSFrederick Mayle   const MinidumpStreamInfo& info = iterator->second;
6408*9712c20fSFrederick Mayle   if (info.stream_index >= header_.stream_count) {
6409*9712c20fSFrederick Mayle     BPLOG(ERROR) << "SeekToStreamType: type " << stream_type <<
6410*9712c20fSFrederick Mayle                     " out of range: " <<
6411*9712c20fSFrederick Mayle                     info.stream_index << "/" << header_.stream_count;
6412*9712c20fSFrederick Mayle     return false;
6413*9712c20fSFrederick Mayle   }
6414*9712c20fSFrederick Mayle 
6415*9712c20fSFrederick Mayle   MDRawDirectory* directory_entry = &(*directory_)[info.stream_index];
6416*9712c20fSFrederick Mayle   if (!SeekSet(directory_entry->location.rva)) {
6417*9712c20fSFrederick Mayle     BPLOG(ERROR) << "SeekToStreamType could not seek to stream type " <<
6418*9712c20fSFrederick Mayle                     stream_type;
6419*9712c20fSFrederick Mayle     return false;
6420*9712c20fSFrederick Mayle   }
6421*9712c20fSFrederick Mayle 
6422*9712c20fSFrederick Mayle   *stream_length = directory_entry->location.data_size;
6423*9712c20fSFrederick Mayle 
6424*9712c20fSFrederick Mayle   return true;
6425*9712c20fSFrederick Mayle }
6426*9712c20fSFrederick Mayle 
6427*9712c20fSFrederick Mayle 
6428*9712c20fSFrederick Mayle template<typename T>
GetStream(T ** stream)6429*9712c20fSFrederick Mayle T* Minidump::GetStream(T** stream) {
6430*9712c20fSFrederick Mayle   // stream is a garbage parameter that's present only to account for C++'s
6431*9712c20fSFrederick Mayle   // inability to overload a method based solely on its return type.
6432*9712c20fSFrederick Mayle 
6433*9712c20fSFrederick Mayle   const uint32_t stream_type = T::kStreamType;
6434*9712c20fSFrederick Mayle 
6435*9712c20fSFrederick Mayle   BPLOG_IF(ERROR, !stream) << "Minidump::GetStream type " << stream_type <<
6436*9712c20fSFrederick Mayle                               " requires |stream|";
6437*9712c20fSFrederick Mayle   assert(stream);
6438*9712c20fSFrederick Mayle   *stream = NULL;
6439*9712c20fSFrederick Mayle 
6440*9712c20fSFrederick Mayle   if (!valid_) {
6441*9712c20fSFrederick Mayle     BPLOG(ERROR) << "Invalid Minidump for GetStream type " << stream_type;
6442*9712c20fSFrederick Mayle     return NULL;
6443*9712c20fSFrederick Mayle   }
6444*9712c20fSFrederick Mayle 
6445*9712c20fSFrederick Mayle   MinidumpStreamMap::iterator iterator = stream_map_->find(stream_type);
6446*9712c20fSFrederick Mayle   if (iterator == stream_map_->end()) {
6447*9712c20fSFrederick Mayle     // This stream type didn't exist in the directory.
6448*9712c20fSFrederick Mayle     BPLOG(INFO) << "GetStream: type " << stream_type << " not present";
6449*9712c20fSFrederick Mayle     return NULL;
6450*9712c20fSFrederick Mayle   }
6451*9712c20fSFrederick Mayle 
6452*9712c20fSFrederick Mayle   // Get a pointer so that the stored stream field can be altered.
6453*9712c20fSFrederick Mayle   MinidumpStreamInfo* info = &iterator->second;
6454*9712c20fSFrederick Mayle 
6455*9712c20fSFrederick Mayle   if (info->stream) {
6456*9712c20fSFrederick Mayle     // This cast is safe because info.stream is only populated by this
6457*9712c20fSFrederick Mayle     // method, and there is a direct correlation between T and stream_type.
6458*9712c20fSFrederick Mayle     *stream = static_cast<T*>(info->stream);
6459*9712c20fSFrederick Mayle     return *stream;
6460*9712c20fSFrederick Mayle   }
6461*9712c20fSFrederick Mayle 
6462*9712c20fSFrederick Mayle   uint32_t stream_length;
6463*9712c20fSFrederick Mayle   if (!SeekToStreamType(stream_type, &stream_length)) {
6464*9712c20fSFrederick Mayle     BPLOG(ERROR) << "GetStream could not seek to stream type " << stream_type;
6465*9712c20fSFrederick Mayle     return NULL;
6466*9712c20fSFrederick Mayle   }
6467*9712c20fSFrederick Mayle 
6468*9712c20fSFrederick Mayle   scoped_ptr<T> new_stream(new T(this));
6469*9712c20fSFrederick Mayle 
6470*9712c20fSFrederick Mayle   if (!new_stream->Read(stream_length)) {
6471*9712c20fSFrederick Mayle     BPLOG(ERROR) << "GetStream could not read stream type " << stream_type;
6472*9712c20fSFrederick Mayle     return NULL;
6473*9712c20fSFrederick Mayle   }
6474*9712c20fSFrederick Mayle 
6475*9712c20fSFrederick Mayle   *stream = new_stream.release();
6476*9712c20fSFrederick Mayle   info->stream = *stream;
6477*9712c20fSFrederick Mayle   return *stream;
6478*9712c20fSFrederick Mayle }
6479*9712c20fSFrederick Mayle 
6480*9712c20fSFrederick Mayle }  // namespace google_breakpad
6481