PageRenderTime 106ms CodeModel.GetById 11ms app.highlight 85ms RepoModel.GetById 1ms app.codeStats 0ms

/thirdparty/breakpad/client/mac/handler/minidump_generator.cc

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