minidump_generator.cc revision 60a69eecd7cf717a1819a1f75b4ef21a6b51c457
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      mach_msg_type_number_t 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("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 = 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
911      kern_return_t ret =
912        mach_vm_region_recurse(crashing_task_,
913                               &addr,
914                               &size,
915                               &nesting_level,
916                               (vm_region_recurse_info_t)&info,
917                               &info_count);
918      if (ret == KERN_SUCCESS && ip >= addr && ip < (addr + size)) {
919        // Try to get 128 bytes before and after the IP, but
920        // settle for whatever's available.
921        ip_memory_d.start_of_memory_range =
922          std::max(uintptr_t(addr),
923                   uintptr_t(ip - (kIPMemorySize / 2)));
924        uintptr_t end_of_range =
925          std::min(uintptr_t(ip + (kIPMemorySize / 2)),
926                   uintptr_t(addr + size));
927        ip_memory_d.memory.data_size =
928          end_of_range - ip_memory_d.start_of_memory_range;
929        have_ip_memory = true;
930        // This needs to get appended to the list even though
931        // the memory bytes aren't filled in yet so the entire
932        // list can be written first. The memory bytes will get filled
933        // in after the memory list is written.
934        memory_blocks_.push_back(ip_memory_d);
935      }
936    }
937  }
938
939  // Now fill in the memory list and write it.
940  unsigned memory_count = memory_blocks_.size();
941  if (!list.AllocateObjectAndArray(memory_count,
942                                   sizeof(MDMemoryDescriptor)))
943    return false;
944
945  memory_list_stream->stream_type = MD_MEMORY_LIST_STREAM;
946  memory_list_stream->location = list.location();
947
948  list.get()->number_of_memory_ranges = memory_count;
949
950  unsigned int i;
951  for (i = 0; i < memory_count; ++i) {
952    list.CopyIndexAfterObject(i, &memory_blocks_[i],
953                              sizeof(MDMemoryDescriptor));
954  }
955
956  if (have_ip_memory) {
957    // Now read the memory around the instruction pointer.
958    UntypedMDRVA ip_memory(&writer_);
959    if (!ip_memory.Allocate(ip_memory_d.memory.data_size))
960      return false;
961
962    if (dynamic_images_) {
963      // Out-of-process.
964      vector<uint8_t> memory;
965      if (ReadTaskMemory(crashing_task_,
966                         ip_memory_d.start_of_memory_range,
967                         ip_memory_d.memory.data_size,
968                         memory) != KERN_SUCCESS) {
969        return false;
970      }
971
972      ip_memory.Copy(&memory[0], ip_memory_d.memory.data_size);
973    } else {
974      // In-process, just copy from local memory.
975      ip_memory.Copy(
976        reinterpret_cast<const void *>(ip_memory_d.start_of_memory_range),
977        ip_memory_d.memory.data_size);
978    }
979
980    ip_memory_d.memory = ip_memory.location();
981    // Write this again now that the data location is filled in.
982    list.CopyIndexAfterObject(i - 1, &ip_memory_d,
983                              sizeof(MDMemoryDescriptor));
984  }
985
986  return true;
987}
988
989bool
990MinidumpGenerator::WriteExceptionStream(MDRawDirectory *exception_stream) {
991  TypedMDRVA<MDRawExceptionStream> exception(&writer_);
992
993  if (!exception.Allocate())
994    return false;
995
996  exception_stream->stream_type = MD_EXCEPTION_STREAM;
997  exception_stream->location = exception.location();
998  MDRawExceptionStream *exception_ptr = exception.get();
999  exception_ptr->thread_id = exception_thread_;
1000
1001  // This naming is confusing, but it is the proper translation from
1002  // mach naming to minidump naming.
1003  exception_ptr->exception_record.exception_code = exception_type_;
1004  exception_ptr->exception_record.exception_flags = exception_code_;
1005
1006  breakpad_thread_state_data_t state;
1007  mach_msg_type_number_t state_count
1008      = static_cast<mach_msg_type_number_t>(sizeof(state));
1009
1010  if (!GetThreadState(exception_thread_, state, &state_count))
1011    return false;
1012
1013  if (!WriteContext(state, &exception_ptr->thread_context))
1014    return false;
1015
1016  if (exception_type_ == EXC_BAD_ACCESS)
1017    exception_ptr->exception_record.exception_address = exception_subcode_;
1018  else
1019    exception_ptr->exception_record.exception_address = CurrentPCForStack(state);
1020
1021  return true;
1022}
1023
1024bool MinidumpGenerator::WriteSystemInfoStream(
1025    MDRawDirectory *system_info_stream) {
1026  TypedMDRVA<MDRawSystemInfo> info(&writer_);
1027
1028  if (!info.Allocate())
1029    return false;
1030
1031  system_info_stream->stream_type = MD_SYSTEM_INFO_STREAM;
1032  system_info_stream->location = info.location();
1033
1034  // CPU Information
1035  uint32_t number_of_processors;
1036  size_t len = sizeof(number_of_processors);
1037  sysctlbyname("hw.ncpu", &number_of_processors, &len, NULL, 0);
1038  MDRawSystemInfo *info_ptr = info.get();
1039
1040  switch (cpu_type_) {
1041#ifdef HAS_ARM_SUPPORT
1042    case CPU_TYPE_ARM:
1043      info_ptr->processor_architecture = MD_CPU_ARCHITECTURE_ARM;
1044      break;
1045#endif
1046#ifdef HAS_PPC_SUPPORT
1047    case CPU_TYPE_POWERPC:
1048    case CPU_TYPE_POWERPC64:
1049      info_ptr->processor_architecture = MD_CPU_ARCHITECTURE_PPC;
1050      break;
1051#endif
1052#ifdef HAS_X86_SUPPORT
1053    case CPU_TYPE_I386:
1054    case CPU_TYPE_X86_64:
1055      if (cpu_type_ == CPU_TYPE_I386)
1056        info_ptr->processor_architecture = MD_CPU_ARCHITECTURE_X86;
1057      else
1058        info_ptr->processor_architecture = MD_CPU_ARCHITECTURE_AMD64;
1059#ifdef __i386__
1060      // ebx is used for PIC code, so we need
1061      // to preserve it.
1062#define cpuid(op,eax,ebx,ecx,edx)      \
1063  asm ("pushl %%ebx   \n\t"            \
1064       "cpuid         \n\t"            \
1065       "movl %%ebx,%1 \n\t"            \
1066       "popl %%ebx"                    \
1067       : "=a" (eax),                   \
1068         "=g" (ebx),                   \
1069         "=c" (ecx),                   \
1070         "=d" (edx)                    \
1071       : "0" (op))
1072#elif defined(__x86_64__)
1073
1074#define cpuid(op,eax,ebx,ecx,edx)      \
1075  asm ("cpuid         \n\t"            \
1076       : "=a" (eax),                   \
1077         "=b" (ebx),                   \
1078         "=c" (ecx),                   \
1079         "=d" (edx)                    \
1080       : "0" (op))
1081#endif
1082
1083#if defined(__i386__) || defined(__x86_64__)
1084      int unused, unused2;
1085      // get vendor id
1086      cpuid(0, unused, info_ptr->cpu.x86_cpu_info.vendor_id[0],
1087            info_ptr->cpu.x86_cpu_info.vendor_id[2],
1088            info_ptr->cpu.x86_cpu_info.vendor_id[1]);
1089      // get version and feature info
1090      cpuid(1, info_ptr->cpu.x86_cpu_info.version_information, unused, unused2,
1091            info_ptr->cpu.x86_cpu_info.feature_information);
1092
1093      // family
1094      info_ptr->processor_level =
1095        (info_ptr->cpu.x86_cpu_info.version_information & 0xF00) >> 8;
1096      // 0xMMSS (Model, Stepping)
1097      info_ptr->processor_revision =
1098        (info_ptr->cpu.x86_cpu_info.version_information & 0xF) |
1099        ((info_ptr->cpu.x86_cpu_info.version_information & 0xF0) << 4);
1100
1101      // decode extended model info
1102      if (info_ptr->processor_level == 0xF ||
1103          info_ptr->processor_level == 0x6) {
1104        info_ptr->processor_revision |=
1105          ((info_ptr->cpu.x86_cpu_info.version_information & 0xF0000) >> 4);
1106      }
1107
1108      // decode extended family info
1109      if (info_ptr->processor_level == 0xF) {
1110        info_ptr->processor_level +=
1111          ((info_ptr->cpu.x86_cpu_info.version_information & 0xFF00000) >> 20);
1112      }
1113
1114#endif  // __i386__ || __x86_64_
1115      break;
1116#endif  // HAS_X86_SUPPORT
1117    default:
1118      info_ptr->processor_architecture = MD_CPU_ARCHITECTURE_UNKNOWN;
1119      break;
1120  }
1121
1122  info_ptr->number_of_processors = number_of_processors;
1123#if TARGET_OS_IPHONE
1124  info_ptr->platform_id = MD_OS_IOS;
1125#else
1126  info_ptr->platform_id = MD_OS_MAC_OS_X;
1127#endif  // TARGET_OS_IPHONE
1128
1129  MDLocationDescriptor build_string_loc;
1130
1131  if (!writer_.WriteString(build_string_, 0,
1132                           &build_string_loc))
1133    return false;
1134
1135  info_ptr->csd_version_rva = build_string_loc.rva;
1136  info_ptr->major_version = os_major_version_;
1137  info_ptr->minor_version = os_minor_version_;
1138  info_ptr->build_number = os_build_number_;
1139
1140  return true;
1141}
1142
1143bool MinidumpGenerator::WriteModuleStream(unsigned int index,
1144                                          MDRawModule *module) {
1145  if (dynamic_images_) {
1146    // we're in a different process than the crashed process
1147    DynamicImage *image = dynamic_images_->GetImage(index);
1148
1149    if (!image)
1150      return false;
1151
1152    memset(module, 0, sizeof(MDRawModule));
1153
1154    MDLocationDescriptor string_location;
1155
1156    string name = image->GetFilePath();
1157    if (!writer_.WriteString(name.c_str(), 0, &string_location))
1158      return false;
1159
1160    module->base_of_image = image->GetVMAddr() + image->GetVMAddrSlide();
1161    module->size_of_image = static_cast<u_int32_t>(image->GetVMSize());
1162    module->module_name_rva = string_location.rva;
1163
1164    // We'll skip the executable module, because they don't have
1165    // LC_ID_DYLIB load commands, and the crash processing server gets
1166    // version information from the Plist file, anyway.
1167    if (index != (uint32_t)FindExecutableModule()) {
1168      module->version_info.signature = MD_VSFIXEDFILEINFO_SIGNATURE;
1169      module->version_info.struct_version |= MD_VSFIXEDFILEINFO_VERSION;
1170      // Convert MAC dylib version format, which is a 32 bit number, to the
1171      // format used by minidump.  The mac format is <16 bits>.<8 bits>.<8 bits>
1172      // so it fits nicely into the windows version with some massaging
1173      // The mapping is:
1174      //    1) upper 16 bits of MAC version go to lower 16 bits of product HI
1175      //    2) Next most significant 8 bits go to upper 16 bits of product LO
1176      //    3) Least significant 8 bits go to lower 16 bits of product LO
1177      uint32_t modVersion = image->GetVersion();
1178      module->version_info.file_version_hi = 0;
1179      module->version_info.file_version_hi = modVersion >> 16;
1180      module->version_info.file_version_lo |= (modVersion & 0xff00)  << 8;
1181      module->version_info.file_version_lo |= (modVersion & 0xff);
1182    }
1183
1184    if (!WriteCVRecord(module, image->GetCPUType(), name.c_str(), false)) {
1185      return false;
1186    }
1187  } else {
1188    // Getting module info in the crashed process
1189    const breakpad_mach_header *header;
1190    header = (breakpad_mach_header*)_dyld_get_image_header(index);
1191    if (!header)
1192      return false;
1193
1194#ifdef __LP64__
1195    assert(header->magic == MH_MAGIC_64);
1196
1197    if(header->magic != MH_MAGIC_64)
1198      return false;
1199#else
1200    assert(header->magic == MH_MAGIC);
1201
1202    if(header->magic != MH_MAGIC)
1203      return false;
1204#endif
1205
1206    int cpu_type = header->cputype;
1207    unsigned long slide = _dyld_get_image_vmaddr_slide(index);
1208    const char* name = _dyld_get_image_name(index);
1209    const struct load_command *cmd =
1210        reinterpret_cast<const struct load_command *>(header + 1);
1211
1212    memset(module, 0, sizeof(MDRawModule));
1213
1214    for (unsigned int i = 0; cmd && (i < header->ncmds); i++) {
1215      if (cmd->cmd == LC_SEGMENT_ARCH) {
1216
1217        const breakpad_mach_segment_command *seg =
1218            reinterpret_cast<const breakpad_mach_segment_command *>(cmd);
1219
1220        if (!strcmp(seg->segname, "__TEXT")) {
1221          MDLocationDescriptor string_location;
1222
1223          if (!writer_.WriteString(name, 0, &string_location))
1224            return false;
1225
1226          module->base_of_image = seg->vmaddr + slide;
1227          module->size_of_image = static_cast<u_int32_t>(seg->vmsize);
1228          module->module_name_rva = string_location.rva;
1229
1230          bool in_memory = false;
1231#if TARGET_OS_IPHONE
1232          in_memory = true;
1233#endif
1234          if (!WriteCVRecord(module, cpu_type, name, in_memory))
1235            return false;
1236
1237          return true;
1238        }
1239      }
1240
1241      cmd = reinterpret_cast<struct load_command*>((char *)cmd + cmd->cmdsize);
1242    }
1243  }
1244
1245  return true;
1246}
1247
1248int MinidumpGenerator::FindExecutableModule() {
1249  if (dynamic_images_) {
1250    int index = dynamic_images_->GetExecutableImageIndex();
1251
1252    if (index >= 0) {
1253      return index;
1254    }
1255  } else {
1256    int image_count = _dyld_image_count();
1257    const struct mach_header *header;
1258
1259    for (int index = 0; index < image_count; ++index) {
1260      header = _dyld_get_image_header(index);
1261
1262      if (header->filetype == MH_EXECUTE)
1263        return index;
1264    }
1265  }
1266
1267  // failed - just use the first image
1268  return 0;
1269}
1270
1271bool MinidumpGenerator::WriteCVRecord(MDRawModule *module, int cpu_type,
1272                                      const char *module_path, bool in_memory) {
1273  TypedMDRVA<MDCVInfoPDB70> cv(&writer_);
1274
1275  // Only return the last path component of the full module path
1276  const char *module_name = strrchr(module_path, '/');
1277
1278  // Increment past the slash
1279  if (module_name)
1280    ++module_name;
1281  else
1282    module_name = "<Unknown>";
1283
1284  size_t module_name_length = strlen(module_name);
1285
1286  if (!cv.AllocateObjectAndArray(module_name_length + 1, sizeof(u_int8_t)))
1287    return false;
1288
1289  if (!cv.CopyIndexAfterObject(0, module_name, module_name_length))
1290    return false;
1291
1292  module->cv_record = cv.location();
1293  MDCVInfoPDB70 *cv_ptr = cv.get();
1294  cv_ptr->cv_signature = MD_CVINFOPDB70_SIGNATURE;
1295  cv_ptr->age = 0;
1296
1297  // Get the module identifier
1298  unsigned char identifier[16];
1299  bool result = false;
1300  if (in_memory) {
1301    MacFileUtilities::MachoID macho(module_path,
1302        reinterpret_cast<void *>(module->base_of_image),
1303        static_cast<size_t>(module->size_of_image));
1304    result = macho.UUIDCommand(cpu_type, identifier);
1305    if (!result)
1306      result = macho.MD5(cpu_type, identifier);
1307  }
1308
1309  if (!result) {
1310     FileID file_id(module_path);
1311     result = file_id.MachoIdentifier(cpu_type, identifier);
1312  }
1313
1314  if (result) {
1315    cv_ptr->signature.data1 = (uint32_t)identifier[0] << 24 |
1316      (uint32_t)identifier[1] << 16 | (uint32_t)identifier[2] << 8 |
1317      (uint32_t)identifier[3];
1318    cv_ptr->signature.data2 = (uint32_t)identifier[4] << 8 | identifier[5];
1319    cv_ptr->signature.data3 = (uint32_t)identifier[6] << 8 | identifier[7];
1320    cv_ptr->signature.data4[0] = identifier[8];
1321    cv_ptr->signature.data4[1] = identifier[9];
1322    cv_ptr->signature.data4[2] = identifier[10];
1323    cv_ptr->signature.data4[3] = identifier[11];
1324    cv_ptr->signature.data4[4] = identifier[12];
1325    cv_ptr->signature.data4[5] = identifier[13];
1326    cv_ptr->signature.data4[6] = identifier[14];
1327    cv_ptr->signature.data4[7] = identifier[15];
1328  }
1329
1330  return true;
1331}
1332
1333bool MinidumpGenerator::WriteModuleListStream(
1334    MDRawDirectory *module_list_stream) {
1335  TypedMDRVA<MDRawModuleList> list(&writer_);
1336
1337  size_t image_count = dynamic_images_ ?
1338      static_cast<size_t>(dynamic_images_->GetImageCount()) :
1339      _dyld_image_count();
1340
1341  if (!list.AllocateObjectAndArray(image_count, MD_MODULE_SIZE))
1342    return false;
1343
1344  module_list_stream->stream_type = MD_MODULE_LIST_STREAM;
1345  module_list_stream->location = list.location();
1346  list.get()->number_of_modules = image_count;
1347
1348  // Write out the executable module as the first one
1349  MDRawModule module;
1350  size_t executableIndex = FindExecutableModule();
1351
1352  if (!WriteModuleStream(executableIndex, &module)) {
1353    return false;
1354  }
1355
1356  list.CopyIndexAfterObject(0, &module, MD_MODULE_SIZE);
1357  int destinationIndex = 1;  // Write all other modules after this one
1358
1359  for (size_t i = 0; i < image_count; ++i) {
1360    if (i != executableIndex) {
1361      if (!WriteModuleStream(i, &module)) {
1362        return false;
1363      }
1364
1365      list.CopyIndexAfterObject(destinationIndex++, &module, MD_MODULE_SIZE);
1366    }
1367  }
1368
1369  return true;
1370}
1371
1372bool MinidumpGenerator::WriteMiscInfoStream(MDRawDirectory *misc_info_stream) {
1373  TypedMDRVA<MDRawMiscInfo> info(&writer_);
1374
1375  if (!info.Allocate())
1376    return false;
1377
1378  misc_info_stream->stream_type = MD_MISC_INFO_STREAM;
1379  misc_info_stream->location = info.location();
1380
1381  MDRawMiscInfo *info_ptr = info.get();
1382  info_ptr->size_of_info = static_cast<u_int32_t>(sizeof(MDRawMiscInfo));
1383  info_ptr->flags1 = MD_MISCINFO_FLAGS1_PROCESS_ID |
1384    MD_MISCINFO_FLAGS1_PROCESS_TIMES |
1385    MD_MISCINFO_FLAGS1_PROCESSOR_POWER_INFO;
1386
1387  // Process ID
1388  info_ptr->process_id = getpid();
1389
1390  // Times
1391  struct rusage usage;
1392  if (getrusage(RUSAGE_SELF, &usage) != -1) {
1393    // Omit the fractional time since the MDRawMiscInfo only wants seconds
1394    info_ptr->process_user_time =
1395        static_cast<u_int32_t>(usage.ru_utime.tv_sec);
1396    info_ptr->process_kernel_time =
1397        static_cast<u_int32_t>(usage.ru_stime.tv_sec);
1398  }
1399  int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID,
1400                 static_cast<int>(info_ptr->process_id) };
1401  u_int mibsize = static_cast<u_int>(sizeof(mib) / sizeof(mib[0]));
1402  struct kinfo_proc proc;
1403  size_t size = sizeof(proc);
1404  if (sysctl(mib, mibsize, &proc, &size, NULL, 0) == 0) {
1405    info_ptr->process_create_time =
1406        static_cast<u_int32_t>(proc.kp_proc.p_starttime.tv_sec);
1407  }
1408
1409  // Speed
1410  uint64_t speed;
1411  const uint64_t kOneMillion = 1000 * 1000;
1412  size = sizeof(speed);
1413  sysctlbyname("hw.cpufrequency_max", &speed, &size, NULL, 0);
1414  info_ptr->processor_max_mhz = static_cast<u_int32_t>(speed / kOneMillion);
1415  info_ptr->processor_mhz_limit = static_cast<u_int32_t>(speed / kOneMillion);
1416  size = sizeof(speed);
1417  sysctlbyname("hw.cpufrequency", &speed, &size, NULL, 0);
1418  info_ptr->processor_current_mhz = static_cast<u_int32_t>(speed / kOneMillion);
1419
1420  return true;
1421}
1422
1423bool MinidumpGenerator::WriteBreakpadInfoStream(
1424    MDRawDirectory *breakpad_info_stream) {
1425  TypedMDRVA<MDRawBreakpadInfo> info(&writer_);
1426
1427  if (!info.Allocate())
1428    return false;
1429
1430  breakpad_info_stream->stream_type = MD_BREAKPAD_INFO_STREAM;
1431  breakpad_info_stream->location = info.location();
1432  MDRawBreakpadInfo *info_ptr = info.get();
1433
1434  if (exception_thread_ && exception_type_) {
1435    info_ptr->validity = MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID |
1436                         MD_BREAKPAD_INFO_VALID_REQUESTING_THREAD_ID;
1437    info_ptr->dump_thread_id = handler_thread_;
1438    info_ptr->requesting_thread_id = exception_thread_;
1439  } else {
1440    info_ptr->validity = MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID;
1441    info_ptr->dump_thread_id = handler_thread_;
1442    info_ptr->requesting_thread_id = 0;
1443  }
1444
1445  return true;
1446}
1447
1448}  // namespace google_breakpad
1449