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