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