minidump_generator.cc revision 486229ba5044ee2e7f49d2f6000e6535f2fca46c
1// Copyright (c) 2006, Google Inc.
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions are
6// met:
7//
8//     * Redistributions of source code must retain the above copyright
9// notice, this list of conditions and the following disclaimer.
10//     * Redistributions in binary form must reproduce the above
11// copyright notice, this list of conditions and the following disclaimer
12// in the documentation and/or other materials provided with the
13// distribution.
14//     * Neither the name of Google Inc. nor the names of its
15// contributors may be used to endorse or promote products derived from
16// this software without specific prior written permission.
17//
18// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30#include <algorithm>
31#include <cstdio>
32
33#include <mach/host_info.h>
34#include <mach/vm_statistics.h>
35#include <mach-o/dyld.h>
36#include <mach-o/loader.h>
37#include <sys/sysctl.h>
38#include <sys/resource.h>
39
40#include <CoreFoundation/CoreFoundation.h>
41
42#include "client/mac/handler/minidump_generator.h"
43
44#ifdef HAS_ARM_SUPPORT
45#include <mach/arm/thread_status.h>
46#endif
47#ifdef HAS_PPC_SUPPORT
48#include <mach/ppc/thread_status.h>
49#endif
50#ifdef HAS_X86_SUPPORT
51#include <mach/i386/thread_status.h>
52#endif
53
54#include "client/minidump_file_writer-inl.h"
55#include "common/mac/file_id.h"
56#include "common/mac/macho_id.h"
57#include "common/mac/string_utilities.h"
58
59using MacStringUtils::ConvertToString;
60using MacStringUtils::IntegerValueAtIndex;
61
62namespace google_breakpad {
63
64#if __LP64__
65#define LC_SEGMENT_ARCH LC_SEGMENT_64
66#else
67#define LC_SEGMENT_ARCH LC_SEGMENT
68#endif
69
70// constructor when generating from within the crashed process
71MinidumpGenerator::MinidumpGenerator()
72    : writer_(),
73      exception_type_(0),
74      exception_code_(0),
75      exception_subcode_(0),
76      exception_thread_(0),
77      crashing_task_(mach_task_self()),
78      handler_thread_(mach_thread_self()),
79      cpu_type_(DynamicImages::GetNativeCPUType()),
80      task_context_(NULL),
81      dynamic_images_(NULL),
82      memory_blocks_(&allocator_) {
83  GatherSystemInformation();
84}
85
86// constructor when generating from a different process than the
87// crashed process
88MinidumpGenerator::MinidumpGenerator(mach_port_t crashing_task,
89                                     mach_port_t handler_thread)
90    : writer_(),
91      exception_type_(0),
92      exception_code_(0),
93      exception_subcode_(0),
94      exception_thread_(0),
95      crashing_task_(crashing_task),
96      handler_thread_(handler_thread),
97      cpu_type_(DynamicImages::GetNativeCPUType()),
98      task_context_(NULL),
99      dynamic_images_(NULL),
100      memory_blocks_(&allocator_) {
101  if (crashing_task != mach_task_self()) {
102    dynamic_images_ = new DynamicImages(crashing_task_);
103    cpu_type_ = dynamic_images_->GetCPUType();
104  } else {
105    dynamic_images_ = NULL;
106    cpu_type_ = DynamicImages::GetNativeCPUType();
107  }
108
109  GatherSystemInformation();
110}
111
112MinidumpGenerator::~MinidumpGenerator() {
113  delete dynamic_images_;
114}
115
116char MinidumpGenerator::build_string_[16];
117int MinidumpGenerator::os_major_version_ = 0;
118int MinidumpGenerator::os_minor_version_ = 0;
119int MinidumpGenerator::os_build_number_ = 0;
120
121// static
122void MinidumpGenerator::GatherSystemInformation() {
123  // If this is non-zero, then we've already gathered the information
124  if (os_major_version_)
125    return;
126
127  // This code extracts the version and build information from the OS
128  CFStringRef vers_path =
129    CFSTR("/System/Library/CoreServices/SystemVersion.plist");
130  CFURLRef sys_vers =
131    CFURLCreateWithFileSystemPath(NULL,
132                                  vers_path,
133                                  kCFURLPOSIXPathStyle,
134                                  false);
135  CFDataRef data;
136  SInt32 error;
137  CFURLCreateDataAndPropertiesFromResource(NULL, sys_vers, &data, NULL, NULL,
138                                           &error);
139
140  if (!data) {
141    CFRelease(sys_vers);
142    return;
143  }
144
145  CFDictionaryRef list = static_cast<CFDictionaryRef>
146    (CFPropertyListCreateFromXMLData(NULL, data, kCFPropertyListImmutable,
147                                     NULL));
148  if (!list) {
149    CFRelease(sys_vers);
150    CFRelease(data);
151    return;
152  }
153
154  CFStringRef build_version = static_cast<CFStringRef>
155    (CFDictionaryGetValue(list, CFSTR("ProductBuildVersion")));
156  CFStringRef product_version = static_cast<CFStringRef>
157    (CFDictionaryGetValue(list, CFSTR("ProductVersion")));
158  string build_str = ConvertToString(build_version);
159  string product_str = ConvertToString(product_version);
160
161  CFRelease(list);
162  CFRelease(sys_vers);
163  CFRelease(data);
164
165  strlcpy(build_string_, build_str.c_str(), sizeof(build_string_));
166
167  // Parse the string that looks like "10.4.8"
168  os_major_version_ = IntegerValueAtIndex(product_str, 0);
169  os_minor_version_ = IntegerValueAtIndex(product_str, 1);
170  os_build_number_ = IntegerValueAtIndex(product_str, 2);
171}
172
173void MinidumpGenerator::SetTaskContext(ucontext_t *task_context) {
174  task_context_ = task_context;
175}
176
177string MinidumpGenerator::UniqueNameInDirectory(const string &dir,
178                                                string *unique_name) {
179  CFUUIDRef uuid = CFUUIDCreate(NULL);
180  CFStringRef uuid_cfstr = CFUUIDCreateString(NULL, uuid);
181  CFRelease(uuid);
182  string file_name(ConvertToString(uuid_cfstr));
183  CFRelease(uuid_cfstr);
184  string path(dir);
185
186  // Ensure that the directory (if non-empty) has a trailing slash so that
187  // we can append the file name and have a valid pathname.
188  if (!dir.empty()) {
189    if (dir.at(dir.size() - 1) != '/')
190      path.append(1, '/');
191  }
192
193  path.append(file_name);
194  path.append(".dmp");
195
196  if (unique_name)
197    *unique_name = file_name;
198
199  return path;
200}
201
202bool MinidumpGenerator::Write(const char *path) {
203  WriteStreamFN writers[] = {
204    &MinidumpGenerator::WriteThreadListStream,
205    &MinidumpGenerator::WriteMemoryListStream,
206    &MinidumpGenerator::WriteSystemInfoStream,
207    &MinidumpGenerator::WriteModuleListStream,
208    &MinidumpGenerator::WriteMiscInfoStream,
209    &MinidumpGenerator::WriteBreakpadInfoStream,
210    // Exception stream needs to be the last entry in this array as it may
211    // be omitted in the case where the minidump is written without an
212    // exception.
213    &MinidumpGenerator::WriteExceptionStream,
214  };
215  bool result = false;
216
217  // If opening was successful, create the header, directory, and call each
218  // writer.  The destructor for the TypedMDRVAs will cause the data to be
219  // flushed.  The destructor for the MinidumpFileWriter will close the file.
220  if (writer_.Open(path)) {
221    TypedMDRVA<MDRawHeader> header(&writer_);
222    TypedMDRVA<MDRawDirectory> dir(&writer_);
223
224    if (!header.Allocate())
225      return false;
226
227    int writer_count = static_cast<int>(sizeof(writers) / sizeof(writers[0]));
228
229    // If we don't have exception information, don't write out the
230    // exception stream
231    if (!exception_thread_ && !exception_type_)
232      --writer_count;
233
234    // Add space for all writers
235    if (!dir.AllocateArray(writer_count))
236      return false;
237
238    MDRawHeader *header_ptr = header.get();
239    header_ptr->signature = MD_HEADER_SIGNATURE;
240    header_ptr->version = MD_HEADER_VERSION;
241    time(reinterpret_cast<time_t *>(&(header_ptr->time_date_stamp)));
242    header_ptr->stream_count = writer_count;
243    header_ptr->stream_directory_rva = dir.position();
244
245    MDRawDirectory local_dir;
246    result = true;
247    for (int i = 0; (result) && (i < writer_count); ++i) {
248      result = (this->*writers[i])(&local_dir);
249
250      if (result)
251        dir.CopyIndex(i, &local_dir);
252    }
253  }
254  return result;
255}
256
257size_t MinidumpGenerator::CalculateStackSize(mach_vm_address_t start_addr) {
258  mach_vm_address_t stack_region_base = start_addr;
259  mach_vm_size_t stack_region_size;
260  natural_t nesting_level = 0;
261  vm_region_submap_info_64 submap_info;
262  mach_msg_type_number_t info_count = VM_REGION_SUBMAP_INFO_COUNT_64;
263
264  vm_region_recurse_info_t region_info;
265  region_info = reinterpret_cast<vm_region_recurse_info_t>(&submap_info);
266
267  if (start_addr == 0) {
268    return 0;
269  }
270
271  kern_return_t result =
272    mach_vm_region_recurse(crashing_task_, &stack_region_base,
273                           &stack_region_size, &nesting_level,
274                           region_info, &info_count);
275
276  if (result != KERN_SUCCESS || start_addr < stack_region_base) {
277    // Failure or stack corruption, since mach_vm_region had to go
278    // higher in the process address space to find a valid region.
279    return 0;
280  }
281
282  unsigned int tag = submap_info.user_tag;
283
284  // If the user tag is VM_MEMORY_STACK, look for more readable regions with
285  // the same tag placed immediately above the computed stack region. Under
286  // some circumstances, the stack for thread 0 winds up broken up into
287  // multiple distinct abutting regions. This can happen for several reasons,
288  // including user code that calls setrlimit(RLIMIT_STACK, ...) or changes
289  // the access on stack pages by calling mprotect.
290  if (tag == VM_MEMORY_STACK) {
291    while (true) {
292      mach_vm_address_t next_region_base = stack_region_base +
293                                           stack_region_size;
294      mach_vm_address_t proposed_next_region_base = next_region_base;
295      mach_vm_size_t next_region_size;
296      nesting_level = 0;
297      info_count = VM_REGION_SUBMAP_INFO_COUNT_64;
298      result = mach_vm_region_recurse(crashing_task_, &next_region_base,
299                                      &next_region_size, &nesting_level,
300                                      region_info, &info_count);
301      if (result != KERN_SUCCESS ||
302          next_region_base != proposed_next_region_base ||
303          submap_info.user_tag != tag ||
304          (submap_info.protection & VM_PROT_READ) == 0) {
305        break;
306      }
307
308      stack_region_size += next_region_size;
309    }
310  }
311
312  return stack_region_base + stack_region_size - start_addr;
313}
314
315bool MinidumpGenerator::WriteStackFromStartAddress(
316    mach_vm_address_t start_addr,
317    MDMemoryDescriptor *stack_location) {
318  UntypedMDRVA memory(&writer_);
319
320  bool result = false;
321  size_t size = CalculateStackSize(start_addr);
322
323  if (size == 0) {
324      // In some situations the stack address for the thread can come back 0.
325      // In these cases we skip over the threads in question and stuff the
326      // stack with a clearly borked value.
327      start_addr = 0xDEADBEEF;
328      size = 16;
329      if (!memory.Allocate(size))
330        return false;
331
332      unsigned long long dummy_stack[2];  // Fill dummy stack with 16 bytes of
333                                          // junk.
334      dummy_stack[0] = 0xDEADBEEF;
335      dummy_stack[1] = 0xDEADBEEF;
336
337      result = memory.Copy(dummy_stack, size);
338  } else {
339
340    if (!memory.Allocate(size))
341      return false;
342
343    if (dynamic_images_) {
344      vector<uint8_t> stack_memory;
345      if (ReadTaskMemory(crashing_task_,
346                         start_addr,
347                         size,
348                         stack_memory) != KERN_SUCCESS) {
349        return false;
350      }
351
352      result = memory.Copy(&stack_memory[0], size);
353    } else {
354      result = memory.Copy(reinterpret_cast<const void *>(start_addr), size);
355    }
356  }
357
358  stack_location->start_of_memory_range = start_addr;
359  stack_location->memory = memory.location();
360
361  return result;
362}
363
364bool MinidumpGenerator::WriteStack(breakpad_thread_state_data_t state,
365                                   MDMemoryDescriptor *stack_location) {
366  switch (cpu_type_) {
367#ifdef HAS_ARM_SUPPORT
368    case CPU_TYPE_ARM:
369      return WriteStackARM(state, stack_location);
370#endif
371#ifdef HAS_PPC_SUPPORT
372    case CPU_TYPE_POWERPC:
373      return WriteStackPPC(state, stack_location);
374    case CPU_TYPE_POWERPC64:
375      return WriteStackPPC64(state, stack_location);
376#endif
377#ifdef HAS_X86_SUPPORT
378    case CPU_TYPE_I386:
379      return WriteStackX86(state, stack_location);
380    case CPU_TYPE_X86_64:
381      return WriteStackX86_64(state, stack_location);
382#endif
383    default:
384      return false;
385  }
386}
387
388bool MinidumpGenerator::WriteContext(breakpad_thread_state_data_t state,
389                                     MDLocationDescriptor *register_location) {
390  switch (cpu_type_) {
391#ifdef HAS_ARM_SUPPORT
392    case CPU_TYPE_ARM:
393      return WriteContextARM(state, register_location);
394#endif
395#ifdef HAS_PPC_SUPPORT
396    case CPU_TYPE_POWERPC:
397      return WriteContextPPC(state, register_location);
398    case CPU_TYPE_POWERPC64:
399      return WriteContextPPC64(state, register_location);
400#endif
401#ifdef HAS_X86_SUPPORT
402    case CPU_TYPE_I386:
403      return WriteContextX86(state, register_location);
404    case CPU_TYPE_X86_64:
405      return WriteContextX86_64(state, register_location);
406#endif
407    default:
408      return false;
409  }
410}
411
412u_int64_t MinidumpGenerator::CurrentPCForStack(
413    breakpad_thread_state_data_t state) {
414  switch (cpu_type_) {
415#ifdef HAS_ARM_SUPPORT
416    case CPU_TYPE_ARM:
417      return CurrentPCForStackARM(state);
418#endif
419#ifdef HAS_PPC_SUPPORT
420    case CPU_TYPE_POWERPC:
421      return CurrentPCForStackPPC(state);
422    case CPU_TYPE_POWERPC64:
423      return CurrentPCForStackPPC64(state);
424#endif
425#ifdef HAS_X86_SUPPORT
426    case CPU_TYPE_I386:
427      return CurrentPCForStackX86(state);
428    case CPU_TYPE_X86_64:
429      return CurrentPCForStackX86_64(state);
430#endif
431    default:
432      assert(0 && "Unknown CPU type!");
433      return 0;
434  }
435}
436
437#ifdef HAS_ARM_SUPPORT
438bool MinidumpGenerator::WriteStackARM(breakpad_thread_state_data_t state,
439                                      MDMemoryDescriptor *stack_location) {
440  arm_thread_state_t *machine_state =
441      reinterpret_cast<arm_thread_state_t *>(state);
442  mach_vm_address_t start_addr = REGISTER_FROM_THREADSTATE(machine_state, sp);
443  return WriteStackFromStartAddress(start_addr, stack_location);
444}
445
446u_int64_t
447MinidumpGenerator::CurrentPCForStackARM(breakpad_thread_state_data_t state) {
448  arm_thread_state_t *machine_state =
449      reinterpret_cast<arm_thread_state_t *>(state);
450
451  return REGISTER_FROM_THREADSTATE(machine_state, pc);
452}
453
454bool MinidumpGenerator::WriteContextARM(breakpad_thread_state_data_t state,
455                                        MDLocationDescriptor *register_location)
456{
457  TypedMDRVA<MDRawContextARM> context(&writer_);
458  arm_thread_state_t *machine_state =
459      reinterpret_cast<arm_thread_state_t *>(state);
460
461  if (!context.Allocate())
462    return false;
463
464  *register_location = context.location();
465  MDRawContextARM *context_ptr = context.get();
466  context_ptr->context_flags = MD_CONTEXT_ARM_FULL;
467
468#define AddGPR(a) context_ptr->iregs[a] = REGISTER_FROM_THREADSTATE(machine_state, r[a])
469
470  context_ptr->iregs[13] = REGISTER_FROM_THREADSTATE(machine_state, sp);
471  context_ptr->iregs[14] = REGISTER_FROM_THREADSTATE(machine_state, lr);
472  context_ptr->iregs[15] = REGISTER_FROM_THREADSTATE(machine_state, pc);
473  context_ptr->cpsr = REGISTER_FROM_THREADSTATE(machine_state, cpsr);
474
475  AddGPR(0);
476  AddGPR(1);
477  AddGPR(2);
478  AddGPR(3);
479  AddGPR(4);
480  AddGPR(5);
481  AddGPR(6);
482  AddGPR(7);
483  AddGPR(8);
484  AddGPR(9);
485  AddGPR(10);
486  AddGPR(11);
487  AddGPR(12);
488#undef AddReg
489#undef AddGPR
490
491  return true;
492}
493#endif
494
495#ifdef HAS_PCC_SUPPORT
496bool MinidumpGenerator::WriteStackPPC(breakpad_thread_state_data_t state,
497                                      MDMemoryDescriptor *stack_location) {
498  ppc_thread_state_t *machine_state =
499      reinterpret_cast<ppc_thread_state_t *>(state);
500  mach_vm_address_t start_addr = REGISTER_FROM_THREADSTATE(machine_state, r1);
501  return WriteStackFromStartAddress(start_addr, stack_location);
502}
503
504bool MinidumpGenerator::WriteStackPPC64(breakpad_thread_state_data_t state,
505                                        MDMemoryDescriptor *stack_location) {
506  ppc_thread_state64_t *machine_state =
507      reinterpret_cast<ppc_thread_state64_t *>(state);
508  mach_vm_address_t start_addr = REGISTER_FROM_THREADSTATE(machine_state, r1);
509  return WriteStackFromStartAddress(start_addr, stack_location);
510}
511
512u_int64_t
513MinidumpGenerator::CurrentPCForStackPPC(breakpad_thread_state_data_t state) {
514  ppc_thread_state_t *machine_state =
515      reinterpret_cast<ppc_thread_state_t *>(state);
516
517  return REGISTER_FROM_THREADSTATE(machine_state, srr0);
518}
519
520u_int64_t
521MinidumpGenerator::CurrentPCForStackPPC64(breakpad_thread_state_data_t state) {
522  ppc_thread_state64_t *machine_state =
523      reinterpret_cast<ppc_thread_state64_t *>(state);
524
525  return REGISTER_FROM_THREADSTATE(machine_state, srr0);
526}
527
528bool MinidumpGenerator::WriteContextPPC(breakpad_thread_state_data_t state,
529                                        MDLocationDescriptor *register_location)
530{
531  TypedMDRVA<MDRawContextPPC> context(&writer_);
532  ppc_thread_state_t *machine_state =
533      reinterpret_cast<ppc_thread_state_t *>(state);
534
535  if (!context.Allocate())
536    return false;
537
538  *register_location = context.location();
539  MDRawContextPPC *context_ptr = context.get();
540  context_ptr->context_flags = MD_CONTEXT_PPC_BASE;
541
542#define AddReg(a) context_ptr->a = REGISTER_FROM_THREADSTATE(machine_state, a)
543#define AddGPR(a) context_ptr->gpr[a] = REGISTER_FROM_THREADSTATE(machine_state, r ## a)
544
545  AddReg(srr0);
546  AddReg(cr);
547  AddReg(xer);
548  AddReg(ctr);
549  AddReg(lr);
550  AddReg(vrsave);
551
552  AddGPR(0);
553  AddGPR(1);
554  AddGPR(2);
555  AddGPR(3);
556  AddGPR(4);
557  AddGPR(5);
558  AddGPR(6);
559  AddGPR(7);
560  AddGPR(8);
561  AddGPR(9);
562  AddGPR(10);
563  AddGPR(11);
564  AddGPR(12);
565  AddGPR(13);
566  AddGPR(14);
567  AddGPR(15);
568  AddGPR(16);
569  AddGPR(17);
570  AddGPR(18);
571  AddGPR(19);
572  AddGPR(20);
573  AddGPR(21);
574  AddGPR(22);
575  AddGPR(23);
576  AddGPR(24);
577  AddGPR(25);
578  AddGPR(26);
579  AddGPR(27);
580  AddGPR(28);
581  AddGPR(29);
582  AddGPR(30);
583  AddGPR(31);
584  AddReg(mq);
585#undef AddReg
586#undef AddGPR
587
588  return true;
589}
590
591bool MinidumpGenerator::WriteContextPPC64(
592    breakpad_thread_state_data_t state,
593    MDLocationDescriptor *register_location) {
594  TypedMDRVA<MDRawContextPPC64> context(&writer_);
595  ppc_thread_state64_t *machine_state =
596      reinterpret_cast<ppc_thread_state64_t *>(state);
597
598  if (!context.Allocate())
599    return false;
600
601  *register_location = context.location();
602  MDRawContextPPC64 *context_ptr = context.get();
603  context_ptr->context_flags = MD_CONTEXT_PPC_BASE;
604
605#define AddReg(a) context_ptr->a = REGISTER_FROM_THREADSTATE(machine_state, a)
606#define AddGPR(a) context_ptr->gpr[a] = REGISTER_FROM_THREADSTATE(machine_state, r ## a)
607
608  AddReg(srr0);
609  AddReg(cr);
610  AddReg(xer);
611  AddReg(ctr);
612  AddReg(lr);
613  AddReg(vrsave);
614
615  AddGPR(0);
616  AddGPR(1);
617  AddGPR(2);
618  AddGPR(3);
619  AddGPR(4);
620  AddGPR(5);
621  AddGPR(6);
622  AddGPR(7);
623  AddGPR(8);
624  AddGPR(9);
625  AddGPR(10);
626  AddGPR(11);
627  AddGPR(12);
628  AddGPR(13);
629  AddGPR(14);
630  AddGPR(15);
631  AddGPR(16);
632  AddGPR(17);
633  AddGPR(18);
634  AddGPR(19);
635  AddGPR(20);
636  AddGPR(21);
637  AddGPR(22);
638  AddGPR(23);
639  AddGPR(24);
640  AddGPR(25);
641  AddGPR(26);
642  AddGPR(27);
643  AddGPR(28);
644  AddGPR(29);
645  AddGPR(30);
646  AddGPR(31);
647#undef AddReg
648#undef AddGPR
649
650  return true;
651}
652
653#endif
654
655#ifdef HAS_X86_SUPPORT
656bool MinidumpGenerator::WriteStackX86(breakpad_thread_state_data_t state,
657                                   MDMemoryDescriptor *stack_location) {
658  i386_thread_state_t *machine_state =
659      reinterpret_cast<i386_thread_state_t *>(state);
660
661  mach_vm_address_t start_addr = REGISTER_FROM_THREADSTATE(machine_state, esp);
662  return WriteStackFromStartAddress(start_addr, stack_location);
663}
664
665bool MinidumpGenerator::WriteStackX86_64(breakpad_thread_state_data_t state,
666                                         MDMemoryDescriptor *stack_location) {
667  x86_thread_state64_t *machine_state =
668      reinterpret_cast<x86_thread_state64_t *>(state);
669
670  mach_vm_address_t start_addr = REGISTER_FROM_THREADSTATE(machine_state, rsp);
671  return WriteStackFromStartAddress(start_addr, stack_location);
672}
673
674u_int64_t
675MinidumpGenerator::CurrentPCForStackX86(breakpad_thread_state_data_t state) {
676  i386_thread_state_t *machine_state =
677      reinterpret_cast<i386_thread_state_t *>(state);
678
679  return REGISTER_FROM_THREADSTATE(machine_state, eip);
680}
681
682u_int64_t
683MinidumpGenerator::CurrentPCForStackX86_64(breakpad_thread_state_data_t state) {
684  x86_thread_state64_t *machine_state =
685      reinterpret_cast<x86_thread_state64_t *>(state);
686
687  return REGISTER_FROM_THREADSTATE(machine_state, rip);
688}
689
690bool MinidumpGenerator::WriteContextX86(breakpad_thread_state_data_t state,
691                                        MDLocationDescriptor *register_location)
692{
693  TypedMDRVA<MDRawContextX86> context(&writer_);
694  i386_thread_state_t *machine_state =
695      reinterpret_cast<i386_thread_state_t *>(state);
696
697  if (!context.Allocate())
698    return false;
699
700  *register_location = context.location();
701  MDRawContextX86 *context_ptr = context.get();
702
703#define AddReg(a) context_ptr->a = REGISTER_FROM_THREADSTATE(machine_state, a)
704
705  context_ptr->context_flags = MD_CONTEXT_X86;
706  AddReg(eax);
707  AddReg(ebx);
708  AddReg(ecx);
709  AddReg(edx);
710  AddReg(esi);
711  AddReg(edi);
712  AddReg(ebp);
713  AddReg(esp);
714
715  AddReg(cs);
716  AddReg(ds);
717  AddReg(ss);
718  AddReg(es);
719  AddReg(fs);
720  AddReg(gs);
721  AddReg(eflags);
722
723  AddReg(eip);
724#undef AddReg
725
726  return true;
727}
728
729bool MinidumpGenerator::WriteContextX86_64(
730    breakpad_thread_state_data_t state,
731    MDLocationDescriptor *register_location) {
732  TypedMDRVA<MDRawContextAMD64> context(&writer_);
733  x86_thread_state64_t *machine_state =
734      reinterpret_cast<x86_thread_state64_t *>(state);
735
736  if (!context.Allocate())
737    return false;
738
739  *register_location = context.location();
740  MDRawContextAMD64 *context_ptr = context.get();
741
742#define AddReg(a) context_ptr->a = REGISTER_FROM_THREADSTATE(machine_state, a)
743
744  context_ptr->context_flags = MD_CONTEXT_AMD64;
745  AddReg(rax);
746  AddReg(rbx);
747  AddReg(rcx);
748  AddReg(rdx);
749  AddReg(rdi);
750  AddReg(rsi);
751  AddReg(rbp);
752  AddReg(rsp);
753  AddReg(r8);
754  AddReg(r9);
755  AddReg(r10);
756  AddReg(r11);
757  AddReg(r12);
758  AddReg(r13);
759  AddReg(r14);
760  AddReg(r15);
761  AddReg(rip);
762  // according to AMD's software developer guide, bits above 18 are
763  // not used in the flags register.  Since the minidump format
764  // specifies 32 bits for the flags register, we can truncate safely
765  // with no loss.
766  context_ptr->eflags = static_cast<u_int32_t>(REGISTER_FROM_THREADSTATE(machine_state, rflags));
767  AddReg(cs);
768  AddReg(fs);
769  AddReg(gs);
770#undef AddReg
771
772  return true;
773}
774#endif
775
776bool MinidumpGenerator::GetThreadState(thread_act_t target_thread,
777                                       thread_state_t state,
778                                       mach_msg_type_number_t *count) {
779  if (task_context_ && target_thread == mach_thread_self()) {
780    switch (cpu_type_) {
781#ifdef HAS_ARM_SUPPORT
782      case CPU_TYPE_ARM: {
783        size_t final_size =
784            std::min(static_cast<size_t>(*count), sizeof(arm_thread_state_t));
785        memcpy(state, &task_context_->uc_mcontext->__ss, final_size);
786        *count = final_size;
787        return true;
788      }
789#endif
790    }
791  }
792  thread_state_flavor_t flavor;
793  switch (cpu_type_) {
794#ifdef HAS_ARM_SUPPORT
795    case CPU_TYPE_ARM:
796      flavor = ARM_THREAD_STATE;
797      break;
798#endif
799#ifdef HAS_PPC_SUPPORT
800    case CPU_TYPE_POWERPC:
801      flavor = PPC_THREAD_STATE;
802      break;
803    case CPU_TYPE_POWERPC64:
804      flavor = PPC_THREAD_STATE64;
805      break;
806#endif
807#ifdef HAS_X86_SUPPORT
808    case CPU_TYPE_I386:
809      flavor = i386_THREAD_STATE;
810      break;
811    case CPU_TYPE_X86_64:
812      flavor = x86_THREAD_STATE64;
813      break;
814#endif
815    default:
816      return false;
817  }
818  return thread_get_state(target_thread, flavor,
819                          state, count) == KERN_SUCCESS;
820}
821
822bool MinidumpGenerator::WriteThreadStream(mach_port_t thread_id,
823                                          MDRawThread *thread) {
824  breakpad_thread_state_data_t state;
825  mach_msg_type_number_t state_count
826      = static_cast<mach_msg_type_number_t>(sizeof(state));
827
828  if (GetThreadState(thread_id, state, &state_count)) {
829    if (!WriteStack(state, &thread->stack))
830      return false;
831
832    memory_blocks_.push_back(thread->stack);
833
834    if (!WriteContext(state, &thread->thread_context))
835      return false;
836
837    thread->thread_id = thread_id;
838  } else {
839    return false;
840  }
841
842  return true;
843}
844
845bool MinidumpGenerator::WriteThreadListStream(
846    MDRawDirectory *thread_list_stream) {
847  TypedMDRVA<MDRawThreadList> list(&writer_);
848  thread_act_port_array_t threads_for_task;
849  mach_msg_type_number_t thread_count;
850  int non_generator_thread_count;
851
852  if (task_threads(crashing_task_, &threads_for_task, &thread_count))
853    return false;
854
855  // Don't include the generator thread
856  if (handler_thread_ != MACH_PORT_NULL)
857    non_generator_thread_count = thread_count - 1;
858  else
859    non_generator_thread_count = thread_count;
860  if (!list.AllocateObjectAndArray(non_generator_thread_count,
861                                   sizeof(MDRawThread)))
862    return false;
863
864  thread_list_stream->stream_type = MD_THREAD_LIST_STREAM;
865  thread_list_stream->location = list.location();
866
867  list.get()->number_of_threads = non_generator_thread_count;
868
869  MDRawThread thread;
870  int thread_idx = 0;
871
872  for (unsigned int i = 0; i < thread_count; ++i) {
873    memset(&thread, 0, sizeof(MDRawThread));
874
875    if (threads_for_task[i] != handler_thread_) {
876      if (!WriteThreadStream(threads_for_task[i], &thread))
877        return false;
878
879      list.CopyIndexAfterObject(thread_idx++, &thread, sizeof(MDRawThread));
880    }
881  }
882
883  return true;
884}
885
886bool MinidumpGenerator::WriteMemoryListStream(
887    MDRawDirectory *memory_list_stream) {
888  TypedMDRVA<MDRawMemoryList> list(&writer_);
889
890  // If the dump has an exception, include some memory around the
891  // instruction pointer.
892  const size_t kIPMemorySize = 256;  // bytes
893  bool have_ip_memory = false;
894  MDMemoryDescriptor ip_memory_d;
895  if (exception_thread_ && exception_type_) {
896    breakpad_thread_state_data_t state;
897    mach_msg_type_number_t stateCount
898      = static_cast<mach_msg_type_number_t>(sizeof(state));
899
900    if (GetThreadState(exception_thread_, state, &stateCount)) {
901      u_int64_t ip = CurrentPCForStack(state);
902      // Bound it to the upper and lower bounds of the region
903      // it's contained within. If it's not in a known memory region,
904      // don't bother trying to write it.
905      mach_vm_address_t addr = static_cast<vm_address_t>(ip);
906      mach_vm_size_t size;
907      natural_t nesting_level = 0;
908      vm_region_submap_info_64 info;
909      mach_msg_type_number_t info_count = VM_REGION_SUBMAP_INFO_COUNT_64;
910      vm_region_recurse_info_t recurse_info;
911      recurse_info = reinterpret_cast<vm_region_recurse_info_t>(&info);
912
913      kern_return_t ret =
914        mach_vm_region_recurse(crashing_task_,
915                               &addr,
916                               &size,
917                               &nesting_level,
918                               recurse_info,
919                               &info_count);
920      if (ret == KERN_SUCCESS && ip >= addr && ip < (addr + size)) {
921        // Try to get 128 bytes before and after the IP, but
922        // settle for whatever's available.
923        ip_memory_d.start_of_memory_range =
924          std::max(uintptr_t(addr),
925                   uintptr_t(ip - (kIPMemorySize / 2)));
926        uintptr_t end_of_range =
927          std::min(uintptr_t(ip + (kIPMemorySize / 2)),
928                   uintptr_t(addr + size));
929        ip_memory_d.memory.data_size =
930            end_of_range -
931            static_cast<uintptr_t>(ip_memory_d.start_of_memory_range);
932        have_ip_memory = true;
933        // This needs to get appended to the list even though
934        // the memory bytes aren't filled in yet so the entire
935        // list can be written first. The memory bytes will get filled
936        // in after the memory list is written.
937        memory_blocks_.push_back(ip_memory_d);
938      }
939    }
940  }
941
942  // Now fill in the memory list and write it.
943  unsigned memory_count = memory_blocks_.size();
944  if (!list.AllocateObjectAndArray(memory_count,
945                                   sizeof(MDMemoryDescriptor)))
946    return false;
947
948  memory_list_stream->stream_type = MD_MEMORY_LIST_STREAM;
949  memory_list_stream->location = list.location();
950
951  list.get()->number_of_memory_ranges = memory_count;
952
953  unsigned int i;
954  for (i = 0; i < memory_count; ++i) {
955    list.CopyIndexAfterObject(i, &memory_blocks_[i],
956                              sizeof(MDMemoryDescriptor));
957  }
958
959  if (have_ip_memory) {
960    // Now read the memory around the instruction pointer.
961    UntypedMDRVA ip_memory(&writer_);
962    if (!ip_memory.Allocate(ip_memory_d.memory.data_size))
963      return false;
964
965    if (dynamic_images_) {
966      // Out-of-process.
967      vector<uint8_t> memory;
968      if (ReadTaskMemory(crashing_task_,
969                         ip_memory_d.start_of_memory_range,
970                         ip_memory_d.memory.data_size,
971                         memory) != KERN_SUCCESS) {
972        return false;
973      }
974
975      ip_memory.Copy(&memory[0], ip_memory_d.memory.data_size);
976    } else {
977      // In-process, just copy from local memory.
978      ip_memory.Copy(
979        reinterpret_cast<const void *>(ip_memory_d.start_of_memory_range),
980        ip_memory_d.memory.data_size);
981    }
982
983    ip_memory_d.memory = ip_memory.location();
984    // Write this again now that the data location is filled in.
985    list.CopyIndexAfterObject(i - 1, &ip_memory_d,
986                              sizeof(MDMemoryDescriptor));
987  }
988
989  return true;
990}
991
992bool
993MinidumpGenerator::WriteExceptionStream(MDRawDirectory *exception_stream) {
994  TypedMDRVA<MDRawExceptionStream> exception(&writer_);
995
996  if (!exception.Allocate())
997    return false;
998
999  exception_stream->stream_type = MD_EXCEPTION_STREAM;
1000  exception_stream->location = exception.location();
1001  MDRawExceptionStream *exception_ptr = exception.get();
1002  exception_ptr->thread_id = exception_thread_;
1003
1004  // This naming is confusing, but it is the proper translation from
1005  // mach naming to minidump naming.
1006  exception_ptr->exception_record.exception_code = exception_type_;
1007  exception_ptr->exception_record.exception_flags = exception_code_;
1008
1009  breakpad_thread_state_data_t state;
1010  mach_msg_type_number_t state_count
1011      = static_cast<mach_msg_type_number_t>(sizeof(state));
1012
1013  if (!GetThreadState(exception_thread_, state, &state_count))
1014    return false;
1015
1016  if (!WriteContext(state, &exception_ptr->thread_context))
1017    return false;
1018
1019  if (exception_type_ == EXC_BAD_ACCESS)
1020    exception_ptr->exception_record.exception_address = exception_subcode_;
1021  else
1022    exception_ptr->exception_record.exception_address = CurrentPCForStack(state);
1023
1024  return true;
1025}
1026
1027bool MinidumpGenerator::WriteSystemInfoStream(
1028    MDRawDirectory *system_info_stream) {
1029  TypedMDRVA<MDRawSystemInfo> info(&writer_);
1030
1031  if (!info.Allocate())
1032    return false;
1033
1034  system_info_stream->stream_type = MD_SYSTEM_INFO_STREAM;
1035  system_info_stream->location = info.location();
1036
1037  // CPU Information
1038  uint32_t number_of_processors;
1039  size_t len = sizeof(number_of_processors);
1040  sysctlbyname("hw.ncpu", &number_of_processors, &len, NULL, 0);
1041  MDRawSystemInfo *info_ptr = info.get();
1042
1043  switch (cpu_type_) {
1044#ifdef HAS_ARM_SUPPORT
1045    case CPU_TYPE_ARM:
1046      info_ptr->processor_architecture = MD_CPU_ARCHITECTURE_ARM;
1047      break;
1048#endif
1049#ifdef HAS_PPC_SUPPORT
1050    case CPU_TYPE_POWERPC:
1051    case CPU_TYPE_POWERPC64:
1052      info_ptr->processor_architecture = MD_CPU_ARCHITECTURE_PPC;
1053      break;
1054#endif
1055#ifdef HAS_X86_SUPPORT
1056    case CPU_TYPE_I386:
1057    case CPU_TYPE_X86_64:
1058      if (cpu_type_ == CPU_TYPE_I386)
1059        info_ptr->processor_architecture = MD_CPU_ARCHITECTURE_X86;
1060      else
1061        info_ptr->processor_architecture = MD_CPU_ARCHITECTURE_AMD64;
1062#ifdef __i386__
1063      // ebx is used for PIC code, so we need
1064      // to preserve it.
1065#define cpuid(op,eax,ebx,ecx,edx)      \
1066  asm ("pushl %%ebx   \n\t"            \
1067       "cpuid         \n\t"            \
1068       "movl %%ebx,%1 \n\t"            \
1069       "popl %%ebx"                    \
1070       : "=a" (eax),                   \
1071         "=g" (ebx),                   \
1072         "=c" (ecx),                   \
1073         "=d" (edx)                    \
1074       : "0" (op))
1075#elif defined(__x86_64__)
1076
1077#define cpuid(op,eax,ebx,ecx,edx)      \
1078  asm ("cpuid         \n\t"            \
1079       : "=a" (eax),                   \
1080         "=b" (ebx),                   \
1081         "=c" (ecx),                   \
1082         "=d" (edx)                    \
1083       : "0" (op))
1084#endif
1085
1086#if defined(__i386__) || defined(__x86_64__)
1087      int unused, unused2;
1088      // get vendor id
1089      cpuid(0, unused, info_ptr->cpu.x86_cpu_info.vendor_id[0],
1090            info_ptr->cpu.x86_cpu_info.vendor_id[2],
1091            info_ptr->cpu.x86_cpu_info.vendor_id[1]);
1092      // get version and feature info
1093      cpuid(1, info_ptr->cpu.x86_cpu_info.version_information, unused, unused2,
1094            info_ptr->cpu.x86_cpu_info.feature_information);
1095
1096      // family
1097      info_ptr->processor_level =
1098        (info_ptr->cpu.x86_cpu_info.version_information & 0xF00) >> 8;
1099      // 0xMMSS (Model, Stepping)
1100      info_ptr->processor_revision =
1101        (info_ptr->cpu.x86_cpu_info.version_information & 0xF) |
1102        ((info_ptr->cpu.x86_cpu_info.version_information & 0xF0) << 4);
1103
1104      // decode extended model info
1105      if (info_ptr->processor_level == 0xF ||
1106          info_ptr->processor_level == 0x6) {
1107        info_ptr->processor_revision |=
1108          ((info_ptr->cpu.x86_cpu_info.version_information & 0xF0000) >> 4);
1109      }
1110
1111      // decode extended family info
1112      if (info_ptr->processor_level == 0xF) {
1113        info_ptr->processor_level +=
1114          ((info_ptr->cpu.x86_cpu_info.version_information & 0xFF00000) >> 20);
1115      }
1116
1117#endif  // __i386__ || __x86_64_
1118      break;
1119#endif  // HAS_X86_SUPPORT
1120    default:
1121      info_ptr->processor_architecture = MD_CPU_ARCHITECTURE_UNKNOWN;
1122      break;
1123  }
1124
1125  info_ptr->number_of_processors = static_cast<uint8_t>(number_of_processors);
1126#if TARGET_OS_IPHONE
1127  info_ptr->platform_id = MD_OS_IOS;
1128#else
1129  info_ptr->platform_id = MD_OS_MAC_OS_X;
1130#endif  // TARGET_OS_IPHONE
1131
1132  MDLocationDescriptor build_string_loc;
1133
1134  if (!writer_.WriteString(build_string_, 0,
1135                           &build_string_loc))
1136    return false;
1137
1138  info_ptr->csd_version_rva = build_string_loc.rva;
1139  info_ptr->major_version = os_major_version_;
1140  info_ptr->minor_version = os_minor_version_;
1141  info_ptr->build_number = os_build_number_;
1142
1143  return true;
1144}
1145
1146bool MinidumpGenerator::WriteModuleStream(unsigned int index,
1147                                          MDRawModule *module) {
1148  if (dynamic_images_) {
1149    // we're in a different process than the crashed process
1150    DynamicImage *image = dynamic_images_->GetImage(index);
1151
1152    if (!image)
1153      return false;
1154
1155    memset(module, 0, sizeof(MDRawModule));
1156
1157    MDLocationDescriptor string_location;
1158
1159    string name = image->GetFilePath();
1160    if (!writer_.WriteString(name.c_str(), 0, &string_location))
1161      return false;
1162
1163    module->base_of_image = image->GetVMAddr() + image->GetVMAddrSlide();
1164    module->size_of_image = static_cast<u_int32_t>(image->GetVMSize());
1165    module->module_name_rva = string_location.rva;
1166
1167    // We'll skip the executable module, because they don't have
1168    // LC_ID_DYLIB load commands, and the crash processing server gets
1169    // version information from the Plist file, anyway.
1170    if (index != static_cast<uint32_t>(FindExecutableModule())) {
1171      module->version_info.signature = MD_VSFIXEDFILEINFO_SIGNATURE;
1172      module->version_info.struct_version |= MD_VSFIXEDFILEINFO_VERSION;
1173      // Convert MAC dylib version format, which is a 32 bit number, to the
1174      // format used by minidump.  The mac format is <16 bits>.<8 bits>.<8 bits>
1175      // so it fits nicely into the windows version with some massaging
1176      // The mapping is:
1177      //    1) upper 16 bits of MAC version go to lower 16 bits of product HI
1178      //    2) Next most significant 8 bits go to upper 16 bits of product LO
1179      //    3) Least significant 8 bits go to lower 16 bits of product LO
1180      uint32_t modVersion = image->GetVersion();
1181      module->version_info.file_version_hi = 0;
1182      module->version_info.file_version_hi = modVersion >> 16;
1183      module->version_info.file_version_lo |= (modVersion & 0xff00)  << 8;
1184      module->version_info.file_version_lo |= (modVersion & 0xff);
1185    }
1186
1187    if (!WriteCVRecord(module, image->GetCPUType(), name.c_str(), false)) {
1188      return false;
1189    }
1190  } else {
1191    // Getting module info in the crashed process
1192    const breakpad_mach_header *header;
1193    header = (breakpad_mach_header*)_dyld_get_image_header(index);
1194    if (!header)
1195      return false;
1196
1197#ifdef __LP64__
1198    assert(header->magic == MH_MAGIC_64);
1199
1200    if(header->magic != MH_MAGIC_64)
1201      return false;
1202#else
1203    assert(header->magic == MH_MAGIC);
1204
1205    if(header->magic != MH_MAGIC)
1206      return false;
1207#endif
1208
1209    int cpu_type = header->cputype;
1210    unsigned long slide = _dyld_get_image_vmaddr_slide(index);
1211    const char* name = _dyld_get_image_name(index);
1212    const struct load_command *cmd =
1213        reinterpret_cast<const struct load_command *>(header + 1);
1214
1215    memset(module, 0, sizeof(MDRawModule));
1216
1217    for (unsigned int i = 0; cmd && (i < header->ncmds); i++) {
1218      if (cmd->cmd == LC_SEGMENT_ARCH) {
1219
1220        const breakpad_mach_segment_command *seg =
1221            reinterpret_cast<const breakpad_mach_segment_command *>(cmd);
1222
1223        if (!strcmp(seg->segname, "__TEXT")) {
1224          MDLocationDescriptor string_location;
1225
1226          if (!writer_.WriteString(name, 0, &string_location))
1227            return false;
1228
1229          module->base_of_image = seg->vmaddr + slide;
1230          module->size_of_image = static_cast<u_int32_t>(seg->vmsize);
1231          module->module_name_rva = string_location.rva;
1232
1233          bool in_memory = false;
1234#if TARGET_OS_IPHONE
1235          in_memory = true;
1236#endif
1237          if (!WriteCVRecord(module, cpu_type, name, in_memory))
1238            return false;
1239
1240          return true;
1241        }
1242      }
1243
1244      cmd = reinterpret_cast<struct load_command*>((char *)cmd + cmd->cmdsize);
1245    }
1246  }
1247
1248  return true;
1249}
1250
1251int MinidumpGenerator::FindExecutableModule() {
1252  if (dynamic_images_) {
1253    int index = dynamic_images_->GetExecutableImageIndex();
1254
1255    if (index >= 0) {
1256      return index;
1257    }
1258  } else {
1259    int image_count = _dyld_image_count();
1260    const struct mach_header *header;
1261
1262    for (int index = 0; index < image_count; ++index) {
1263      header = _dyld_get_image_header(index);
1264
1265      if (header->filetype == MH_EXECUTE)
1266        return index;
1267    }
1268  }
1269
1270  // failed - just use the first image
1271  return 0;
1272}
1273
1274bool MinidumpGenerator::WriteCVRecord(MDRawModule *module, int cpu_type,
1275                                      const char *module_path, bool in_memory) {
1276  TypedMDRVA<MDCVInfoPDB70> cv(&writer_);
1277
1278  // Only return the last path component of the full module path
1279  const char *module_name = strrchr(module_path, '/');
1280
1281  // Increment past the slash
1282  if (module_name)
1283    ++module_name;
1284  else
1285    module_name = "<Unknown>";
1286
1287  size_t module_name_length = strlen(module_name);
1288
1289  if (!cv.AllocateObjectAndArray(module_name_length + 1, sizeof(u_int8_t)))
1290    return false;
1291
1292  if (!cv.CopyIndexAfterObject(0, module_name, module_name_length))
1293    return false;
1294
1295  module->cv_record = cv.location();
1296  MDCVInfoPDB70 *cv_ptr = cv.get();
1297  cv_ptr->cv_signature = MD_CVINFOPDB70_SIGNATURE;
1298  cv_ptr->age = 0;
1299
1300  // Get the module identifier
1301  unsigned char identifier[16];
1302  bool result = false;
1303  if (in_memory) {
1304    MacFileUtilities::MachoID macho(module_path,
1305        reinterpret_cast<void *>(module->base_of_image),
1306        static_cast<size_t>(module->size_of_image));
1307    result = macho.UUIDCommand(cpu_type, identifier);
1308    if (!result)
1309      result = macho.MD5(cpu_type, identifier);
1310  }
1311
1312  if (!result) {
1313     FileID file_id(module_path);
1314     result = file_id.MachoIdentifier(cpu_type, identifier);
1315  }
1316
1317  if (result) {
1318    cv_ptr->signature.data1 =
1319        static_cast<uint32_t>(identifier[0]) << 24 |
1320        static_cast<uint32_t>(identifier[1]) << 16 |
1321        static_cast<uint32_t>(identifier[2]) << 8 |
1322        static_cast<uint32_t>(identifier[3]);
1323    cv_ptr->signature.data2 =
1324        static_cast<uint16_t>(identifier[4] << 8) | identifier[5];
1325    cv_ptr->signature.data3 =
1326        static_cast<uint16_t>(identifier[6] << 8) | identifier[7];
1327    cv_ptr->signature.data4[0] = identifier[8];
1328    cv_ptr->signature.data4[1] = identifier[9];
1329    cv_ptr->signature.data4[2] = identifier[10];
1330    cv_ptr->signature.data4[3] = identifier[11];
1331    cv_ptr->signature.data4[4] = identifier[12];
1332    cv_ptr->signature.data4[5] = identifier[13];
1333    cv_ptr->signature.data4[6] = identifier[14];
1334    cv_ptr->signature.data4[7] = identifier[15];
1335  }
1336
1337  return true;
1338}
1339
1340bool MinidumpGenerator::WriteModuleListStream(
1341    MDRawDirectory *module_list_stream) {
1342  TypedMDRVA<MDRawModuleList> list(&writer_);
1343
1344  size_t image_count = dynamic_images_ ?
1345      static_cast<size_t>(dynamic_images_->GetImageCount()) :
1346      _dyld_image_count();
1347
1348  if (!list.AllocateObjectAndArray(image_count, MD_MODULE_SIZE))
1349    return false;
1350
1351  module_list_stream->stream_type = MD_MODULE_LIST_STREAM;
1352  module_list_stream->location = list.location();
1353  list.get()->number_of_modules = image_count;
1354
1355  // Write out the executable module as the first one
1356  MDRawModule module;
1357  size_t executableIndex = FindExecutableModule();
1358
1359  if (!WriteModuleStream(executableIndex, &module)) {
1360    return false;
1361  }
1362
1363  list.CopyIndexAfterObject(0, &module, MD_MODULE_SIZE);
1364  int destinationIndex = 1;  // Write all other modules after this one
1365
1366  for (size_t i = 0; i < image_count; ++i) {
1367    if (i != executableIndex) {
1368      if (!WriteModuleStream(i, &module)) {
1369        return false;
1370      }
1371
1372      list.CopyIndexAfterObject(destinationIndex++, &module, MD_MODULE_SIZE);
1373    }
1374  }
1375
1376  return true;
1377}
1378
1379bool MinidumpGenerator::WriteMiscInfoStream(MDRawDirectory *misc_info_stream) {
1380  TypedMDRVA<MDRawMiscInfo> info(&writer_);
1381
1382  if (!info.Allocate())
1383    return false;
1384
1385  misc_info_stream->stream_type = MD_MISC_INFO_STREAM;
1386  misc_info_stream->location = info.location();
1387
1388  MDRawMiscInfo *info_ptr = info.get();
1389  info_ptr->size_of_info = static_cast<u_int32_t>(sizeof(MDRawMiscInfo));
1390  info_ptr->flags1 = MD_MISCINFO_FLAGS1_PROCESS_ID |
1391    MD_MISCINFO_FLAGS1_PROCESS_TIMES |
1392    MD_MISCINFO_FLAGS1_PROCESSOR_POWER_INFO;
1393
1394  // Process ID
1395  info_ptr->process_id = getpid();
1396
1397  // Times
1398  struct rusage usage;
1399  if (getrusage(RUSAGE_SELF, &usage) != -1) {
1400    // Omit the fractional time since the MDRawMiscInfo only wants seconds
1401    info_ptr->process_user_time =
1402        static_cast<u_int32_t>(usage.ru_utime.tv_sec);
1403    info_ptr->process_kernel_time =
1404        static_cast<u_int32_t>(usage.ru_stime.tv_sec);
1405  }
1406  int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID,
1407                 static_cast<int>(info_ptr->process_id) };
1408  u_int mibsize = static_cast<u_int>(sizeof(mib) / sizeof(mib[0]));
1409  struct kinfo_proc proc;
1410  size_t size = sizeof(proc);
1411  if (sysctl(mib, mibsize, &proc, &size, NULL, 0) == 0) {
1412    info_ptr->process_create_time =
1413        static_cast<u_int32_t>(proc.kp_proc.p_starttime.tv_sec);
1414  }
1415
1416  // Speed
1417  uint64_t speed;
1418  const uint64_t kOneMillion = 1000 * 1000;
1419  size = sizeof(speed);
1420  sysctlbyname("hw.cpufrequency_max", &speed, &size, NULL, 0);
1421  info_ptr->processor_max_mhz = static_cast<u_int32_t>(speed / kOneMillion);
1422  info_ptr->processor_mhz_limit = static_cast<u_int32_t>(speed / kOneMillion);
1423  size = sizeof(speed);
1424  sysctlbyname("hw.cpufrequency", &speed, &size, NULL, 0);
1425  info_ptr->processor_current_mhz = static_cast<u_int32_t>(speed / kOneMillion);
1426
1427  return true;
1428}
1429
1430bool MinidumpGenerator::WriteBreakpadInfoStream(
1431    MDRawDirectory *breakpad_info_stream) {
1432  TypedMDRVA<MDRawBreakpadInfo> info(&writer_);
1433
1434  if (!info.Allocate())
1435    return false;
1436
1437  breakpad_info_stream->stream_type = MD_BREAKPAD_INFO_STREAM;
1438  breakpad_info_stream->location = info.location();
1439  MDRawBreakpadInfo *info_ptr = info.get();
1440
1441  if (exception_thread_ && exception_type_) {
1442    info_ptr->validity = MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID |
1443                         MD_BREAKPAD_INFO_VALID_REQUESTING_THREAD_ID;
1444    info_ptr->dump_thread_id = handler_thread_;
1445    info_ptr->requesting_thread_id = exception_thread_;
1446  } else {
1447    info_ptr->validity = MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID;
1448    info_ptr->dump_thread_id = handler_thread_;
1449    info_ptr->requesting_thread_id = 0;
1450  }
1451
1452  return true;
1453}
1454
1455}  // namespace google_breakpad
1456