bug 379518 - sync up with breakpad svn, to revision 157. r=mento
authorted.mielczarek@gmail.com
Sun, 06 May 2007 18:03:38 -0700
changeset 1178 619f2ad903142758ff3fb38415c42cbb1edc7000
parent 1177 8be991856f13e1c9731a83b2e6c8cede1c94d514
child 1179 27203acce24242a2ae16d1c512901ce105988a6c
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmento
bugs379518
milestone1.9a5pre
bug 379518 - sync up with breakpad svn, to revision 157. r=mento
toolkit/airbag/airbag/src/client/mac/handler/Makefile.in
toolkit/airbag/airbag/src/client/mac/handler/dynamic_images.cc
toolkit/airbag/airbag/src/client/mac/handler/dynamic_images.h
toolkit/airbag/airbag/src/client/mac/handler/exception_handler.cc
toolkit/airbag/airbag/src/client/mac/handler/exception_handler.h
toolkit/airbag/airbag/src/client/mac/handler/minidump_generator.cc
toolkit/airbag/airbag/src/client/mac/handler/minidump_generator.h
toolkit/airbag/airbag/src/client/windows/handler/exception_handler.cc
toolkit/airbag/airbag/src/common/linux/dump_symbols.cc
toolkit/airbag/airbag/src/common/linux/dump_symbols.h
toolkit/airbag/airbag/src/common/linux/file_id.cc
toolkit/airbag/airbag/src/common/linux/md5.c
toolkit/airbag/airbag/src/common/linux/md5.h
toolkit/airbag/airbag/src/common/mac/Makefile.in
toolkit/airbag/airbag/src/common/mac/dump_syms.h
toolkit/airbag/airbag/src/common/mac/dump_syms.mm
toolkit/airbag/airbag/src/common/mac/macho_id.cc
toolkit/airbag/airbag/src/common/mac/macho_utilities.cc
toolkit/airbag/airbag/src/common/mac/macho_utilities.h
toolkit/airbag/airbag/src/common/mac/macho_walker.cc
toolkit/airbag/airbag/src/common/windows/guid_string.cc
toolkit/airbag/airbag/src/common/windows/http_upload.cc
toolkit/airbag/airbag/src/common/windows/pdb_source_line_writer.cc
toolkit/airbag/airbag/src/common/windows/string_utils-inl.h
toolkit/airbag/airbag/src/google_breakpad/processor/stackwalker.h
toolkit/airbag/airbag/src/processor/stackwalker.cc
toolkit/airbag/airbag/src/processor/stackwalker_x86.cc
toolkit/airbag/airbag/src/tools/linux/dump_syms/dump_syms.cc
toolkit/airbag/airbag/src/tools/linux/symupload/sym_upload.cc
toolkit/airbag/airbag/src/tools/mac/crash_report/crash_report.xcodeproj/project.pbxproj
toolkit/airbag/airbag/src/tools/mac/dump_syms/dump_syms.xcodeproj/project.pbxproj
toolkit/airbag/airbag/src/tools/mac/dump_syms/dump_syms_tool.m
toolkit/airbag/airbag/src/tools/mac/symupload/symupload.xcodeproj/project.pbxproj
toolkit/airbag/airbag/src/tools/windows/symupload/symupload.cc
--- a/toolkit/airbag/airbag/src/client/mac/handler/Makefile.in
+++ b/toolkit/airbag/airbag/src/client/mac/handler/Makefile.in
@@ -42,18 +42,19 @@ VPATH		= @srcdir@
 include $(DEPTH)/config/autoconf.mk
 
 MODULE		= handler
 LIBRARY_NAME	= exception_handler_s
 XPI_NAME 	= crashreporter
 
 LOCAL_INCLUDES 	= -I$(srcdir)/../../..
 
-CPPSRCS		= \
-		exception_handler.cc \
-		minidump_generator.cc \
-		../../minidump_file_writer.cc \
-		$(NULL)
+CPPSRCS	= \
+  exception_handler.cc \
+  minidump_generator.cc \
+  dynamic_images.cc \
+  ../../minidump_file_writer.cc \
+  $(NULL)
 
 # need static lib
 FORCE_STATIC_LIB = 1
 
 include $(topsrcdir)/config/rules.mk
new file mode 100644
--- /dev/null
+++ b/toolkit/airbag/airbag/src/client/mac/handler/dynamic_images.cc
@@ -0,0 +1,239 @@
+// Copyright (c) 2007, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <mach-o/nlist.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <algorithm>
+
+#include "client/mac/handler/dynamic_images.h"
+
+namespace google_breakpad {
+
+//==============================================================================
+// Reads an address range from another task.  A block of memory is malloced
+// and should be freed by the caller.
+void* ReadTaskMemory(task_port_t target_task,
+                     const void* address,
+                     size_t length) {
+  void* result = NULL;
+  mach_vm_address_t page_address = (uint32_t)address & (-4096);
+  mach_vm_address_t last_page_address =
+    ((uint32_t)address + length + 4095) & (-4096);
+  mach_vm_size_t page_size = last_page_address - page_address;
+  uint8_t* local_start;
+  uint32_t local_length;
+
+  kern_return_t r = vm_read(target_task,
+                            page_address,
+                            page_size,
+                            reinterpret_cast<vm_offset_t*>(&local_start),
+                            &local_length);
+
+  if (r == KERN_SUCCESS) {
+    result = malloc(length);
+    if (result != NULL) {
+      memcpy(result, &local_start[(uint32_t)address - page_address], length);
+    }
+    vm_deallocate(mach_task_self(), (uintptr_t)local_start, local_length);
+  }
+
+  return result;
+}
+
+#pragma mark -
+
+//==============================================================================
+// Initializes vmaddr_, vmsize_, and slide_
+void DynamicImage::CalculateMemoryInfo() {
+  mach_header *header = GetMachHeader();
+
+  const struct load_command *cmd =
+    reinterpret_cast<const struct load_command *>(header + 1);
+
+  for (unsigned int i = 0; cmd && (i < header->ncmds); ++i) {
+    if (cmd->cmd == LC_SEGMENT) {
+      const struct segment_command *seg =
+        reinterpret_cast<const struct segment_command *>(cmd);
+
+      if (!strcmp(seg->segname, "__TEXT")) {
+        vmaddr_ = seg->vmaddr;
+        vmsize_ = seg->vmsize;
+        slide_ = 0;
+        
+        if (seg->fileoff == 0  &&  seg->filesize != 0) {
+          slide_ = (uintptr_t)GetLoadAddress() - (uintptr_t)seg->vmaddr;
+        }
+        return;
+      }
+    }
+
+    cmd = reinterpret_cast<const struct load_command *>
+      (reinterpret_cast<const char *>(cmd) + cmd->cmdsize);
+  }
+  
+  // we failed - a call to IsValid() will return false
+  vmaddr_ = 0;
+  vmsize_ = 0;
+  slide_ = 0;
+}
+
+#pragma mark -
+
+//==============================================================================
+// Loads information about dynamically loaded code in the given task.
+DynamicImages::DynamicImages(mach_port_t task)
+  : task_(task) {
+  ReadImageInfoForTask();
+}
+
+//==============================================================================
+// This code was written using dyld_debug.c (from Darwin) as a guide.
+void DynamicImages::ReadImageInfoForTask() {
+  struct nlist l[8];
+  memset(l, 0, sizeof(l) );
+  
+  // First we lookup the address of the "_dyld_all_image_infos" struct
+  // which lives in "dyld".  This structure contains information about all
+  // of the loaded dynamic images.
+  struct nlist &list = l[0];
+  list.n_un.n_name = "_dyld_all_image_infos";
+  nlist("/usr/lib/dyld", &list);
+  
+  if (list.n_value) {
+    // Read the structure inside of dyld that contains information about
+    // loaded images.  We're reading from the desired task's address space.
+
+    // Here we make the assumption that dyld loaded at the same address in
+    // the crashed process vs. this one.  This is an assumption made in
+    // "dyld_debug.c" and is said to be nearly always valid.
+    dyld_all_image_infos *dyldInfo = reinterpret_cast<dyld_all_image_infos*>
+      (ReadTaskMemory(task_,
+                      reinterpret_cast<void*>(list.n_value),
+                      sizeof(dyld_all_image_infos)));
+
+    if (dyldInfo) {
+      // number of loaded images
+      int count = dyldInfo->infoArrayCount;
+
+      // Read an array of dyld_image_info structures each containing
+      // information about a loaded image.
+      dyld_image_info *infoArray = reinterpret_cast<dyld_image_info*>
+        (ReadTaskMemory(task_,
+                        dyldInfo->infoArray,
+                        count*sizeof(dyld_image_info)));
+
+      image_list_.reserve(count);
+      
+      for (int i = 0; i < count; ++i) {
+        dyld_image_info &info = infoArray[i];
+
+        // First read just the mach_header from the image in the task.
+        mach_header *header = reinterpret_cast<mach_header*>
+          (ReadTaskMemory(task_, info.load_address_, sizeof(mach_header)));
+
+        if (!header)
+          break;   // bail on this dynamic image
+        
+        // Now determine the total amount we really want to read based on the
+        // size of the load commands.  We need the header plus all of the 
+        // load commands.
+        unsigned int header_size = sizeof(mach_header) + header->sizeofcmds;
+        free(header);
+
+        header = reinterpret_cast<mach_header*>
+          (ReadTaskMemory(task_, info.load_address_, header_size));
+        
+        // Read the file name from the task's memory space.
+        char *file_path = NULL;
+        if (info.file_path_) {
+          // Although we're reading 0x2000 bytes, this is copied in the
+          // the DynamicImage constructor below with the correct string length,
+          // so it's not really wasting memory.
+          file_path = reinterpret_cast<char*>
+            (ReadTaskMemory(task_,
+                            info.file_path_,
+                            0x2000));
+        }
+        
+        // Create an object representing this image and add it to our list.
+        DynamicImage *new_image = new DynamicImage(header,
+                                                   header_size,
+                                                   info.load_address_,
+                                                   file_path,
+                                                   info.file_mod_date_,
+                                                   task_);
+
+        if (new_image->IsValid()) {
+          image_list_.push_back(DynamicImageRef(new_image));
+        } else {
+          delete new_image;
+        }
+        
+        if (file_path) {
+          free(file_path);
+        }
+      }
+      
+      free(dyldInfo);
+      free(infoArray);
+      
+      // sorts based on loading address
+      sort(image_list_.begin(), image_list_.end() );
+    }
+  }
+}
+
+//==============================================================================
+DynamicImage  *DynamicImages::GetExecutableImage() {
+  int executable_index = GetExecutableImageIndex();
+  
+  if (executable_index >= 0) {
+    return GetImage(executable_index);
+  }
+  
+  return NULL;
+}
+
+//==============================================================================
+// returns -1 if failure to find executable
+int DynamicImages::GetExecutableImageIndex() {
+  int image_count = GetImageCount();
+
+  for (int i = 0; i < image_count; ++i) {
+    DynamicImage  *image = GetImage(i);
+    if (image->GetMachHeader()->filetype == MH_EXECUTE) {
+      return i;
+    }
+  }
+
+  return -1;
+}
+
+}  // namespace google_breakpad
new file mode 100644
--- /dev/null
+++ b/toolkit/airbag/airbag/src/client/mac/handler/dynamic_images.h
@@ -0,0 +1,303 @@
+// Copyright (c) 2007, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+//  dynamic_images.h
+//
+//    Implements most of the function of the dyld API, but allowing an
+//    arbitrary task to be introspected, unlike the dyld API which
+//    only allows operation on the current task.  The current implementation
+//    is limited to use by 32-bit tasks.
+
+#ifndef CLIENT_MAC_HANDLER_DYNAMIC_IMAGES_H__
+#define CLIENT_MAC_HANDLER_DYNAMIC_IMAGES_H__
+
+#include <mach/mach.h>
+#include <mach-o/dyld.h>
+#include <mach-o/loader.h>
+#include <sys/types.h>
+#include <vector>
+
+namespace google_breakpad {
+
+using std::vector;
+
+//==============================================================================
+// The memory layout of this struct matches the dyld_image_info struct
+// defined in "dyld_gdb.h" in the darwin source.
+typedef struct dyld_image_info {
+  struct mach_header        *load_address_;
+  char                      *file_path_;
+  uintptr_t                 file_mod_date_;
+} dyld_image_info;
+
+//==============================================================================
+// This is as defined in "dyld_gdb.h" in the darwin source.
+// _dyld_all_image_infos (in dyld) is a structure of this type
+// which will be used to determine which dynamic code has been loaded.
+typedef struct dyld_all_image_infos {
+  uint32_t                      version;  // == 1 in Mac OS X 10.4
+  uint32_t                      infoArrayCount;
+  const struct dyld_image_info  *infoArray;
+  void*                         notification;
+  bool                          processDetachedFromSharedRegion;
+} dyld_all_image_infos;
+
+//==============================================================================
+// A simple wrapper for a mach_header
+//
+// This could be fleshed out with some more interesting methods.
+class MachHeader {
+ public:
+  explicit MachHeader(const mach_header &header) : header_(header) {}
+
+  void Print() {
+    printf("magic\t\t: %4x\n", header_.magic);
+    printf("cputype\t\t: %d\n", header_.cputype);
+    printf("cpusubtype\t: %d\n", header_.cpusubtype);
+    printf("filetype\t: %d\n", header_.filetype);
+    printf("ncmds\t\t: %d\n", header_.ncmds);
+    printf("sizeofcmds\t: %d\n", header_.sizeofcmds);
+    printf("flags\t\t: %d\n", header_.flags);
+  }
+
+  mach_header   header_;
+};
+
+//==============================================================================
+// Represents a single dynamically loaded mach-o image
+class DynamicImage {
+ public:
+  DynamicImage(mach_header *header,       // we take ownership
+               int header_size,           // includes load commands
+               mach_header *load_address,
+               char *inFilePath,
+               uintptr_t image_mod_date,
+               mach_port_t task)
+    : header_(header),
+      header_size_(header_size),
+      load_address_(load_address),
+      file_mod_date_(image_mod_date),
+      task_(task) {
+    InitializeFilePath(inFilePath);
+    CalculateMemoryInfo();
+  }
+
+  ~DynamicImage() {
+    if (file_path_) {
+      free(file_path_);
+    }
+    free(header_);
+  }
+
+  // Returns pointer to a local copy of the mach_header plus load commands
+  mach_header *GetMachHeader() {return header_;}
+
+  // Size of mach_header plus load commands
+  int GetHeaderSize() const {return header_size_;}
+
+  // Full path to mach-o binary
+  char *GetFilePath() {return file_path_;}
+
+  uintptr_t GetModDate() const {return file_mod_date_;}
+
+  // Actual address where the image was loaded
+  mach_header *GetLoadAddress() const {return load_address_;}
+
+  // Address where the image should be loaded
+  uint32_t GetVMAddr() const {return vmaddr_;}
+
+  // Difference between GetLoadAddress() and GetVMAddr()
+  ptrdiff_t GetVMAddrSlide() const {return slide_;}
+
+  // Size of the image
+  uint32_t GetVMSize() const {return vmsize_;}
+
+  // Task owning this loaded image
+  mach_port_t GetTask() {return task_;}
+
+  // For sorting
+  bool operator<(const DynamicImage &inInfo) {
+    return GetLoadAddress() < inInfo.GetLoadAddress();
+  }
+
+  // Debugging
+  void Print() {
+    char *path = GetFilePath();
+    if (!path) {
+      path = "(unknown)";
+    }
+    printf("%p: %s\n", GetLoadAddress(), path);
+    mach_header *header = GetMachHeader();
+    MachHeader(*header).Print();
+    printf("vmaddr\t\t: %p\n", reinterpret_cast<void*>(GetVMAddr()));
+    printf("vmsize\t\t: %d\n", GetVMSize());
+    printf("slide\t\t: %d\n", GetVMAddrSlide());
+  }
+
+ private:
+  friend class DynamicImages;
+
+  // Sanity checking
+  bool IsValid() {return GetVMAddr() != 0;}
+
+  // Makes local copy of file path to mach-o binary
+  void InitializeFilePath(char *inFilePath) {
+    if (inFilePath) {
+      file_path_ = reinterpret_cast<char*>(malloc(strlen(inFilePath)));
+      strcpy(file_path_, inFilePath);
+    } else {
+      file_path_ = NULL;
+    }
+  }
+
+  // Initializes vmaddr_, vmsize_, and slide_
+  void CalculateMemoryInfo();
+
+#if 0   // currently not needed
+  // Copy constructor: we don't want this to be invoked,
+  // but here's the code in case we need to make it public some day.
+  DynamicImage(DynamicImage &inInfo)
+    : load_address_(inInfo.load_address_),
+      vmaddr_(inInfo.vmaddr_),
+      vmsize_(inInfo.vmsize_),
+      slide_(inInfo.slide_),
+      file_mod_date_(inInfo.file_mod_date_),
+      task_(inInfo.task_) {
+    // copy file path string
+    InitializeFilePath(inInfo.GetFilePath());
+
+    // copy mach_header and load commands
+    header_ = reinterpret_cast<mach_header*>(malloc(inInfo.header_size_));
+    memcpy(header_, inInfo.header_, inInfo.header_size_);
+    header_size_ = inInfo.header_size_;
+  }
+#endif
+
+  mach_header          *header_;        // our local copy of the header
+  int                   header_size_;    // mach_header plus load commands
+  mach_header          *load_address_;  // base address image is mapped into
+  uint32_t             vmaddr_;
+  uint32_t             vmsize_;
+  ptrdiff_t            slide_;
+
+  char                 *file_path_;     // path dyld used to load the image
+  uintptr_t            file_mod_date_;  // time_t of image file
+
+  mach_port_t          task_;
+};
+
+//==============================================================================
+// DynamicImageRef is just a simple wrapper for a pointer to
+// DynamicImage.  The reason we use it instead of a simple typedef is so
+// that we can use stl::sort() on a vector of DynamicImageRefs
+// and simple class pointers can't implement operator<().
+//
+class DynamicImageRef {
+ public:
+  explicit DynamicImageRef(DynamicImage *inP) : p(inP) {}
+  DynamicImageRef(const DynamicImageRef &inRef) : p(inRef.p) {}  // STL required
+
+  bool operator<(const DynamicImageRef &inRef) const {
+    return (*const_cast<DynamicImageRef*>(this)->p)
+      < (*const_cast<DynamicImageRef&>(inRef).p);
+  }
+
+  // Be just like DynamicImage*
+  DynamicImage  *operator->() {return p;}
+  operator DynamicImage*() {return p;}
+
+ private:
+  DynamicImage  *p;
+};
+
+//==============================================================================
+// An object of type DynamicImages may be created to allow introspection of
+// an arbitrary task's dynamically loaded mach-o binaries.  This makes the
+// assumption that the current task has send rights to the target task.
+class DynamicImages {
+ public:
+  explicit DynamicImages(mach_port_t task);
+
+  ~DynamicImages() {
+    for (int i = 0; i < (int)image_list_.size(); ++i) {
+      delete image_list_[i];
+    }
+  }
+
+  // Returns the number of dynamically loaded mach-o images.
+  int GetImageCount() const {return image_list_.size();}
+
+  // Returns an individual image.
+  DynamicImage *GetImage(int i) {
+    if (i < (int)image_list_.size()) {
+      return image_list_[i];
+    }
+    return NULL;
+  }
+
+  // Returns the image corresponding to the main executable.
+  DynamicImage *GetExecutableImage();
+  int GetExecutableImageIndex();
+
+  // Returns the task which we're looking at.
+  mach_port_t GetTask() const {return task_;}
+
+  // Debugging
+  void Print() {
+    for (int i = 0; i < (int)image_list_.size(); ++i) {
+      image_list_[i]->Print();
+    }
+  }
+
+  void TestPrint() {
+    for (int i = 0; i < (int)image_list_.size(); ++i) {
+      printf("dyld: %p: name = %s\n", _dyld_get_image_header(i),
+        _dyld_get_image_name(i) );
+      const mach_header *header = _dyld_get_image_header(i);
+      MachHeader(*header).Print();
+    }
+  }
+
+ private:
+  bool IsOurTask() {return task_ == mach_task_self();}
+
+  // Initialization
+  void ReadImageInfoForTask();
+
+  mach_port_t              task_;
+  vector<DynamicImageRef>  image_list_;
+};
+
+// Returns a malloced block containing the contents of memory at a particular
+// location in another task.
+void* ReadTaskMemory(task_port_t target_task, const void* address, size_t len);
+
+}   // namespace google_breakpad
+
+#endif // CLIENT_MAC_HANDLER_DYNAMIC_IMAGES_H__
--- a/toolkit/airbag/airbag/src/client/mac/handler/exception_handler.cc
+++ b/toolkit/airbag/airbag/src/client/mac/handler/exception_handler.cc
@@ -27,16 +27,17 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include <map>
 #include <pthread.h>
 
 #include "client/mac/handler/exception_handler.h"
 #include "client/mac/handler/minidump_generator.h"
+#include "common/mac/macho_utilities.h"
 
 namespace google_breakpad {
 
 using std::map;
 
 // These structures and techniques are illustrated in
 // Mac OS X Internals, Amit Singh, ch 9.7
 struct ExceptionMessage {
@@ -128,29 +129,51 @@ ExceptionHandler::ExceptionHandler(const
                                    FilterCallback filter,
                                    MinidumpCallback callback,
                                    void *callback_context,
                                    bool install_handler)
     : dump_path_(),
       filter_(filter),
       callback_(callback),
       callback_context_(callback_context),
+      directCallback_(NULL),
       handler_thread_(NULL),
       handler_port_(0),
       previous_(NULL),
       installed_exception_handler_(false),
       is_in_teardown_(false),
       last_minidump_write_result_(false),
       use_minidump_write_mutex_(false) {
   // This will update to the ID and C-string pointers
   set_dump_path(dump_path);
   MinidumpGenerator::GatherSystemInformation();
   Setup(install_handler);
 }
 
+// special constructor if we want to bypass minidump writing and
+// simply get a callback with the exception information
+ExceptionHandler::ExceptionHandler(DirectCallback callback,
+                                   void *callback_context,
+                                   bool install_handler)
+    : dump_path_(),
+      filter_(NULL),
+      callback_(NULL),
+      callback_context_(callback_context),
+      directCallback_(callback),
+      handler_thread_(NULL),
+      handler_port_(0),
+      previous_(NULL),
+      installed_exception_handler_(false),
+      is_in_teardown_(false),
+      last_minidump_write_result_(false),
+      use_minidump_write_mutex_(false) {
+  MinidumpGenerator::GatherSystemInformation();
+  Setup(install_handler);
+}
+
 ExceptionHandler::~ExceptionHandler() {
   Teardown();
 }
 
 bool ExceptionHandler::WriteMinidump() {
   // If we're currently writing, just return
   if (use_minidump_write_mutex_)
     return false;
@@ -181,46 +204,57 @@ bool ExceptionHandler::WriteMinidump(con
   ExceptionHandler handler(dump_path, NULL, callback, callback_context, false);
   return handler.WriteMinidump();
 }
 
 bool ExceptionHandler::WriteMinidumpWithException(int exception_type,
                                                   int exception_code,
                                                   mach_port_t thread_name) {
   bool result = false;
-  string minidump_id;
 
-  // Putting the MinidumpGenerator in its own context will ensure that the
-  // destructor is executed, closing the newly created minidump file.
-  if (!dump_path_.empty()) {
-    MinidumpGenerator md;
-    if (exception_type && exception_code) {
-      // If this is a real exception, give the filter (if any) a chance to
-      // decided if this should be sent
-      if (filter_ && !filter_(callback_context_))
-        return false;
-
-      md.SetExceptionInformation(exception_type, exception_code, thread_name);
-    }
-
-    result = md.Write(next_minidump_path_c_);
-  }
-
-  // Call user specified callback (if any)
-  if (callback_) {
-    // If the user callback returned true and we're handling an exception
-    // (rather than just writing out the file), then we should exit without
-    // forwarding the exception to the next handler.
-    if (callback_(dump_path_c_, next_minidump_id_c_, callback_context_, 
-                  result)) {
+  if (directCallback_) {
+    if (directCallback_(callback_context_,
+                        exception_type,
+                        exception_code,
+                        thread_name) ) {
       if (exception_type && exception_code)
         exit(exception_type);
     }
+  } else {
+    string minidump_id;
+
+    // Putting the MinidumpGenerator in its own context will ensure that the
+    // destructor is executed, closing the newly created minidump file.
+    if (!dump_path_.empty()) {
+      MinidumpGenerator md;
+      if (exception_type && exception_code) {
+        // If this is a real exception, give the filter (if any) a chance to
+        // decided if this should be sent
+        if (filter_ && !filter_(callback_context_))
+          return false;
+
+        md.SetExceptionInformation(exception_type, exception_code, thread_name);
+      }
+
+      result = md.Write(next_minidump_path_c_);
+    }
+
+    // Call user specified callback (if any)
+    if (callback_) {
+      // If the user callback returned true and we're handling an exception
+      // (rather than just writing out the file), then we should exit without
+      // forwarding the exception to the next handler.
+      if (callback_(dump_path_c_, next_minidump_id_c_, callback_context_, 
+                    result)) {
+        if (exception_type && exception_code)
+          exit(exception_type);
+      }
+    }
   }
-
+  
   return result;
 }
 
 kern_return_t ForwardException(mach_port_t task, mach_port_t failed_thread,
                                exception_type_t exception,
                                exception_data_t code,
                                mach_msg_type_number_t code_count) {
   // At this time, we should have called Uninstall() on the exception handler
@@ -252,17 +286,17 @@ kern_return_t ForwardException(mach_port
     exit(KERN_FAILURE);
   }
 
   mach_port_t target_port = current.ports[found];
   exception_behavior_t target_behavior = current.behaviors[found];
   thread_state_flavor_t target_flavor = current.flavors[found];
 
   mach_msg_type_number_t thread_state_count = THREAD_STATE_MAX;
-  thread_state_data_t thread_state;
+  breakpad_thread_state_data_t thread_state;
   switch (target_behavior) {
     case EXCEPTION_DEFAULT:
       result = exception_raise(target_port, failed_thread, task, exception,
                                code, code_count);
       break;
 
     case EXCEPTION_STATE:
       result = thread_get_state(failed_thread, target_flavor, thread_state,
@@ -321,46 +355,47 @@ void *ExceptionHandler::WaitForMessage(v
   // Wait for the exception info
   while (1) {
     receive.header.msgh_local_port = self->handler_port_;
     receive.header.msgh_size = sizeof(receive);
     kern_return_t result = mach_msg(&(receive.header),
                                     MACH_RCV_MSG | MACH_RCV_LARGE, 0,
                                     sizeof(receive), self->handler_port_,
                                     MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
-
     if (result == KERN_SUCCESS) {
       // Uninstall our handler so that we don't get in a loop if the process of
       // writing out a minidump causes an exception.  However, if the exception
       // was caused by a fork'd process, don't uninstall things
       if (receive.task.name == mach_task_self())
-        self->UninstallHandler();
-      
       // If the actual exception code is zero, then we're calling this handler
       // in a way that indicates that we want to either exit this thread or
       // generate a minidump
       //
       // While reporting, all threads (except this one) must be suspended
       // to avoid misleading stacks.  If appropriate they will be resumed
       // afterwards.
       if (!receive.exception) {
+        self->UninstallHandler(false);
+      
         if (self->is_in_teardown_)
           return NULL;
 
         self->SuspendThreads();
 
         // Write out the dump and save the result for later retrieval
         self->last_minidump_write_result_ =
           self->WriteMinidumpWithException(0, 0, 0);
 
         self->ResumeThreads();
 
         if (self->use_minidump_write_mutex_)
           pthread_mutex_unlock(&self->minidump_write_mutex_);
       } else {
+        self->UninstallHandler(true);
+
         // When forking a child process with the exception handler installed,
         // if the child crashes, it will send the exception back to the parent
         // process.  The check for task == self_task() ensures that only 
         // exceptions that occur in the parent process are caught and 
         // processed.
         if (receive.task.name == mach_task_self()) {
           self->SuspendThreads();
           
@@ -414,33 +449,37 @@ bool ExceptionHandler::InstallHandler() 
                                       handler_port_, EXCEPTION_DEFAULT,
                                       THREAD_STATE_NONE);
 
   installed_exception_handler_ = (result == KERN_SUCCESS);
 
   return installed_exception_handler_;
 }
 
-bool ExceptionHandler::UninstallHandler() {
+bool ExceptionHandler::UninstallHandler(bool in_exception) {
   kern_return_t result = KERN_SUCCESS;
   
   if (installed_exception_handler_) {
     mach_port_t current_task = mach_task_self();
     
     // Restore the previous ports
     for (unsigned int i = 0; i < previous_->count; ++i) {
        result = task_set_exception_ports(current_task, previous_->masks[i],
                                         previous_->ports[i],
                                         previous_->behaviors[i],
                                         previous_->flavors[i]);
       if (result != KERN_SUCCESS)
         return false;
     }
     
-    delete previous_;
+    // this delete should NOT happen if an exception just occurred!
+    if (!in_exception) {
+      delete previous_; 
+    }
+    
     previous_ = NULL;
     installed_exception_handler_ = false;
   }
   
   return result == KERN_SUCCESS;
 }
 
 bool ExceptionHandler::Setup(bool install_handler) {
@@ -474,17 +513,17 @@ bool ExceptionHandler::Setup(bool instal
 
   return result == KERN_SUCCESS ? true : false;
 }
 
 bool ExceptionHandler::Teardown() {
   kern_return_t result = KERN_SUCCESS;
   is_in_teardown_ = true;
 
-  if (!UninstallHandler())
+  if (!UninstallHandler(false))
     return false;
   
   // Send an empty message so that the handler_thread exits
   if (SendEmptyMachMessage()) {
     mach_port_t current_task = mach_task_self();
     result = mach_port_deallocate(current_task, handler_port_);
     if (result != KERN_SUCCESS)
       return false;
--- a/toolkit/airbag/airbag/src/client/mac/handler/exception_handler.h
+++ b/toolkit/airbag/airbag/src/client/mac/handler/exception_handler.h
@@ -66,25 +66,40 @@ class ExceptionHandler {
   // |succeeded| indicates whether a minidump file was successfully written.
   // Return true if the exception was fully handled and breakpad should exit.
   // Return false to allow any other exception handlers to process the 
   // exception.
   typedef bool (*MinidumpCallback)(const char *dump_dir,
                                    const char *minidump_id,
                                    void *context, bool succeeded);
 
+  // A callback function which will be called directly if an exception occurs.
+  // This bypasses the minidump file writing and simply gives the client
+  // the exception information.
+  typedef bool (*DirectCallback)( void *context,
+                                  int exception_type,
+                                  int exception_code,
+                                  mach_port_t thread_name);
+
   // Creates a new ExceptionHandler instance to handle writing minidumps.
   // Minidump files will be written to dump_path, and the optional callback
   // is called after writing the dump file, as described above.
   // If install_handler is true, then a minidump will be written whenever
   // an unhandled exception occurs.  If it is false, minidumps will only
   // be written when WriteMinidump is called.
   ExceptionHandler(const string &dump_path, 
                    FilterCallback filter, MinidumpCallback callback,
                    void *callback_context, bool install_handler);
+
+  // A special constructor if we want to bypass minidump writing and
+  // simply get a callback with the exception information.
+  ExceptionHandler(DirectCallback callback,
+                   void *callback_context,
+                   bool install_handler);
+
   ~ExceptionHandler();
 
   // Get and set the minidump path.
   string dump_path() const { return dump_path_; }
   void set_dump_path(const string &dump_path) {
     dump_path_ = dump_path;
     dump_path_c_ = dump_path_.c_str();
     UpdateNextID();  // Necessary to put dump_path_ in next_minidump_path_.
@@ -99,17 +114,17 @@ class ExceptionHandler {
   static bool WriteMinidump(const string &dump_path, MinidumpCallback callback,
                             void *callback_context);
 
  private:
   // Install the mach exception handler
   bool InstallHandler();
 
   // Uninstall the mach exception handler (if any)
-  bool UninstallHandler();
+  bool UninstallHandler(bool in_exception);
       
   // Setup the handler thread, and if |install_handler| is true, install the
   // mach exception port handler
   bool Setup(bool install_handler);
     
   // Uninstall the mach exception handler (if any) and terminate the helper
   // thread
   bool Teardown();
@@ -154,16 +169,20 @@ class ExceptionHandler {
   const char *next_minidump_path_c_;
 
   // The callback function and pointer to be passed back after the minidump
   // has been written
   FilterCallback filter_;
   MinidumpCallback callback_;
   void *callback_context_;
 
+  // The callback function to be passed back when we don't want a minidump
+  // file to be written
+  DirectCallback directCallback_;
+
   // The thread that is created for the handler
   pthread_t handler_thread_;
 
   // The port that is waiting on an exception message to be sent, if the
   // handler is installed
   mach_port_t handler_port_;
 
   // These variables save the previous exception handler's data so that it
--- a/toolkit/airbag/airbag/src/client/mac/handler/minidump_generator.cc
+++ b/toolkit/airbag/airbag/src/client/mac/handler/minidump_generator.cc
@@ -29,33 +29,48 @@
 
 #include <cstdio>
 
 #include <mach/host_info.h>
 #include <mach/vm_statistics.h>
 #include <mach-o/dyld.h>
 #include <mach-o/loader.h>
 #include <sys/sysctl.h>
+#include <sys/resource.h>
 
 #include <CoreFoundation/CoreFoundation.h>
 
 #include "client/mac/handler/minidump_generator.h"
 #include "client/minidump_file_writer-inl.h"
 #include "common/mac/file_id.h"
 #include "common/mac/string_utilities.h"
 
 using MacStringUtils::ConvertToString;
 using MacStringUtils::IntegerValueAtIndex;
 
 namespace google_breakpad {
   
 MinidumpGenerator::MinidumpGenerator()
     : exception_type_(0),
       exception_code_(0),
-      exception_thread_(0) {
+      exception_thread_(0),
+      crashing_task_(mach_task_self()),
+      handler_thread_(mach_thread_self()) {
+  dynamic_images_ = new DynamicImages(mach_task_self());
+  GatherSystemInformation();
+}
+
+MinidumpGenerator::MinidumpGenerator(mach_port_t crashing_task, mach_port_t handler_thread)
+    : exception_type_(0),
+      exception_code_(0),
+      exception_thread_(0),
+      crashing_task_(crashing_task),
+      handler_thread_(handler_thread) {
+  dynamic_images_ = new DynamicImages(crashing_task_);
+  GatherSystemInformation();
 }
 
 MinidumpGenerator::~MinidumpGenerator() {
 }
 
 char MinidumpGenerator::build_string_[16];
 int MinidumpGenerator::os_major_version_ = 0;
 int MinidumpGenerator::os_minor_version_ = 0;
@@ -179,24 +194,24 @@ bool MinidumpGenerator::Write(const char
       if (result)
         dir.CopyIndex(i, &local_dir);
     }
   }
 
   return result;
 }
 
-static size_t CalculateStackSize(vm_address_t start_addr) {
+size_t MinidumpGenerator::CalculateStackSize(vm_address_t start_addr) {
   vm_address_t stack_region_base = start_addr;
   vm_size_t stack_region_size;
   natural_t nesting_level = 0;
   vm_region_submap_info submap_info;
   mach_msg_type_number_t info_count = VM_REGION_SUBMAP_INFO_COUNT;
   kern_return_t result = 
-    vm_region_recurse(mach_task_self(), &stack_region_base, &stack_region_size,
+    vm_region_recurse(crashing_task_, &stack_region_base, &stack_region_size,
                       &nesting_level, 
                       reinterpret_cast<vm_region_recurse_info_t>(&submap_info),
                       &info_count);
 
   if ((stack_region_base + stack_region_size) == 0xbffff000) {
     // The stack for thread 0 needs to extend all the way to 0xc0000000
     // For many processes the stack is first created in one page
     // from 0xbffff000 - 0xc0000000 and is then later extended to
@@ -220,40 +235,46 @@ bool MinidumpGenerator::WriteStackFromSt
   // If there's an error in the calculation, return at least the current
   // stack information
   if (size == 0)
     size = 16;
 
   if (!memory.Allocate(size))
     return false;
 
-  bool result = memory.Copy(reinterpret_cast<const void *>(start_addr), size);
+  void *stack_memory = ReadTaskMemory(crashing_task_, (void*)start_addr, size);
+
+  bool result = memory.Copy(stack_memory, size);
+  
+  free(stack_memory);
+  
+  
   stack_location->start_of_memory_range = start_addr;
   stack_location->memory = memory.location();
 
   return result;
 }
 
 #if TARGET_CPU_PPC
-bool MinidumpGenerator::WriteStack(thread_state_data_t state,
+bool MinidumpGenerator::WriteStack(breakpad_thread_state_data_t state,
                                    MDMemoryDescriptor *stack_location) {
   ppc_thread_state_t *machine_state =
     reinterpret_cast<ppc_thread_state_t *>(state);
   vm_address_t start_addr = machine_state->r1;
   return WriteStackFromStartAddress(start_addr, stack_location);
 }
 
-u_int64_t MinidumpGenerator::CurrentPCForStack(thread_state_data_t state) {
+u_int64_t MinidumpGenerator::CurrentPCForStack(breakpad_thread_state_data_t state) {
   ppc_thread_state_t *machine_state =
     reinterpret_cast<ppc_thread_state_t *>(state);
 
   return machine_state->srr0;
 }
 
-bool MinidumpGenerator::WriteContext(thread_state_data_t state,
+bool MinidumpGenerator::WriteContext(breakpad_thread_state_data_t state,
                                      MDLocationDescriptor *register_location) {
   TypedMDRVA<MDRawContextPPC> context(&writer_);
   ppc_thread_state_t *machine_state =
     reinterpret_cast<ppc_thread_state_t *>(state);
 
   if (!context.Allocate())
     return false;
 
@@ -302,32 +323,32 @@ bool MinidumpGenerator::WriteContext(thr
   AddGPR(28);
   AddGPR(29);
   AddGPR(30);
   AddGPR(31);
   return true;
 }
 
 #elif TARGET_CPU_X86
-bool MinidumpGenerator::WriteStack(thread_state_data_t state,
+bool MinidumpGenerator::WriteStack(breakpad_thread_state_data_t state,
                                    MDMemoryDescriptor *stack_location) {
   x86_thread_state_t *machine_state =
     reinterpret_cast<x86_thread_state_t *>(state);
   vm_address_t start_addr = machine_state->uts.ts32.esp;
   return WriteStackFromStartAddress(start_addr, stack_location);
 }
 
-u_int64_t MinidumpGenerator::CurrentPCForStack(thread_state_data_t state) {
+u_int64_t MinidumpGenerator::CurrentPCForStack(breakpad_thread_state_data_t state) {
   x86_thread_state_t *machine_state =
     reinterpret_cast<x86_thread_state_t *>(state);
 
   return machine_state->uts.ts32.eip;
 }
 
-bool MinidumpGenerator::WriteContext(thread_state_data_t state,
+bool MinidumpGenerator::WriteContext(breakpad_thread_state_data_t state,
                                      MDLocationDescriptor *register_location) {
   TypedMDRVA<MDRawContextX86> context(&writer_);
   x86_thread_state_t *machine_state =
     reinterpret_cast<x86_thread_state_t *>(state);
 
   if (!context.Allocate())
     return false;
 
@@ -353,17 +374,17 @@ bool MinidumpGenerator::WriteContext(thr
   AddReg(ebp);
   AddReg(esp);
   return true;
 }
 #endif
 
 bool MinidumpGenerator::WriteThreadStream(mach_port_t thread_id,
                                           MDRawThread *thread) {
-  thread_state_data_t state;
+  breakpad_thread_state_data_t state;
   mach_msg_type_number_t state_count = sizeof(state);
 
   if (thread_get_state(thread_id, MACHINE_THREAD_STATE, state, &state_count) ==
       KERN_SUCCESS) {
     if (!WriteStack(state, &thread->stack))
       return false;
 
     if (!WriteContext(state, &thread->thread_context))
@@ -379,17 +400,17 @@ bool MinidumpGenerator::WriteThreadStrea
 
 bool MinidumpGenerator::WriteThreadListStream(
     MDRawDirectory *thread_list_stream) {
   TypedMDRVA<MDRawThreadList> list(&writer_);
   thread_act_port_array_t threads_for_task;
   mach_msg_type_number_t thread_count;
   int non_generator_thread_count;
 
-  if (task_threads(mach_task_self(), &threads_for_task, &thread_count))
+  if (task_threads(crashing_task_, &threads_for_task, &thread_count))
     return false;
 
   // Don't include the generator thread
   non_generator_thread_count = thread_count - 1;
   if (!list.AllocateObjectAndArray(non_generator_thread_count,
                                    sizeof(MDRawThread)))
     return false;
 
@@ -399,17 +420,17 @@ bool MinidumpGenerator::WriteThreadListS
   list.get()->number_of_threads = non_generator_thread_count;
 
   MDRawThread thread;
   int thread_idx = 0;
 
   for (unsigned int i = 0; i < thread_count; ++i) {
     memset(&thread, 0, sizeof(MDRawThread));
 
-    if (threads_for_task[i] != mach_thread_self()) {
+    if (threads_for_task[i] != handler_thread_) {
       if (!WriteThreadStream(threads_for_task[i], &thread))
         return false;
 
       list.CopyIndexAfterObject(thread_idx++, &thread, sizeof(MDRawThread));
     }
   }
 
   return true;
@@ -426,17 +447,17 @@ bool MinidumpGenerator::WriteExceptionSt
   MDRawExceptionStream *exception_ptr = exception.get();
   exception_ptr->thread_id = exception_thread_;
 
   // This naming is confusing, but it is the proper translation from
   // mach naming to minidump naming.
   exception_ptr->exception_record.exception_code = exception_type_;
   exception_ptr->exception_record.exception_flags = exception_code_;
 
-  thread_state_data_t state;
+  breakpad_thread_state_data_t state;
   mach_msg_type_number_t stateCount = sizeof(state);
 
   if (thread_get_state(exception_thread_, MACHINE_THREAD_STATE, state,
                        &stateCount) != KERN_SUCCESS)
     return false;
 
   if (!WriteContext(state, &exception_ptr->thread_context))
     return false;
@@ -491,67 +512,55 @@ bool MinidumpGenerator::WriteSystemInfoS
   info_ptr->minor_version = os_minor_version_;
   info_ptr->build_number = os_build_number_;
 
   return true;
 }
 
 bool MinidumpGenerator::WriteModuleStream(unsigned int index,
                                           MDRawModule *module) {
-  const struct mach_header *header = _dyld_get_image_header(index);
+  DynamicImage *image = dynamic_images_->GetImage(index);
+
+  if (!image)
+    return false;
+
+  const mach_header *header = image->GetMachHeader();
 
   if (!header)
     return false;
 
   int cpu_type = header->cputype;
-  unsigned long slide = _dyld_get_image_vmaddr_slide(index);
-  const char* name = _dyld_get_image_name(index);
-  const struct load_command *cmd =
-    reinterpret_cast<const struct load_command *>(header + 1);
 
   memset(module, 0, sizeof(MDRawModule));
 
-  for (unsigned int i = 0; cmd && (i < header->ncmds); i++) {
-    if (cmd->cmd == LC_SEGMENT) {
-      const struct segment_command *seg =
-        reinterpret_cast<const struct segment_command *>(cmd);
-      if (!strcmp(seg->segname, "__TEXT")) {
-        MDLocationDescriptor string_location;
+  MDLocationDescriptor string_location;
 
-        if (!writer_.WriteString(name, 0, &string_location))
-          return false;
+  const char* name = image->GetFilePath();
+  if (!writer_.WriteString(name, 0, &string_location))
+    return false;
 
-        module->base_of_image = seg->vmaddr + slide;
-        module->size_of_image = seg->vmsize;
-        module->module_name_rva = string_location.rva;
+  module->base_of_image = image->GetVMAddr() + image->GetVMAddrSlide();
+  module->size_of_image = image->GetVMSize();
+  module->module_name_rva = string_location.rva;
 
-        if (!WriteCVRecord(module, cpu_type, name))
-          return false;
-
-        return true;
-      }
-    }
-
-    cmd = reinterpret_cast<struct load_command *>((char *)cmd + cmd->cmdsize);
+  if (!WriteCVRecord(module, cpu_type, name)) {
+    return false;
   }
 
   return true;
 }
 
-static int FindExecutableModule() {
-  int image_count = _dyld_image_count();
-  const struct mach_header *header;
+int MinidumpGenerator::FindExecutableModule() {
+  int index = dynamic_images_->GetExecutableImageIndex();
 
-  for (int i = 0; i < image_count; ++i) {
-    header = _dyld_get_image_header(i);
-
-    if (header->filetype == MH_EXECUTE)
-      return i;
+  if (index >= 0) {
+    return index;
   }
-
+  
+  // failed - just use the first image
   return 0;
 }
 
 bool MinidumpGenerator::WriteCVRecord(MDRawModule *module, int cpu_type,
                                       const char *module_path) {
   TypedMDRVA<MDCVInfoPDB70> cv(&writer_);
 
   // Only return the last path component of the full module path
@@ -601,39 +610,41 @@ bool MinidumpGenerator::WriteCVRecord(MD
 
 bool MinidumpGenerator::WriteModuleListStream(
     MDRawDirectory *module_list_stream) {
   TypedMDRVA<MDRawModuleList> list(&writer_);
 
   if (!_dyld_present())
     return false;
 
-  int image_count = _dyld_image_count();
+  int image_count = dynamic_images_->GetImageCount();
 
   if (!list.AllocateObjectAndArray(image_count, MD_MODULE_SIZE))
     return false;
 
   module_list_stream->stream_type = MD_MODULE_LIST_STREAM;
   module_list_stream->location = list.location();
   list.get()->number_of_modules = image_count;
 
   // Write out the executable module as the first one
   MDRawModule module;
   int executableIndex = FindExecutableModule();
 
-  if (!WriteModuleStream(executableIndex, &module))
+  if (!WriteModuleStream(executableIndex, &module)) {
     return false;
+  }
 
   list.CopyIndexAfterObject(0, &module, MD_MODULE_SIZE);
   int destinationIndex = 1;  // Write all other modules after this one
 
   for (int i = 0; i < image_count; ++i) {
     if (i != executableIndex) {
-      if (!WriteModuleStream(i, &module))
+      if (!WriteModuleStream(i, &module)) {
         return false;
+      }
 
       list.CopyIndexAfterObject(destinationIndex++, &module, MD_MODULE_SIZE);
     }
   }
 
   return true;
 }
 
@@ -696,20 +707,20 @@ bool MinidumpGenerator::WriteBreakpadInf
 
   breakpad_info_stream->stream_type = MD_BREAKPAD_INFO_STREAM;
   breakpad_info_stream->location = info.location();
   MDRawBreakpadInfo *info_ptr = info.get();
 
   if (exception_thread_ && exception_type_) {
     info_ptr->validity = MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID |
                          MD_BREAKPAD_INFO_VALID_REQUESTING_THREAD_ID;
-    info_ptr->dump_thread_id = mach_thread_self();
+    info_ptr->dump_thread_id = handler_thread_;
     info_ptr->requesting_thread_id = exception_thread_;
   } else {
     info_ptr->validity = MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID;
-    info_ptr->dump_thread_id = mach_thread_self();
+    info_ptr->dump_thread_id = handler_thread_;
     info_ptr->requesting_thread_id = 0;
   }
 
   return true;
 }
 
 }  // namespace google_breakpad
--- a/toolkit/airbag/airbag/src/client/mac/handler/minidump_generator.h
+++ b/toolkit/airbag/airbag/src/client/mac/handler/minidump_generator.h
@@ -33,31 +33,36 @@
 #define CLIENT_MAC_GENERATOR_MINIDUMP_GENERATOR_H__
 
 #include <mach/mach.h>
 
 #include <string>
 
 #include "client/minidump_file_writer.h"
 #include "google_breakpad/common/minidump_format.h"
+#include "common/mac/macho_utilities.h"
+
+#include "dynamic_images.h"
 
 namespace google_breakpad {
 
 using std::string;
 
 // Creates a minidump file of the current process.  If there is exception data,
 // use SetExceptionInformation() to add this to the minidump.  The minidump
 // file is generated by the Write() function.
 // Usage:
 // MinidumpGenerator minidump();
 // minidump.Write("/tmp/minidump");
 //
 class MinidumpGenerator {
  public:
   MinidumpGenerator();
+  MinidumpGenerator(mach_port_t crashing_task, mach_port_t handler_thread);
+
   ~MinidumpGenerator();
 
   // Return <dir>/<unique_name>.dmp
   // Sets |unique_name| (if requested) to the unique name for the minidump
   static string UniqueNameInDirectory(const string &dir, string *unique_name);
 
   // Write out the minidump into |path|
   // All of the components of |path| must exist and be writable
@@ -82,42 +87,49 @@ class MinidumpGenerator {
   bool WriteThreadListStream(MDRawDirectory *thread_list_stream);
   bool WriteExceptionStream(MDRawDirectory *exception_stream);
   bool WriteSystemInfoStream(MDRawDirectory *system_info_stream);
   bool WriteModuleListStream(MDRawDirectory *module_list_stream);
   bool WriteMiscInfoStream(MDRawDirectory *misc_info_stream);
   bool WriteBreakpadInfoStream(MDRawDirectory *breakpad_info_stream);
 
   // Helpers
-  u_int64_t CurrentPCForStack(thread_state_data_t state);
+  u_int64_t CurrentPCForStack(breakpad_thread_state_data_t state);
   bool WriteStackFromStartAddress(vm_address_t start_addr,
                                   MDMemoryDescriptor *stack_location);
-  bool WriteStack(thread_state_data_t state,
+  bool WriteStack(breakpad_thread_state_data_t state,
                   MDMemoryDescriptor *stack_location);
-  bool WriteContext(thread_state_data_t state,
+  bool WriteContext(breakpad_thread_state_data_t state,
                     MDLocationDescriptor *register_location);
   bool WriteThreadStream(mach_port_t thread_id, MDRawThread *thread);
   bool WriteCVRecord(MDRawModule *module, int cpu_type, 
                      const char *module_path);
   bool WriteModuleStream(unsigned int index, MDRawModule *module);
+  size_t CalculateStackSize(vm_address_t start_addr);
+  int  FindExecutableModule();
 
   // disallow copy ctor and operator=
   explicit MinidumpGenerator(const MinidumpGenerator &);
   void operator=(const MinidumpGenerator &);
 
   // Use this writer to put the data to disk
   MinidumpFileWriter writer_;
 
   // Exception information
   int exception_type_;
   int exception_code_;
   mach_port_t exception_thread_;
-
+  mach_port_t crashing_task_;
+  mach_port_t handler_thread_;
+  
   // System information
   static char build_string_[16];
   static int os_major_version_;
   static int os_minor_version_;
   static int os_build_number_;
+  
+  // Information about dynamically loaded code
+  DynamicImages *dynamic_images_;
 };
 
 }  // namespace google_breakpad
 
 #endif  // CLIENT_MAC_GENERATOR_MINIDUMP_GENERATOR_H__
--- a/toolkit/airbag/airbag/src/client/windows/handler/exception_handler.cc
+++ b/toolkit/airbag/airbag/src/client/windows/handler/exception_handler.cc
@@ -472,14 +472,17 @@ void ExceptionHandler::UpdateNextID() {
   GUID id;
   CoCreateGuid(&id);
   next_minidump_id_ = GUIDString::GUIDToWString(&id);
   next_minidump_id_c_ = next_minidump_id_.c_str();
 
   wchar_t minidump_path[MAX_PATH];
   swprintf(minidump_path, MAX_PATH, L"%s\\%s.dmp",
            dump_path_c_, next_minidump_id_c_);
-  GB_WSU_SAFE_SWPRINTF_TERMINATE(minidump_path, MAX_PATH);
+
+  // remove when VC++7.1 is no longer supported
+  minidump_path[MAX_PATH - 1] = L'\0';
+
   next_minidump_path_ = minidump_path;
   next_minidump_path_c_ = next_minidump_path_.c_str();
 }
 
 }  // namespace google_breakpad
--- a/toolkit/airbag/airbag/src/common/linux/dump_symbols.cc
+++ b/toolkit/airbag/airbag/src/common/linux/dump_symbols.cc
@@ -488,17 +488,17 @@ bool WriteModuleInfo(int fd, ElfW(Half) 
       if (identifier_str[i] != '-')
         id_no_dash[id_no_dash_len++] = identifier_str[i];
     // Add an extra "0" by the end.
     id_no_dash[id_no_dash_len++] = '0';
     std::string filename = obj_file;
     size_t slash_pos = obj_file.find_last_of("/");
     if (slash_pos != std::string::npos)
       filename = obj_file.substr(slash_pos + 1);
-    return WriteFormat(fd, "MODULE Linux %s %s 1 %s\n", arch_name,
+    return WriteFormat(fd, "MODULE Linux %s %s %s\n", arch_name,
                        id_no_dash, filename.c_str());
   }
   return false;
 }
 
 bool WriteSourceFileInfo(int fd, const struct SymbolInfo &symbols) {
   for (size_t i = 0; i < symbols.source_file_info.size(); ++i) {
     if (symbols.source_file_info[i].source_id != -1) {
@@ -611,17 +611,17 @@ class MmapWrapper {
    size_t size_;
 };
 
 }  // namespace
 
 namespace google_breakpad {
 
 bool DumpSymbols::WriteSymbolFile(const std::string &obj_file,
-                       const std::string &symbol_file) {
+				  int sym_fd) {
   int obj_fd = open(obj_file.c_str(), O_RDONLY);
   if (obj_fd < 0)
     return false;
   FDWrapper obj_fd_wrapper(obj_fd);
   struct stat st;
   if (fstat(obj_fd, &st) != 0 && st.st_size <= 0)
     return false;
   void *obj_base = mmap(NULL, st.st_size,
@@ -631,22 +631,16 @@ bool DumpSymbols::WriteSymbolFile(const 
   MmapWrapper map_wrapper(obj_base, st.st_size);
   ElfW(Ehdr) *elf_header = reinterpret_cast<ElfW(Ehdr) *>(obj_base);
   if (!IsValidElf(elf_header))
     return false;
   struct SymbolInfo symbols;
   if (!LoadSymbols(elf_header, &symbols))
      return false;
   // Write to symbol file.
-  int sym_fd = open(symbol_file.c_str(), O_CREAT | O_WRONLY | O_TRUNC, 0666);
-  if (sym_fd < 0)
-    return false;
-  FDWrapper sym_fd_wrapper(sym_fd);
   if (WriteModuleInfo(sym_fd, elf_header->e_machine, obj_file) &&
       DumpStabSymbols(sym_fd, symbols))
     return true;
 
-  // Remove the symbol file if failed to write the symbols.
-  unlink(symbol_file.c_str());
   return false;
 }
 
 }  // namespace google_breakpad
--- a/toolkit/airbag/airbag/src/common/linux/dump_symbols.h
+++ b/toolkit/airbag/airbag/src/common/linux/dump_symbols.h
@@ -35,14 +35,14 @@
 
 #include <string>
 
 namespace google_breakpad {
 
 class DumpSymbols {
  public:
   bool WriteSymbolFile(const std::string &obj_file,
-                       const std::string &symbol_file);
+                       int sym_fd);
 };
 
 }  // namespace google_breakpad
 
 #endif  // COMMON_LINUX_DUMP_SYMBOLS_H__
--- a/toolkit/airbag/airbag/src/common/linux/file_id.cc
+++ b/toolkit/airbag/airbag/src/common/linux/file_id.cc
@@ -33,21 +33,21 @@
 //
 
 #include <cassert>
 #include <cstdio>
 #include <elf.h>
 #include <fcntl.h>
 #include <link.h>
 #include <sys/mman.h>
-#include <openssl/md5.h>
 #include <string.h>
 #include <unistd.h>
 
 #include "common/linux/file_id.h"
+#include "common/linux/md5.h"
 
 namespace google_breakpad {
 
 static bool FindElfTextSection(const void *elf_mapped_base,
                                const void **text_start,
                                int *text_size) {
   assert(elf_mapped_base);
   assert(text_start);
@@ -104,20 +104,22 @@ bool FileID::ElfFileIdentifier(unsigned 
   if (!base) {
     close(fd);
     return false;
   }
   bool success = false;
   const void *text_section = NULL;
   int text_size = 0;
   if (FindElfTextSection(base, &text_section, &text_size) && (text_size > 0)) {
-    MD5_CTX md5;
-    MD5_Init(&md5);
-    MD5_Update(&md5, text_section, text_size);
-    MD5_Final(identifier, &md5);
+    struct MD5Context md5;
+    MD5Init(&md5);
+    MD5Update(&md5,
+              static_cast<const unsigned char*>(text_section),
+              text_size);
+    MD5Final(identifier, &md5);
     success = true;
   }
 
   close(fd);
   munmap(base, st.st_size);
   return success;
 }
 
new file mode 100644
--- /dev/null
+++ b/toolkit/airbag/airbag/src/common/linux/md5.c
@@ -0,0 +1,246 @@
+/*
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ */
+
+#include <string.h>
+
+#include "common/linux/md5.h"
+
+#ifndef WORDS_BIGENDIAN
+#define byteReverse(buf, len)   /* Nothing */
+#else
+/*
+ * Note: this code is harmless on little-endian machines.
+ */
+static void byteReverse(unsigned char *buf, unsigned longs)
+{
+  u32 t;
+  do {
+    t = (u32) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
+      ((unsigned) buf[1] << 8 | buf[0]);
+    *(u32 *) buf = t;
+    buf += 4;
+  } while (--longs);
+}
+#endif
+
+static void MD5Transform(u32 buf[4], u32 const in[16]);
+
+/*
+ * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+void MD5Init(struct MD5Context *ctx)
+{
+  ctx->buf[0] = 0x67452301;
+  ctx->buf[1] = 0xefcdab89;
+  ctx->buf[2] = 0x98badcfe;
+  ctx->buf[3] = 0x10325476;
+
+  ctx->bits[0] = 0;
+  ctx->bits[1] = 0;
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len)
+{
+  u32 t;
+
+  /* Update bitcount */
+
+  t = ctx->bits[0];
+  if ((ctx->bits[0] = t + ((u32) len << 3)) < t)
+    ctx->bits[1]++;         /* Carry from low to high */
+  ctx->bits[1] += len >> 29;
+
+  t = (t >> 3) & 0x3f;        /* Bytes already in shsInfo->data */
+
+  /* Handle any leading odd-sized chunks */
+
+  if (t) {
+    unsigned char *p = (unsigned char *) ctx->in + t;
+
+    t = 64 - t;
+    if (len < t) {
+      memcpy(p, buf, len);
+      return;
+    }
+    memcpy(p, buf, t);
+    byteReverse(ctx->in, 16);
+    MD5Transform(ctx->buf, (u32 *) ctx->in);
+    buf += t;
+    len -= t;
+  }
+  /* Process data in 64-byte chunks */
+
+  while (len >= 64) {
+    memcpy(ctx->in, buf, 64);
+    byteReverse(ctx->in, 16);
+    MD5Transform(ctx->buf, (u32 *) ctx->in);
+    buf += 64;
+    len -= 64;
+  }
+
+  /* Handle any remaining bytes of data. */
+
+  memcpy(ctx->in, buf, len);
+}
+
+/*
+ * Final wrapup - pad to 64-byte boundary with the bit pattern
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
+{
+  unsigned count;
+  unsigned char *p;
+
+  /* Compute number of bytes mod 64 */
+  count = (ctx->bits[0] >> 3) & 0x3F;
+
+  /* Set the first char of padding to 0x80.  This is safe since there is
+     always at least one byte free */
+  p = ctx->in + count;
+  *p++ = 0x80;
+
+  /* Bytes of padding needed to make 64 bytes */
+  count = 64 - 1 - count;
+
+  /* Pad out to 56 mod 64 */
+  if (count < 8) {
+    /* Two lots of padding:  Pad the first block to 64 bytes */
+    memset(p, 0, count);
+    byteReverse(ctx->in, 16);
+    MD5Transform(ctx->buf, (u32 *) ctx->in);
+
+    /* Now fill the next block with 56 bytes */
+    memset(ctx->in, 0, 56);
+  } else {
+    /* Pad block to 56 bytes */
+    memset(p, 0, count - 8);
+  }
+  byteReverse(ctx->in, 14);
+
+  /* Append length in bits and transform */
+  ((u32 *) ctx->in)[14] = ctx->bits[0];
+  ((u32 *) ctx->in)[15] = ctx->bits[1];
+
+  MD5Transform(ctx->buf, (u32 *) ctx->in);
+  byteReverse((unsigned char *) ctx->buf, 4);
+  memcpy(digest, ctx->buf, 16);
+  memset(ctx, 0, sizeof(ctx));        /* In case it's sensitive */
+}
+
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f, w, x, y, z, data, s) \
+  ( w += f(x, y, z) + data,  w = w<<s | w>>(32-s),  w += x )
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data.  MD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+static void MD5Transform(u32 buf[4], u32 const in[16])
+{
+  register u32 a, b, c, d;
+
+  a = buf[0];
+  b = buf[1];
+  c = buf[2];
+  d = buf[3];
+
+  MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
+  MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
+  MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
+  MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
+  MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
+  MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
+  MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
+  MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
+  MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
+  MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
+  MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+  MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+  MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
+  MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
+  MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
+  MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+
+  MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
+  MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
+  MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+  MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
+  MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
+  MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
+  MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+  MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
+  MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
+  MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
+  MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
+  MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
+  MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
+  MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
+  MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
+  MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+
+  MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
+  MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
+  MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+  MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+  MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
+  MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
+  MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
+  MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+  MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
+  MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
+  MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
+  MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
+  MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
+  MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+  MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+  MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
+
+  MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
+  MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
+  MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+  MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
+  MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
+  MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
+  MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+  MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
+  MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
+  MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+  MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
+  MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+  MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
+  MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+  MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
+  MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
+
+  buf[0] += a;
+  buf[1] += b;
+  buf[2] += c;
+  buf[3] += d;
+}
new file mode 100644
--- /dev/null
+++ b/toolkit/airbag/airbag/src/common/linux/md5.h
@@ -0,0 +1,31 @@
+// Copyright 2007 Google Inc. All Rights Reserved.
+// Author: liuli@google.com (Liu Li)
+#ifndef COMMON_LINUX_MD5_H__
+#define COMMON_LINUX_MD5_H__
+
+#include <stdint.h>
+
+typedef uint32_t u32;
+typedef uint8_t u8;
+
+struct MD5Context {
+  u32 buf[4];
+  u32 bits[2];
+  u8 in[64];
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif  // __cplusplus
+
+void MD5Init(struct MD5Context *ctx);
+
+void MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len);
+
+void MD5Final(unsigned char digest[16], struct MD5Context *ctx);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif  // COMMON_LINUX_MD5_H__
--- a/toolkit/airbag/airbag/src/common/mac/Makefile.in
+++ b/toolkit/airbag/airbag/src/common/mac/Makefile.in
@@ -50,16 +50,17 @@ LOCAL_INCLUDES 	= -I$(srcdir)/../..
 # This is a little weird, but we're building a host and a target lib here.
 # The host lib is used for dump_syms, and the target lib for the
 # crash reporter client.  Therefore, we don't need all the srcs in both.
 CPPSRCS	= \
   file_id.cc \
   macho_id.cc \
   macho_walker.cc \
   string_utilities.cc \
+  macho_utilities.cc \
   $(NULL)
 
 CMSRCS = \
   HTTPMultipartUpload.m \
   $(NULL)
 
 HOST_CPPSRCS = $(CPPSRCS)
 
--- a/toolkit/airbag/airbag/src/common/mac/dump_syms.h
+++ b/toolkit/airbag/airbag/src/common/mac/dump_syms.h
@@ -34,21 +34,22 @@
 
 #import <Foundation/Foundation.h>
 
 @interface DumpSymbols : NSObject {
  @protected
   NSString *sourcePath_;              // Source of symbols (STRONG)
   NSString *architecture_;            // Architecture to extract (STRONG)
   NSMutableDictionary *addresses_;    // Addresses and symbols (STRONG)
+  NSMutableSet *functionAddresses_;   // Function addresses (STRONG)
   NSMutableDictionary *sources_;      // Address and Source file paths (STRONG)
   NSMutableArray *cppAddresses_;      // Addresses of C++ symbols (STRONG)
   NSMutableDictionary *headers_;      // Mach-o header information (STRONG)
-  NSMutableDictionary *lastFunctionStartDict_; // Keyed by section# (STRONG)
   NSMutableDictionary *sectionNumbers_; // Keyed by seg/sect name (STRONG)
+  uint32_t   lastStartAddress_;
 }
 
 - (id)initWithContentsOfFile:(NSString *)machoFile;
 
 - (NSArray *)availableArchitectures;
 
 // One of ppc, x86, i386, ppc64, x86_64
 // If the architecture is not available, it will return NO
--- a/toolkit/airbag/airbag/src/common/mac/dump_syms.mm
+++ b/toolkit/airbag/airbag/src/common/mac/dump_syms.mm
@@ -26,28 +26,32 @@
 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 // dump_syms.mm: Create a symbol file for use with minidumps
 
 #include <unistd.h>
 #include <signal.h>
+#include <cxxabi.h>
+#include <stdlib.h>
 
 #include <mach/machine.h>
 #include <mach-o/arch.h>
 #include <mach-o/fat.h>
 #include <mach-o/loader.h>
 #include <mach-o/nlist.h>
 #include <mach-o/stab.h>
+#include <fcntl.h>
 
 #import <Foundation/Foundation.h>
 
 #import "dump_syms.h"
 #import "common/mac/file_id.h"
+#import "common/mac/macho_utilities.h"
 
 using google_breakpad::FileID;
 
 static NSString *kAddressSymbolKey = @"symbol";
 static NSString *kAddressConvertedSymbolKey = @"converted_symbol";
 static NSString *kAddressSourceLineKey = @"line";
 static NSString *kFunctionSizeKey = @"size";
 static NSString *kHeaderBaseAddressKey = @"baseAddr";
@@ -57,138 +61,54 @@ static NSString *kHeaderIs64BitKey = @"i
 static NSString *kHeaderCPUTypeKey = @"cpuType";
 static NSString *kUnknownSymbol = @"???";
 
 // The section for __TEXT, __text seems to be always 1.  This is useful
 // for pruning out extraneous non-function symbols.
 static const int kTextSection = 1;
 
 @interface DumpSymbols(PrivateMethods)
-- (NSString *)stringFromTask:(NSString *)action args:(NSArray *)args
-                  standardIn:(NSFileHandle *)standardIn;
 - (NSArray *)convertCPlusPlusSymbols:(NSArray *)symbols;
 - (void)convertSymbols;
 - (void)addFunction:(NSString *)name line:(int)line address:(uint64_t)address section:(int)section;
 - (BOOL)processSymbolItem:(struct nlist_64 *)list stringTable:(char *)table;
 - (BOOL)loadSymbolInfo:(void *)base offset:(uint32_t)offset;
 - (BOOL)loadSymbolInfo64:(void *)base offset:(uint32_t)offset;
 - (BOOL)loadSymbolInfoForArchitecture;
 - (void)generateSectionDictionary:(struct mach_header*)header;
 - (BOOL)loadHeader:(void *)base offset:(uint32_t)offset;
 - (BOOL)loadHeader64:(void *)base offset:(uint32_t)offset;
 - (BOOL)loadModuleInfo;
 @end
 
-static BOOL StringHeadMatches(NSString *str, NSString *head) {
-  int headLen = [head length];
-  int strLen = [str length];
-
-  if (headLen > strLen)
-    return NO;
-
-  return [[str substringToIndex:headLen] isEqualToString:head];
-}
-
-static BOOL StringTailMatches(NSString *str, NSString *tail) {
-  int tailLen = [tail length];
-  int strLen = [str length];
-
-  if (tailLen > strLen)
-    return NO;
-
-  return [[str substringFromIndex:strLen - tailLen] isEqualToString:tail];
-}
-
 @implementation DumpSymbols
 //=============================================================================
-- (NSString *)stringFromTask:(NSString *)action args:(NSArray *)args
-                  standardIn:(NSFileHandle *)standardIn {
-  NSTask *task = [[NSTask alloc] init];
-  [task setLaunchPath:action];
-  NSPipe *pipe = [NSPipe pipe];
-  [task setStandardOutput:pipe];
-  NSFileHandle *output = [pipe fileHandleForReading];
-
-  if (standardIn)
-    [task setStandardInput:standardIn];
-
-  if (args)
-    [task setArguments:args];
-
-  [task launch];
-
-  // This seems a bit strange, but when using [task waitUntilExit], it hangs
-  // waiting for data, but there isn't any.  So, we'll poll for data,
-  // take a short nap, and then ask again
-  BOOL done = NO;
-  NSMutableData *allData = [NSMutableData data];
-  NSData *data = nil;
-  int exceptionCount = 0;
-
-  while (!done) {
-    data = nil;
-    // If there's a communications problem with the task, this might throw
-    // an exception.  We'll catch and keep trying.
-    @try {
-      data = [output availableData];
-    }
-    @catch (NSException *e) {
-      ++exceptionCount;
-    }
-
-    [allData appendData:data];
+- (NSArray *)convertCPlusPlusSymbols:(NSArray *)symbols {
+  NSMutableArray *symbols_demangled = [[NSMutableArray alloc]
+					initWithCapacity:[symbols count]];
+  // __cxa_demangle will realloc this if needed
+  char *buffer = (char *)malloc(1024);
+  size_t buffer_size = 1024;
+  int result;
 
-    // Loop over the data until we're no longer returning data.  If we're
-    // still receiving data, sleep for 1/2 second and let the task
-    // continue.  If we keep receiving exceptions, bail out
-    if (![data length] && data || exceptionCount > 10)
-      done = YES;
-    else
-      usleep(500);
+  NSEnumerator *enumerator = [symbols objectEnumerator];
+  id symbolObject;
+  while ((symbolObject = [enumerator nextObject])) {
+    const char *symbol = [symbolObject UTF8String];
+    buffer = abi::__cxa_demangle(symbol, buffer, &buffer_size, &result);
+    if (result == 0) {
+      [symbols_demangled addObject:[NSString stringWithUTF8String:buffer]];
+    } else {
+      // unable to demangle - use mangled name instead
+      [symbols_demangled addObject:symbolObject];
+    }
   }
-
-  // Gather any remaining data
-  [task waitUntilExit];
-  data = [output availableData];
-  [allData appendData:data];
-  [task release];
-
-  return [[[NSString alloc] initWithData:allData
-                                encoding:NSUTF8StringEncoding] autorelease];
-}
-
-//=============================================================================
-- (NSArray *)convertCPlusPlusSymbols:(NSArray *)symbols {
-  NSString *action = @"/usr/bin/c++filt";
-  unsigned int count = [symbols count];
+  free(buffer);
 
-  // It's possible that we have too many symbols on the command line.
-  // Unfortunately, c++filt doesn't take a file containing names, so we'll
-  // copy the symbols to a temporary file and use that as stdin.
-  char buffer[PATH_MAX];
-  snprintf(buffer, sizeof(buffer), "/tmp/dump_syms_filtXXXXX");
-  int fd = mkstemp(buffer);
-  char nl = '\n';
-  for (unsigned int i = 0; i < count; ++i) {
-    const char *symbol = [[symbols objectAtIndex:i] UTF8String];
-    write(fd, symbol, strlen(symbol));
-    write(fd, &nl, 1);
-  }
-
-  // Reset to the beginning and wrap up with a file handle
-  lseek(fd, 0, SEEK_SET);
-  NSArray *args = [NSArray arrayWithObject:@"-n"];
-  NSFileHandle *fh = [[NSFileHandle alloc] initWithFileDescriptor:fd
-                                                   closeOnDealloc:YES];
-  NSArray *result = [[self stringFromTask:action args:args standardIn:fh]
-      componentsSeparatedByString:@"\n"];
-
-  [fh release];
-
-  return result;
+  return symbols_demangled;
 }
 
 //=============================================================================
 - (void)convertSymbols {
   unsigned int count = [cppAddresses_ count];
   NSMutableArray *symbols = [[NSMutableArray alloc] initWithCapacity:count];
 
   // Sort addresses for processing
@@ -202,59 +122,101 @@ static BOOL StringTailMatches(NSString *
 
     // Make sure that the symbol is valid
     if ([symbol length] < 1)
       symbol = kUnknownSymbol;
 
     [symbols addObject:symbol];
   }
 
-  NSArray *converted = [self convertCPlusPlusSymbols:symbols];
-  [symbols release];
+  // In order to deal with crashing problems in c++filt, we setup
+  // a while loop to handle the case where convertCPlusPlusSymbols
+  // only returns partial results.
+  // We then attempt to continue from the point where c++filt failed
+  // and add the partial results to the total results until we're
+  // completely done.
+  
+  unsigned int totalIndex = 0;
+  unsigned int totalCount = count;
+  
+  while (totalIndex < totalCount) {
+    NSRange range = NSMakeRange(totalIndex, totalCount - totalIndex);
+    NSArray *subarray = [symbols subarrayWithRange:range];
+    NSArray *converted = [self convertCPlusPlusSymbols:subarray];
+    unsigned int convertedCount = [converted count];
 
-  for (unsigned int i = 0; i < count; ++i) {
-    NSMutableDictionary *dict = [addresses_ objectForKey:
-      [addresses objectAtIndex:i]];
-    NSString *symbol = [converted objectAtIndex:i];
+    if (convertedCount == 0) {
+      break; // we give up at this point
+    }
+    
+    for (unsigned int convertedIndex = 0;
+      convertedIndex < convertedCount && totalIndex < totalCount;
+       ++totalIndex, ++convertedIndex) {
+      NSMutableDictionary *dict = [addresses_ objectForKey:
+        [addresses objectAtIndex:totalIndex]];
+      NSString *symbol = [converted objectAtIndex:convertedIndex];
 
-    // Only add if this is a non-zero length symbol
-    if ([symbol length])
-      [dict setObject:symbol forKey:kAddressConvertedSymbolKey];
+      // Only add if this is a non-zero length symbol
+      if ([symbol length])
+        [dict setObject:symbol forKey:kAddressConvertedSymbolKey];
+    }
   }
+  
+  [symbols release];
 }
 
 //=============================================================================
 - (void)addFunction:(NSString *)name line:(int)line address:(uint64_t)address section:(int)section {
   NSNumber *addressNum = [NSNumber numberWithUnsignedLongLong:address];
 
   if (!address)
     return;
 
   // If the function starts with "_Z" or "__Z" then add it to the list of
   // addresses to run through the c++filt
   BOOL isCPP = NO;
 
-  if (StringHeadMatches(name, @"__Z")) {
+  if ([name hasPrefix:@"__Z"]) {
     // Remove the leading underscore
     name = [name substringFromIndex:1];
     isCPP = YES;
-  } else if (StringHeadMatches(name, @"_Z")) {
+  } else if ([name hasPrefix:@"_Z"]) {
     isCPP = YES;
   }
 
   // Filter out non-functions
-  if (StringTailMatches(name, @".eh"))
+  if ([name hasSuffix:@".eh"])
+    return;
+
+  if ([name hasSuffix:@"__func__"])
+    return;
+
+  if ([name hasSuffix:@"GCC_except_table"])
     return;
 
-  if (StringTailMatches(name, @"__func__"))
-    return;
-
-  if (StringTailMatches(name, @"GCC_except_table"))
-    return;
-
+  if (isCPP) {
+    // OBJCPP_MANGLING_HACK
+    // There are cases where ObjC++ mangles up an ObjC name using quasi-C++ 
+    // mangling:
+    // @implementation Foozles + (void)barzles {
+    //    static int Baz = 0;
+    // } @end
+    // gives you _ZZ18+[Foozles barzles]E3Baz
+    // c++filt won't parse this properly, and will crash in certain cases. 
+    // Logged as radar:
+    // 5129938: c++filt does not deal with ObjC++ symbols
+    // If 5129938 ever gets fixed, we can remove this, but for now this prevents
+    // c++filt from attempting to demangle names it doesn't know how to handle.
+    // This is with c++filt 2.16
+    NSCharacterSet *objcppCharSet = [NSCharacterSet characterSetWithCharactersInString:@"-+[]: "];
+    NSRange emptyRange = { NSNotFound, 0 };
+    NSRange objcppRange = [name rangeOfCharacterFromSet:objcppCharSet];
+    isCPP = NSEqualRanges(objcppRange, emptyRange);
+  }
+  
   if (isCPP) {
     if (!cppAddresses_)
       cppAddresses_ = [[NSMutableArray alloc] init];
     [cppAddresses_ addObject:addressNum];
   } else if ([name characterAtIndex:0] == '_') {
     // Remove the leading underscore
     name = [name substringFromIndex:1];
   }
@@ -264,46 +226,67 @@ static BOOL StringTailMatches(NSString *
   NSMutableDictionary *dict = [addresses_ objectForKey:addressNum];
 
   if (!dict) {
     dict = [[NSMutableDictionary alloc] init];
     [addresses_ setObject:dict forKey:addressNum];
     [dict release];
   }
 
-  if (name && ![dict objectForKey:kAddressSymbolKey])
+  if (name && ![dict objectForKey:kAddressSymbolKey]) {
     [dict setObject:name forKey:kAddressSymbolKey];
 
+    // only functions, not line number addresses
+    [functionAddresses_ addObject:addressNum];
+  }
+  
   if (line && ![dict objectForKey:kAddressSourceLineKey])
     [dict setObject:[NSNumber numberWithUnsignedInt:line]
              forKey:kAddressSourceLineKey];
-
-  // Save the function name so that we can add the end of function address
-  if ([name length]) {
-    [lastFunctionStartDict_ setObject:addressNum forKey:[NSNumber numberWithUnsignedInt:section] ];
-  }
 }
 
 //=============================================================================
 - (BOOL)processSymbolItem:(struct nlist_64 *)list stringTable:(char *)table {
   uint32_t n_strx = list->n_un.n_strx;
   BOOL result = NO;
 
-  // We don't care about non-section specific information
-  if (list->n_sect == 0 )
+  // We don't care about non-section specific information except function length
+  if (list->n_sect == 0 && list->n_type != N_FUN )
     return NO;
 
+  if (list->n_type == N_FUN) {
+    if (list->n_sect != 0) {
+      // we get the function address from the first N_FUN
+      lastStartAddress_ = list->n_value;
+    }
+    else {
+      // an N_FUN from section 0 may follow the initial N_FUN
+      // giving us function length information
+      NSMutableDictionary *dict = [addresses_ objectForKey:
+        [NSNumber numberWithUnsignedLong:lastStartAddress_]];
+      
+      assert(dict);
+
+      // only set the function size the first time
+      // (sometimes multiple section 0 N_FUN entries appear!)
+      if (![dict objectForKey:kFunctionSizeKey]) {
+        [dict setObject:[NSNumber numberWithUnsignedLongLong:list->n_value]
+                 forKey:kFunctionSizeKey];
+      }
+    }
+  }
+  
   int line = list->n_desc;
   
   // We only care about line number information in __TEXT __text
   uint32_t mainSection = [[sectionNumbers_ objectForKey:@"__TEXT__text" ] unsignedLongValue];
   if(list->n_sect != mainSection) {
     line = 0;
   }
-       
+
   // Extract debugging information:
   // Doc: http://developer.apple.com/documentation/DeveloperTools/gdb/stabs/stabs_toc.html
   // Header: /usr/include/mach-o/stab.h:
   if (list->n_type == N_SO)  {
     NSString *src = [NSString stringWithUTF8String:&table[n_strx]];
     NSString *ext = [src pathExtension];
     NSNumber *address = [NSNumber numberWithUnsignedLongLong:list->n_value];
 
@@ -331,34 +314,19 @@ static BOOL StringTailMatches(NSString *
 
     result = YES;
   } else if (list->n_type == N_SLINE && list->n_sect == mainSection ) {
     [self addFunction:nil line:line address:list->n_value section:list->n_sect ];
     result = YES;
   } else if (((list->n_type & N_TYPE) == N_SECT) && !(list->n_type & N_STAB)) {
     // Regular symbols or ones that are external
     NSString *fn = [NSString stringWithUTF8String:&table[n_strx]];
+
     [self addFunction:fn line:0 address:list->n_value section:list->n_sect ];
     result = YES;
-  } else if (list->n_type == N_ENSYM && list->n_sect == mainSection ) {
-    NSNumber *lastFunctionStart = [lastFunctionStartDict_ 
-      objectForKey:[NSNumber numberWithUnsignedLongLong:list->n_sect]  ];
-
-    if (lastFunctionStart) {
-      unsigned long long start = [lastFunctionStart unsignedLongLongValue];
-      unsigned long long size = list->n_value - start;
-      NSMutableDictionary *dict = [addresses_ objectForKey:lastFunctionStart];
-      assert(dict);
-      assert(list->n_value > start);
-      
-      [dict setObject:[NSNumber numberWithUnsignedLongLong:size]
-               forKey:kFunctionSizeKey];
-
-      [lastFunctionStartDict_ removeObjectForKey:[NSNumber numberWithUnsignedLongLong:list->n_sect] ];
-    }
   }
 
   return result;
 }
 
 #define SwapLongLongIfNeeded(a) (swap ? NXSwapLongLong(a) : (a))
 #define SwapLongIfNeeded(a) (swap ? NXSwapLong(a) : (a))
 #define SwapIntIfNeeded(a) (swap ? NXSwapInt(a) : (a))
@@ -387,17 +355,17 @@ static BOOL StringTailMatches(NSString *
 
       // Process each command, looking for debugging stuff
       for (uint32_t j = 0; j < ncmds; ++j, ++list) {
         // Fill in an nlist_64 structure and process with that
         struct nlist_64 nlist64;
         nlist64.n_un.n_strx = SwapLongIfNeeded(list->n_un.n_strx);
         nlist64.n_type = list->n_type;
         nlist64.n_sect = list->n_sect;
-        nlist64.n_desc = SwapIntIfNeeded(list->n_desc);
+        nlist64.n_desc = SwapShortIfNeeded(list->n_desc);
         nlist64.n_value = (uint64_t)SwapLongIfNeeded(list->n_value);
 
         if ([self processSymbolItem:&nlist64 stringTable:strtab])
           result = YES;
       }
     }
 
     uint32_t cmdSize = SwapLongIfNeeded(cmd->cmdsize);
@@ -432,17 +400,17 @@ static BOOL StringTailMatches(NSString *
         if (!(list->n_type & (N_STAB | N_TYPE)))
           continue;
 
         // Fill in an nlist_64 structure and process with that
         struct nlist_64 nlist64;
         nlist64.n_un.n_strx = SwapLongIfNeeded(list->n_un.n_strx);
         nlist64.n_type = list->n_type;
         nlist64.n_sect = list->n_sect;
-        nlist64.n_desc = SwapIntIfNeeded(list->n_desc);
+        nlist64.n_desc = SwapShortIfNeeded(list->n_desc);
         nlist64.n_value = SwapLongLongIfNeeded(list->n_value);
 
         if ([self processSymbolItem:&nlist64 stringTable:strtab])
           result = YES;
       }
     }
 
     uint32_t cmdSize = SwapLongIfNeeded(cmd->cmdsize);
@@ -663,39 +631,48 @@ static BOOL WriteFormat(int fd, const ch
   NSDictionary *archDict = [headers_ objectForKey:architecture_];
   NSNumber *baseAddressNum = [archDict objectForKey:kHeaderBaseAddressKey];
   uint64_t baseAddress =
     baseAddressNum ? [baseAddressNum unsignedLongLongValue] : 0;
   NSNumber *moduleSizeNum = [archDict objectForKey:kHeaderSizeKey];
   uint64_t moduleSize =
     moduleSizeNum ? [moduleSizeNum unsignedLongLongValue] : 0;
 
-  [lastFunctionStartDict_ removeAllObjects];
-  
-  // Gather the information
-  [self loadSymbolInfoForArchitecture];
-  [self convertSymbols];
-
-  NSArray *sortedAddresses = [[addresses_ allKeys]
-    sortedArrayUsingSelector:@selector(compare:)];
-
   // UUID
   FileID file_id([sourcePath_ fileSystemRepresentation]);
   unsigned char identifier[16];
   char identifierStr[40];
   const char *moduleName = [[sourcePath_ lastPathComponent] UTF8String];
   int cpu_type = [[archDict objectForKey:kHeaderCPUTypeKey] unsignedLongValue];
   if (file_id.MachoIdentifier(cpu_type, identifier)) {
     FileID::ConvertIdentifierToString(identifier, identifierStr,
                                       sizeof(identifierStr));
   }
   else {
-    strlcpy(identifierStr, moduleName, sizeof(identifierStr));
+    fprintf(stderr, "Unable to calculate UUID of mach-o binary!\n");
+    return NO;
   }
 
+  // keep track exclusively of function addresses
+  // for sanity checking function lengths
+  functionAddresses_ = [[NSMutableSet alloc] init];
+
+  // Gather the information
+  [self loadSymbolInfoForArchitecture];
+  [self convertSymbols];
+
+  NSArray *sortedAddresses = [[addresses_ allKeys]
+    sortedArrayUsingSelector:@selector(compare:)];
+
+  NSArray *sortedFunctionAddresses = [[functionAddresses_ allObjects]
+    sortedArrayUsingSelector:@selector(compare:)];
+
+  // position ourselves at the 2nd function
+  unsigned int funcIndex = 1;
+
   // Remove the dashes from the string
   NSMutableString *compactedStr =
     [NSMutableString stringWithCString:identifierStr encoding:NSASCIIStringEncoding];
   [compactedStr replaceOccurrencesOfString:@"-" withString:@"" options:0
                                      range:NSMakeRange(0, [compactedStr length])];
 
   if (!WriteFormat(fd, "MODULE mac %s %s0 %s\n", [architecture_ UTF8String],
                    [compactedStr UTF8String], moduleName)) {
@@ -728,47 +705,56 @@ static BOOL WriteFormat(int fd, const ch
     if (i + 1 < addressCount) {
       nextAddress = [sortedAddresses objectAtIndex:i + 1];
       nextAddressVal = [nextAddress unsignedLongLongValue] - baseAddress;
     } else {
       nextAddressVal = baseAddress + moduleSize;
       // The symbol reader doesn't want a trailing newline
       terminatingChar = '\0';
     }
-
+    
     NSDictionary *dict = [addresses_ objectForKey:address];
     NSNumber *line = [dict objectForKey:kAddressSourceLineKey];
     NSString *symbol = [dict objectForKey:kAddressConvertedSymbolKey];
 
     if (!symbol)
       symbol = [dict objectForKey:kAddressSymbolKey];
 
+    // sanity check the function length by making sure it doesn't
+    // run beyond the next function entry
+    uint64_t nextFunctionAddress = 0;
+    if (symbol && funcIndex < [sortedFunctionAddresses count]) {
+      nextFunctionAddress = [[sortedFunctionAddresses objectAtIndex:funcIndex]
+        unsignedLongLongValue] - baseAddress;
+      ++funcIndex;
+    }
+
     // Skip some symbols
-    if (StringHeadMatches(symbol, @"vtable for"))
+    if ([symbol hasPrefix:@"vtable for"])
       continue;
 
-    if (StringHeadMatches(symbol, @"__static_initialization_and_destruction_0"))
-      continue;
-
-    if (StringHeadMatches(symbol, @"_GLOBAL__I__"))
+    if ([symbol hasPrefix:@"__static_initialization_and_destruction_0"])
       continue;
 
-    if (StringHeadMatches(symbol, @"__func__."))
+    if ([symbol hasPrefix:@"_GLOBAL__I__"])
       continue;
 
-    if (StringHeadMatches(symbol, @"__gnu"))
+    if ([symbol hasPrefix:@"__func__."])
       continue;
 
-    if (StringHeadMatches(symbol, @"typeinfo "))
+    if ([symbol hasPrefix:@"__gnu"])
       continue;
 
-    if (StringHeadMatches(symbol, @"EH_frame"))
+    if ([symbol hasPrefix:@"typeinfo "])
       continue;
 
-    if (StringHeadMatches(symbol, @"GCC_except_table"))
+    if ([symbol hasPrefix:@"EH_frame"])
+      continue;
+
+    if ([symbol hasPrefix:@"GCC_except_table"])
       continue;
 
     // Find the source file (if any) that contains this address
     while (sourceCount && (addressVal >= nextSourceFileAddress)) {
       fileIdx = nextFileIdx;
 
       if (nextFileIdx < sourceCount) {
         NSNumber *addr = [sources objectAtIndex:nextFileIdx];
@@ -780,16 +766,26 @@ static BOOL WriteFormat(int fd, const ch
       }
     }
 
     NSNumber *functionLength = [dict objectForKey:kFunctionSizeKey];
 
     if (line) {
       if (symbol && functionLength) {
         uint64_t functionLengthVal = [functionLength unsignedLongLongValue];
+        
+        // sanity check to make sure the length we were told does not exceed
+        // the space between this function and the next
+        if (nextFunctionAddress != 0) {
+          uint64_t functionLengthVal2 = nextFunctionAddress - addressVal;
+
+          if(functionLengthVal > functionLengthVal2 ) {
+            functionLengthVal = functionLengthVal2;
+          }
+        }
 
         // Function
         if (!WriteFormat(fd, "FUNC %llx %llx 0 %s\n", addressVal,
                          functionLengthVal, [symbol UTF8String]))
           return NO;
       }
 
       // Source line
@@ -819,20 +815,16 @@ static BOOL WriteFormat(int fd, const ch
 
     sourcePath_ = [path copy];
 
     if (![self loadModuleInfo]) {
       [self autorelease];
       return nil;
     }
 
-    // keep track of last function start address on a per-section basis
-    if (!lastFunctionStartDict_)
-      lastFunctionStartDict_ = [[NSMutableDictionary alloc] init];
-
     // If there's more than one, use the native one
     if ([headers_ count] > 1) {
       const NXArchInfo *localArchInfo = NXGetLocalArchInfo();
 
       if (localArchInfo) {
         cpu_type_t cpu = localArchInfo->cputype;
         NSString *arch;
 
@@ -858,20 +850,20 @@ static BOOL WriteFormat(int fd, const ch
   return [headers_ allKeys];
 }
 
 //=============================================================================
 - (void)dealloc {
   [sourcePath_ release];
   [architecture_ release];
   [addresses_ release];
+  [functionAddresses_ release];
   [sources_ release];
   [headers_ release];
-  [lastFunctionStartDict_ release];
-
+  
   [super dealloc];
 }
 
 //=============================================================================
 - (BOOL)setArchitecture:(NSString *)architecture {
   NSString *normalized = [architecture lowercaseString];
   BOOL isValid = NO;
 
--- a/toolkit/airbag/airbag/src/common/mac/macho_id.cc
+++ b/toolkit/airbag/airbag/src/common/mac/macho_id.cc
@@ -42,16 +42,17 @@
 #include <stdlib.h>
 #include <string.h>
 #include <sys/time.h>
 #include <sys/types.h>
 #include <unistd.h>
 
 #include "common/mac/macho_id.h"
 #include "common/mac/macho_walker.h"
+#include "common/mac/macho_utilities.h"
 
 namespace MacFileUtilities {
 
 MachoID::MachoID(const char *path) {
   strlcpy(path_, path, sizeof(path_));
   file_ = open(path, O_RDONLY);
 }
 
@@ -137,17 +138,17 @@ void MachoID::Update(MachoWalker *walker
       return;
 
     (this->*update_function_)(buffer, buffer_size);
     file_offset += buffer_size;
   }
 }
 
 bool MachoID::UUIDCommand(int cpu_type, unsigned char bytes[16]) {
-  struct uuid_command uuid_cmd;
+  struct breakpad_uuid_command uuid_cmd;
   MachoWalker walker(path_, UUIDWalkerCB, &uuid_cmd);
 
   uuid_cmd.cmd = 0;
   if (!walker.WalkHeader(cpu_type))
     return false;
 
   // If we found the command, we'll have initialized the uuid_command
   // structure
@@ -279,55 +280,57 @@ bool MachoID::WalkerCB(MachoWalker *walk
     }
   } else if (cmd->cmd == LC_SEGMENT_64) {
     struct segment_command_64 seg64;
 
     if (!walker->ReadBytes(&seg64, sizeof(seg64), offset))
       return false;
 
     if (swap)
-      swap_segment_command_64(&seg64, NXHostByteOrder());
+      breakpad_swap_segment_command_64(&seg64, NXHostByteOrder());
 
     struct mach_header_64 header;
     off_t header_offset;
     
     if (!walker->CurrentHeader(&header, &header_offset))
       return false;
     
     // Process segments that have sections:
     // (e.g., __TEXT, __DATA, __IMPORT, __OBJC)
     offset += sizeof(struct segment_command_64);
     struct section_64 sec64;
     for (unsigned long i = 0; i < seg64.nsects; ++i) {
       if (!walker->ReadBytes(&sec64, sizeof(sec64), offset))
         return false;
 
       if (swap)
-        swap_section_64(&sec64, 1, NXHostByteOrder());
+        breakpad_swap_section_64(&sec64, 1, NXHostByteOrder());
 
       macho_id->Update(walker, header_offset + sec64.offset, sec64.size);
       offset += sizeof(struct section_64);
     }
   }
 
   // Continue processing
   return true;
 }
 
 // static
 bool MachoID::UUIDWalkerCB(MachoWalker *walker, load_command *cmd, off_t offset,
                            bool swap, void *context) {
   if (cmd->cmd == LC_UUID) {
-    struct uuid_command *uuid_cmd = (struct uuid_command *)context;
+    struct breakpad_uuid_command *uuid_cmd =
+      (struct breakpad_uuid_command *)context;
 
-    if (!walker->ReadBytes(uuid_cmd, sizeof(struct uuid_command), offset))
+    if (!walker->ReadBytes(uuid_cmd, sizeof(struct breakpad_uuid_command),
+                           offset))
       return false;
 
     if (swap)
-      swap_uuid_command(uuid_cmd, NXHostByteOrder());
+      breakpad_swap_uuid_command(uuid_cmd, NXHostByteOrder());
 
     return false;
   }
 
   // Continue processing
   return true;
 }
 
new file mode 100644
--- /dev/null
+++ b/toolkit/airbag/airbag/src/common/mac/macho_utilities.cc
@@ -0,0 +1,89 @@
+// Copyright (c) 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// macho_utilties.cc: Utilities for dealing with mach-o files
+//
+// Author: Dave Camp
+
+#include "common/mac/macho_utilities.h"
+
+void breakpad_swap_uuid_command(struct breakpad_uuid_command *uc,
+                                enum NXByteOrder target_byte_order)
+{
+  uc->cmd = NXSwapLong(uc->cmd);
+  uc->cmdsize = NXSwapLong(uc->cmdsize);
+}
+
+void breakpad_swap_segment_command_64(struct segment_command_64 *sg,
+                                      enum NXByteOrder target_byte_order)
+{
+  sg->cmd = NXSwapLong(sg->cmd);
+  sg->cmdsize = NXSwapLong(sg->cmdsize);
+
+  sg->vmaddr = NXSwapLongLong(sg->vmaddr);
+  sg->vmsize = NXSwapLongLong(sg->vmsize);
+  sg->fileoff = NXSwapLongLong(sg->fileoff);
+  sg->filesize = NXSwapLongLong(sg->filesize);
+
+  sg->maxprot = NXSwapLong(sg->maxprot);
+  sg->initprot = NXSwapLong(sg->initprot);
+  sg->nsects = NXSwapLong(sg->nsects);
+  sg->flags = NXSwapLong(sg->flags);
+}
+
+void breakpad_swap_mach_header_64(struct mach_header_64 *mh,
+                                  enum NXByteOrder target_byte_order)
+{
+  mh->magic = NXSwapLong(mh->magic);
+  mh->cputype = NXSwapLong(mh->cputype);
+  mh->cpusubtype = NXSwapLong(mh->cpusubtype);
+  mh->filetype = NXSwapLong(mh->filetype);
+  mh->ncmds = NXSwapLong(mh->ncmds);
+  mh->sizeofcmds = NXSwapLong(mh->sizeofcmds);
+  mh->flags = NXSwapLong(mh->flags);
+  mh->reserved = NXSwapLong(mh->reserved);
+}
+
+void breakpad_swap_section_64(struct section_64 *s,
+                              uint32_t nsects,
+                              enum NXByteOrder target_byte_order)
+{
+  for (uint32_t i = 0; i < nsects; i++) {
+    s[i].addr = NXSwapLongLong(s[i].addr);
+    s[i].size = NXSwapLongLong(s[i].size);
+
+    s[i].offset = NXSwapLong(s[i].offset);
+    s[i].align = NXSwapLong(s[i].align);
+    s[i].reloff = NXSwapLong(s[i].reloff);
+    s[i].nreloc = NXSwapLong(s[i].nreloc);
+    s[i].flags = NXSwapLong(s[i].flags);
+    s[i].reserved1 = NXSwapLong(s[i].reserved1);
+    s[i].reserved2 = NXSwapLong(s[i].reserved2);
+  }
+}
new file mode 100644
--- /dev/null
+++ b/toolkit/airbag/airbag/src/common/mac/macho_utilities.h
@@ -0,0 +1,85 @@
+// Copyright (c) 2006, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+// macho_utilities.h: Utilities for dealing with mach-o files
+//
+// Author: Dave Camp
+
+#ifndef COMMON_MAC_MACHO_UTILITIES_H__
+#define COMMON_MAC_MACHO_UTILITIES_H__
+
+#include <mach-o/loader.h>
+#include <mach/thread_status.h>
+
+/* Some #defines and structs that aren't defined in older SDKs */
+#ifndef CPU_ARCH_ABI64
+# define CPU_ARCH_ABI64    0x01000000
+#endif
+
+#ifndef CPU_TYPE_X86
+# define CPU_TYPE_X86 CPU_TYPE_I386
+#endif
+
+#ifndef CPU_TYPE_POWERPC64
+# define CPU_TYPE_POWERPC64 (CPU_TYPE_POWERPC | CPU_ARCH_ABI64)
+#endif
+
+#ifndef LC_UUID
+# define LC_UUID         0x1b    /* the uuid */
+#endif
+
+
+// The uuid_command struct/swap routines were added during the 10.4 series.
+// Their presence isn't guaranteed.
+struct breakpad_uuid_command {
+  uint32_t    cmd;            /* LC_UUID */
+  uint32_t    cmdsize;        /* sizeof(struct uuid_command) */
+  uint8_t     uuid[16];       /* the 128-bit uuid */
+};
+
+void breakpad_swap_uuid_command(struct breakpad_uuid_command *uc,
+                                enum NXByteOrder target_byte_order);
+
+// Older SDKs defines thread_state_data_t as an int[] instead
+// of the natural_t[] it should be.
+typedef natural_t breakpad_thread_state_data_t[THREAD_STATE_MAX];
+
+// The 64-bit swap routines were added during the 10.4 series, their
+// presence isn't guaranteed.
+void breakpad_swap_segment_command_64(struct segment_command_64 *sg,
+                                      enum NXByteOrder target_byte_order);
+
+void breakpad_swap_mach_header_64(struct mach_header_64 *mh,
+                                  enum NXByteOrder target_byte_order);
+
+void breakpad_swap_section_64(struct section_64 *s,
+                              uint32_t nsects,
+                              enum NXByteOrder target_byte_order);
+
+#endif
\ No newline at end of file
--- a/toolkit/airbag/airbag/src/common/mac/macho_walker.cc
+++ b/toolkit/airbag/airbag/src/common/mac/macho_walker.cc
@@ -37,16 +37,17 @@
 #include <fcntl.h>
 #include <mach-o/arch.h>
 #include <mach-o/loader.h>
 #include <mach-o/swap.h>
 #include <string.h>
 #include <unistd.h>
 
 #include "common/mac/macho_walker.h"
+#include "common/mac/macho_utilities.h"
 
 namespace MacFileUtilities {
 
 MachoWalker::MachoWalker(const char *path, LoadCommandCallback callback,
                          void *context)
     : callback_(callback),
       callback_context_(context) {
   file_ = open(path, O_RDONLY);
@@ -125,16 +126,19 @@ bool MachoWalker::FindHeader(int cpu_typ
 
   if (!is_fat) {
     // If we don't have a fat header, check if the cpu type matches the single
     // header
     cpu_type_t header_cpu_type;
     if (!ReadBytes(&header_cpu_type, sizeof(header_cpu_type), offset))
       return false;
 
+    if (magic == MH_CIGAM || magic == MH_CIGAM_64)
+      header_cpu_type = NXSwapInt(header_cpu_type);
+
     if (valid_cpu_type != header_cpu_type)
       return false;
 
     offset = 0;
     return true;
   } else {
     // Read the fat header and find an appropriate architecture
     offset = 0;
@@ -196,17 +200,17 @@ bool MachoWalker::WalkHeaderAtOffset(off
 
 bool MachoWalker::WalkHeader64AtOffset(off_t offset) {
   struct mach_header_64 header;
   if (!ReadBytes(&header, sizeof(header), offset))
     return false;
 
   bool swap = (header.magic == MH_CIGAM_64);
   if (swap)
-    swap_mach_header_64(&header, NXHostByteOrder());
+    breakpad_swap_mach_header_64(&header, NXHostByteOrder());
 
   current_header_ = &header;
   current_header_size_ = sizeof(header);
   current_header_offset_ = offset;
   offset += current_header_size_;
   bool result = WalkHeaderCore(offset, header.ncmds, swap);
   current_header_ = NULL;
   current_header_size_ = 0;
--- a/toolkit/airbag/airbag/src/common/windows/guid_string.cc
+++ b/toolkit/airbag/airbag/src/common/windows/guid_string.cc
@@ -44,29 +44,33 @@ wstring GUIDString::GUIDToWString(GUID *
   wchar_t guid_string[37];
   swprintf(
       guid_string, sizeof(guid_string) / sizeof(guid_string[0]),
       L"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
       guid->Data1, guid->Data2, guid->Data3,
       guid->Data4[0], guid->Data4[1], guid->Data4[2],
       guid->Data4[3], guid->Data4[4], guid->Data4[5],
       guid->Data4[6], guid->Data4[7]);
-  GB_WSU_SAFE_SWPRINTF_TERMINATE(guid_string,
-                                 sizeof(guid_string) / sizeof(guid_string[0]));
+
+  // remove when VC++7.1 is no longer supported
+  guid_string[sizeof(guid_string) / sizeof(guid_string[0]) - 1] = L'\0';
+
   return wstring(guid_string);
 }
 
 // static
 wstring GUIDString::GUIDToSymbolServerWString(GUID *guid) {
   wchar_t guid_string[33];
   swprintf(
       guid_string, sizeof(guid_string) / sizeof(guid_string[0]),
       L"%08X%04X%04X%02X%02X%02X%02X%02X%02X%02X%02X",
       guid->Data1, guid->Data2, guid->Data3,
       guid->Data4[0], guid->Data4[1], guid->Data4[2],
       guid->Data4[3], guid->Data4[4], guid->Data4[5],
       guid->Data4[6], guid->Data4[7]);
-  GB_WSU_SAFE_SWPRINTF_TERMINATE(guid_string,
-                                 sizeof(guid_string) / sizeof(guid_string[0]));
+
+  // remove when VC++7.1 is no longer supported
+  guid_string[sizeof(guid_string) / sizeof(guid_string[0]) - 1] = L'\0';
+
   return wstring(guid_string);
 }
 
 }  // namespace google_breakpad
--- a/toolkit/airbag/airbag/src/common/windows/http_upload.cc
+++ b/toolkit/airbag/airbag/src/common/windows/http_upload.cc
@@ -225,17 +225,20 @@ wstring HTTPUpload::GenerateMultipartBou
   static const int kBoundaryLength = 27 + 16 + 1;
 
   // Generate some random numbers to fill out the boundary
   int r0 = rand();
   int r1 = rand();
 
   wchar_t temp[kBoundaryLength];
   swprintf(temp, kBoundaryLength, L"%s%08X%08X", kBoundaryPrefix, r0, r1);
-  GB_WSU_SAFE_SWPRINTF_TERMINATE(temp, kBoundaryLength);
+
+  // remove when VC++7.1 is no longer supported
+  temp[kBoundaryLength - 1] = L'\0';
+
   return wstring(temp);
 }
 
 // static
 wstring HTTPUpload::GenerateRequestHeader(const wstring &boundary) {
   wstring header = L"Content-Type: multipart/form-data; boundary=";
   header += boundary;
   return header;
--- a/toolkit/airbag/airbag/src/common/windows/pdb_source_line_writer.cc
+++ b/toolkit/airbag/airbag/src/common/windows/pdb_source_line_writer.cc
@@ -610,17 +610,18 @@ int PDBSourceLineWriter::GetFunctionStac
       goto next_child;
     }
 
     LONG child_register_offset;
     if (FAILED(child->get_offset(&child_register_offset))) {
       goto next_child;
     }
 
-    if (FAILED(child->get_type(&child_type))) {
+    // IDiaSymbol::get_type can succeed but still pass back a NULL value.
+    if (FAILED(child->get_type(&child_type)) || !child_type) {
       goto next_child;
     }
 
     ULONGLONG child_length;
     if (FAILED(child_type->get_length(&child_length))) {
       goto next_child;
     }
 
@@ -720,36 +721,39 @@ bool PDBSourceLineWriter::GetModuleInfo(
       return false;
     }
 
     // Use the same format that the MS symbol server uses in filesystem
     // hierarchies.
     wchar_t age_string[9];
     swprintf(age_string, sizeof(age_string) / sizeof(age_string[0]),
              L"%x", age);
-    GB_WSU_SAFE_SWPRINTF_TERMINATE(age_string,
-                                   sizeof(age_string) / sizeof(age_string[0]));
+
+    // remove when VC++7.1 is no longer supported
+    age_string[sizeof(age_string) / sizeof(age_string[0]) - 1] = L'\0';
 
     info->debug_identifier = GUIDString::GUIDToSymbolServerWString(&guid);
     info->debug_identifier.append(age_string);
   } else {
     DWORD signature;
     if (FAILED(global->get_signature(&signature))) {
       return false;
     }
 
     // Use the same format that the MS symbol server uses in filesystem
     // hierarchies.
     wchar_t identifier_string[17];
     swprintf(identifier_string,
              sizeof(identifier_string) / sizeof(identifier_string[0]),
              L"%08X%x", signature, age);
-    GB_WSU_SAFE_SWPRINTF_TERMINATE(identifier_string,
-                                   sizeof(identifier_string) /
-                                       sizeof(identifier_string[0]));
+
+    // remove when VC++7.1 is no longer supported
+    identifier_string[sizeof(identifier_string) /
+                      sizeof(identifier_string[0]) - 1] = L'\0';
+
     info->debug_identifier = identifier_string;
   }
 
   CComBSTR debug_file_string;
   if (FAILED(global->get_symbolsFileName(&debug_file_string))) {
     return false;
   }
   info->debug_file =
--- a/toolkit/airbag/airbag/src/common/windows/string_utils-inl.h
+++ b/toolkit/airbag/airbag/src/common/windows/string_utils-inl.h
@@ -44,28 +44,24 @@
 // is available, in the event of oddball systems where |long long| is not
 // 64 bits wide.
 #if _MSC_VER >= 1400  // MSVC 2005/8
 #define WIN_STRING_FORMAT_LL "ll"
 #else  // MSC_VER >= 1400
 #define WIN_STRING_FORMAT_LL "I64"
 #endif  // MSC_VER >= 1400
 
-// When using swprintf, call GB_WSU_SWPRINTF_TERMINATE afterwards using the
-// first two arguments to swprintf.  This will ensure that the buffer is
-// 0-terminated.  MSVC8's swprintf always 0-terminates the buffer, so the
-// macro is a no-op.  This is done in a macro rather than a function
-// because the function approach relies on vswprintf, which is incompatible
-// with some analysis tools.
-#if _MSC_VER >= 1400 // MSVC 2005/8
-#define GB_WSU_SAFE_SWPRINTF_TERMINATE(buffer, count);
-#else  // _MSC_VER >= 1400
-#define GB_WSU_SAFE_SWPRINTF_TERMINATE(buffer, count); \
-    (buffer)[(count) - 1] = L'\0';
-#endif  // _MSC_VER >= 1400
+// A nonconforming version of swprintf, without the length argument, was
+// included with the CRT prior to MSVC8.  Although a conforming version was
+// also available via an overload, it is not reliably chosen.  _snwprintf
+// behaves as a standards-confirming swprintf should, so force the use of
+// _snwprintf when using older CRTs.
+#if _MSC_VER < 1400  // MSVC 2005/8
+#define swprintf _snwprintf
+#endif  // MSC_VER < 1400
 
 namespace google_breakpad {
 
 using std::string;
 using std::wstring;
 
 class WindowsStringUtils {
  public:
--- a/toolkit/airbag/airbag/src/google_breakpad/processor/stackwalker.h
+++ b/toolkit/airbag/airbag/src/google_breakpad/processor/stackwalker.h
@@ -98,16 +98,20 @@ class Stackwalker {
   // Information about the system that produced the minidump.  Subclasses
   // and the SymbolSupplier may find this information useful.
   const SystemInfo *system_info_;
 
   // The stack memory to walk.  Subclasses will require this region to
   // get information from the stack.
   MemoryRegion *memory_;
 
+  // A list of modules, for populating each StackFrame's module information.
+  // This field is optional and may be NULL.
+  const CodeModules *modules_;
+
  private:
   // Obtains the context frame, the innermost called procedure in a stack
   // trace.  Returns NULL on failure.  GetContextFrame allocates a new
   // StackFrame (or StackFrame subclass), ownership of which is taken by
   // the caller.
   virtual StackFrame* GetContextFrame() = 0;
 
   // Obtains a caller frame.  Each call to GetCallerFrame should return the
@@ -117,20 +121,16 @@ class Stackwalker {
   // return NULL on failure or when there are no more caller frames (when
   // the end of the stack has been reached).  GetCallerFrame allocates a new
   // StackFrame (or StackFrame subclass), ownership of which is taken by
   // the caller.
   virtual StackFrame* GetCallerFrame(
       const CallStack *stack,
       const vector< linked_ptr<StackFrameInfo> > &stack_frame_info) = 0;
 
-  // A list of modules, for populating each StackFrame's module information.
-  // This field is optional and may be NULL.
-  const CodeModules *modules_;
-
   // The optional SymbolSupplier for resolving source line info.
   SymbolSupplier *supplier_;
 
   // The SourceLineResolver implementation
   SourceLineResolverInterface *resolver_;
 };
 
 
--- a/toolkit/airbag/airbag/src/processor/stackwalker.cc
+++ b/toolkit/airbag/airbag/src/processor/stackwalker.cc
@@ -134,16 +134,19 @@ bool Stackwalker::Walk(CallStack *stack)
 // static
 Stackwalker* Stackwalker::StackwalkerForCPU(
     const SystemInfo *system_info,
     MinidumpContext *context,
     MemoryRegion *memory,
     const CodeModules *modules,
     SymbolSupplier *supplier,
     SourceLineResolverInterface *resolver) {
+  if (!context)
+    return NULL;
+
   Stackwalker *cpu_stackwalker = NULL;
 
   u_int32_t cpu = context->GetContextCPU();
   switch (cpu) {
     case MD_CONTEXT_X86:
       cpu_stackwalker = new StackwalkerX86(system_info,
                                            context->GetContextX86(),
                                            memory, modules, supplier,
--- a/toolkit/airbag/airbag/src/processor/stackwalker_x86.cc
+++ b/toolkit/airbag/airbag/src/processor/stackwalker_x86.cc
@@ -33,16 +33,17 @@
 //
 // Author: Mark Mentovai
 
 
 #include "processor/postfix_evaluator-inl.h"
 
 #include "processor/stackwalker_x86.h"
 #include "google_breakpad/processor/call_stack.h"
+#include "google_breakpad/processor/code_modules.h"
 #include "google_breakpad/processor/memory_region.h"
 #include "google_breakpad/processor/stack_frame_cpu.h"
 #include "processor/linked_ptr.h"
 #include "processor/stack_frame_info.h"
 
 namespace google_breakpad {
 
 
@@ -158,25 +159,33 @@ StackFrame* StackwalkerX86::GetCallerFra
     // from other debugging data.
     dictionary[".cbParams"] = last_frame_info->parameter_size;
   }
 
   // Decide what type of program string to use.  The program string is in
   // postfix notation and will be passed to PostfixEvaluator::Evaluate.
   // Given the dictionary and the program string, it is possible to compute
   // the return address and the values of other registers in the calling
-  // function.
+  // function.  When encountering a nontraditional frame (one which takes
+  // advantage of FPO), the stack may need to be scanned for these values.
+  // For traditional frames, simple deterministic dereferencing suffices
+  // without any need for scanning.  The results of program string evaluation
+  // will be used to determine whether to scan for better values.
   string program_string;
+  bool traditional_frame = true;
+  bool recover_ebp = true;
   if (last_frame_info && last_frame_info->valid == StackFrameInfo::VALID_ALL) {
     // FPO data available.
+    traditional_frame = false;
     if (!last_frame_info->program_string.empty()) {
       // The FPO data has its own program string, which will tell us how to
       // get to the caller frame, and may even fill in the values of
       // nonvolatile registers and provide pointers to local variables and
-      // parameters.
+      // parameters.  In some cases, particularly with program strings that use
+      // .raSearchStart, the stack may need to be scanned afterward.
       program_string = last_frame_info->program_string;
     } else if (last_frame_info->allocates_base_pointer) {
       // The function corresponding to the last frame doesn't use the frame
       // pointer for conventional purposes, but it does allocate a new
       // frame pointer and use it for its own purposes.  Its callee's
       // information is still accessed relative to %esp, and the previous
       // value of %ebp can be recovered from a location in its stack frame,
       // within the saved-register area.
@@ -192,16 +201,25 @@ StackFrame* StackwalkerX86::GetCallerFra
       // (%esp).  The return address is recovered from the memory location
       // above the known sizes of the callee's parameters, saved registers,
       // and locals.  The caller's stack pointer (the value of %esp when
       // the caller executed CALL) is the location immediately above the
       // saved return address.  The saved value of %ebp to be restored for
       // the caller is at a known location in the saved-register area of
       // the stack frame.
       //
+      // For this type of frame, MSVC 14 (from Visual Studio 8/2005) in
+      // link-time code generation mode (/LTCG and /GL) can generate erroneous
+      // debugging data.  The reported size of saved registers can be 0,
+      // which is clearly an error because these frames must, at the very
+      // least, save %ebp.  For this reason, in addition to those given above
+      // about the use of .raSearchStart, the stack may need to be scanned
+      // for a better return address and a better frame pointer after the
+      // program string is evaluated.
+      //
       // %eip_new = *(%esp_old + callee_params + saved_regs + locals)
       // %ebp_new = *(%esp_old + callee_params + saved_regs - 8)
       // %esp_new = %esp_old + callee_params + saved_regs + locals + 4
       program_string = "$eip .raSearchStart ^ = "
                        "$ebp $esp .cbCalleeParams + .cbSavedRegs + 8 - ^ = "
                        "$esp .raSearchStart 4 + =";
     } else {
       // The function corresponding to the last frame doesn't use %ebp at
@@ -212,22 +230,28 @@ StackFrame* StackwalkerX86::GetCallerFra
       // The called procedure's instruction pointer and stack pointer are
       // recovered in the same way as the case above, except that no
       // frame pointer (%ebp) is used at all, so it is not saved anywhere
       // in the callee's stack frame and does not need to be recovered.
       // Because %ebp wasn't used in the callee, whatever value it has
       // is the value that it had in the caller, so it can be carried
       // straight through without bringing its validity into question.
       //
+      // Because of the use of .raSearchStart, the stack will possibly be
+      // examined to locate a better return address after program string
+      // evaluation.  The stack will not be examined to locate a saved
+      // %ebp value, because these frames do not save (or use) %ebp.
+      //
       // %eip_new = *(%esp_old + callee_params + saved_regs + locals)
       // %esp_new = %esp_old + callee_params + saved_regs + locals + 4
       // %ebp_new = %ebp_old
       program_string = "$eip .raSearchStart ^ = "
                        "$esp .raSearchStart 4 + = "
                        "$ebp $ebp =";
+      recover_ebp = false;
     }
   } else {
     // No FPO information is available for the last frame.  Assume that the
     // standard %ebp-using x86 calling convention is in use.
     //
     // The typical x86 calling convention, when frame pointers are present,
     // is for the calling procedure to use CALL, which pushes the return
     // address onto the stack and sets the instruction pointer (%eip) to
@@ -239,16 +263,20 @@ StackFrame* StackwalkerX86::GetCallerFra
     // address is always available at the memory location immediately above
     // the address pointed to by the called procedure's frame pointer.  The
     // calling procedure's stack pointer (%esp) is 8 higher than the value
     // of the called procedure's frame pointer at the time the calling
     // procedure made the CALL: 4 bytes for the return address pushed by the
     // CALL itself, and 4 bytes for the callee's PUSH of the caller's frame
     // pointer.
     //
+    // Instruction and frame pointer recovery for these traditional frames is
+    // entirely deterministic, and the stack will not be scanned after
+    // recovering these values.
+    //
     // %eip_new = *(%ebp_old + 4)
     // %esp_new = %ebp_old + 8
     // %ebp_new = *(%ebp_old)
     program_string = "$eip $ebp 4 + ^ = "
                      "$esp $ebp 8 + = "
                      "$ebp $ebp ^ =";
   }
 
@@ -259,16 +287,101 @@ StackFrame* StackwalkerX86::GetCallerFra
   PostfixEvaluator<u_int32_t>::DictionaryValidityType dictionary_validity;
   if (!evaluator.Evaluate(program_string, &dictionary_validity) ||
       dictionary_validity.find("$eip") == dictionary_validity.end() ||
       dictionary_validity.find("$esp") == dictionary_validity.end() ||
       dictionary_validity.find("$ebp") == dictionary_validity.end()) {
     return NULL;
   }
 
+  // If this stack frame did not use %ebp in a traditional way, locating the
+  // return address isn't entirely deterministic.  In that case, the stack
+  // can be scanned to locate the return address.
+  //
+  // Even in nontraditional frames, if program string evaluation resulted in
+  // both %eip and %ebp values of 0, trust that the end of the stack has been
+  // reached and don't scan for anything else.
+  if (!traditional_frame &&
+      (dictionary["$eip"] != 0 || dictionary["$ebp"] != 0)) {
+    int offset = 0;
+
+    // This scan can only be done if a CodeModules object is available, to
+    // check that candidate return addresses are in fact inside a module.
+    //
+    // TODO(mmentovai): This ignores dynamically-generated code.  One possible
+    // solution is to check the minidump's memory map to see if the candidate
+    // %eip value comes from a mapped executable page, although this would
+    // require dumps that contain MINIDUMP_MEMORY_INFO, which the Breakpad
+    // client doesn't currently write (it would need to call MiniDumpWriteDump
+    // with the MiniDumpWithFullMemoryInfo type bit set).  Even given this
+    // ability, older OSes (pre-XP SP2) and CPUs (pre-P4) don't enforce
+    // an independent execute privilege on memory pages.
+
+    u_int32_t eip = dictionary["$eip"];
+    if (modules_ && !modules_->GetModuleForAddress(eip)) {
+      const int kRASearchWords = 15;
+
+      // The instruction pointer at .raSearchStart was invalid, so start
+      // looking one 32-bit word above that location.
+      u_int32_t location_start = dictionary[".raSearchStart"] + 4;
+
+      for (u_int32_t location = location_start;
+           location <= location_start + kRASearchWords * 4;
+           location += 4) {
+        if (!memory_->GetMemoryAtAddress(location, &eip))
+          break;
+
+        if (modules_->GetModuleForAddress(eip)) {
+          // This is a better return address that what program string
+          // evaluation found.  Use it, and set %esp to the location above the
+          // one where the return address was found.
+          //
+          // TODO(mmentovai): The return-address check can be made even
+          // stronger in modules for which debugging data is available.  In
+          // that case, it's possible to check that the candidate return
+          // address is inside a known function.
+
+          dictionary["$eip"] = eip;
+          dictionary["$esp"] = location + 4;
+          offset = location - location_start;
+          break;
+        }
+      }
+    }
+
+    // When trying to recover the previous value of the frame pointer (%ebp),
+    // start looking at the lowest possible address in the saved-register
+    // area, and look at the entire saved register area, increased by the
+    // size of |offset| to account for additional data that may be on the
+    // stack.  The scan is performed from the highest possible address to
+    // the lowest, because we expect that the function's prolog would have
+    // saved %ebp early.
+    u_int32_t ebp = dictionary["$ebp"];
+    u_int32_t value;  // throwaway variable to check pointer validity
+    if (recover_ebp && !memory_->GetMemoryAtAddress(ebp, &value)) {
+      int fp_search_bytes = last_frame_info->saved_register_size + offset;
+      u_int32_t location_end = last_frame->context.esp +
+                               last_frame_callee_parameter_size;
+
+      for (u_int32_t location = location_end + fp_search_bytes;
+           location >= location_end;
+           location -= 4) {
+        if (!memory_->GetMemoryAtAddress(location, &ebp))
+          break;
+
+        if (memory_->GetMemoryAtAddress(ebp, &value)) {
+          // The candidate value is a pointer to the same memory region
+          // (the stack).  Prefer it as a recovered %ebp result.
+          dictionary["$ebp"] = ebp;
+          break;
+        }
+      }
+    }
+  }
+
   // Treat an instruction address of 0 as end-of-stack.  Treat incorrect stack
   // direction as end-of-stack to enforce progress and avoid infinite loops.
   if (dictionary["$eip"] == 0 ||
       dictionary["$esp"] <= last_frame->context.esp) {
     return NULL;
   }
 
   // Create a new stack frame (ownership will be transferred to the caller)
--- a/toolkit/airbag/airbag/src/tools/linux/dump_syms/dump_syms.cc
+++ b/toolkit/airbag/airbag/src/tools/linux/dump_syms/dump_syms.cc
@@ -23,34 +23,30 @@
 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 #include <string>
+#include <cstdio>
 
 #include "common/linux/dump_symbols.h"
 
 using namespace google_breakpad;
 
 int main(int argc, char **argv) {
-  if (argc < 2 || argc > 3)  {
-    fprintf(stderr,
-            "Usage: %s <binary-with-stab-symbol> [output-symbol-file]\n",
-            argv[0]);
+  if (argc != 2) {
+    fprintf(stderr, "Usage: %s <binary-with-stab-symbol>\n", argv[0]);
     return 1;
   }
 
   const char *binary = argv[1];
-  std::string symbol_file(binary);
-  symbol_file += ".sym";
-  if (argc == 3)
-    symbol_file = argv[2];
 
   DumpSymbols dumper;
-  if (dumper.WriteSymbolFile(binary, symbol_file))
-    printf("Symbol file successfully written: %s\n", symbol_file.c_str());
-  else
-    printf("Failed to write symbol file.\n");
+  if (!dumper.WriteSymbolFile(binary, fileno(stdout))) {
+    fprintf(stderr, "Failed to write symbol file.\n");
+    return 1;
+  }
+
   return 0;
 }
--- a/toolkit/airbag/airbag/src/tools/linux/symupload/sym_upload.cc
+++ b/toolkit/airbag/airbag/src/tools/linux/symupload/sym_upload.cc
@@ -70,22 +70,22 @@ static void TokenizeByChar(const std::st
       results->push_back(source_string.substr(cur_pos, next_pos - cur_pos));
     cur_pos = next_pos + 1;
   }
   if (cur_pos < source_string.size() && next_pos != cur_pos)
     results->push_back(source_string.substr(cur_pos));
 }
 
 //=============================================================================
-// Parse out the module line which have 6 parts.
-// MODULE <os> <cpu> <uuid> <age> <module-name>
+// Parse out the module line which have 5 parts.
+// MODULE <os> <cpu> <uuid> <module-name>
 static bool ModuleDataForSymbolFile(const std::string &file,
                                     std::vector<std::string> *module_parts) {
   assert(module_parts);
-  const size_t kModulePartNumber = 6;
+  const size_t kModulePartNumber = 5;
   FILE *fp = fopen(file.c_str(), "r");
   if (fp) {
     char buffer[1024];
     if (fgets(buffer, sizeof(buffer), fp)) {
       std::string line(buffer);
       std::string::size_type line_break_pos = line.find_first_of('\n');
       if (line_break_pos == std::string::npos) {
         assert(!"The file is invalid!");
@@ -100,51 +100,47 @@ static bool ModuleDataForSymbolFile(cons
     }
     fclose(fp);
   }
 
   return module_parts->size() == kModulePartNumber;
 }
 
 //=============================================================================
-static std::string CompactIdentifier(const std::string &uuid,
-                                     const std::string &age) {
+static std::string CompactIdentifier(const std::string &uuid) {
   std::vector<std::string> components;
   TokenizeByChar(uuid, '-', &components);
   std::string result;
   for (size_t i = 0; i < components.size(); ++i)
     result += components[i];
-  result += age;
   return result;
 }
 
 //=============================================================================
 static void Start(Options *options) {
   std::map<std::string, std::string> parameters;
   options->success = false;
   std::vector<std::string> module_parts;
   if (!ModuleDataForSymbolFile(options->symbolsPath, &module_parts)) {
     fprintf(stderr, "Failed to parse symbol file!\n");
     return;
   }
 
-  std::string compacted_id = CompactIdentifier(module_parts[3],
-                                               module_parts[4]);
+  std::string compacted_id = CompactIdentifier(module_parts[3]);
 
   // Add parameters
   if (!options->version.empty())
     parameters["version"] = options->version;
 
-  // MODULE <os> <cpu> <uuid> <age> <module-name>
-  // 0      1    2     3      4     5
-  parameters["age"] = "1";
+  // MODULE <os> <cpu> <uuid> <module-name>
+  // 0      1    2     3      4
   parameters["os"] = module_parts[1];
   parameters["cpu"] = module_parts[2];
-  parameters["debug_file"] = module_parts[5];
-  parameters["code_file"] = module_parts[5];
+  parameters["debug_file"] = module_parts[4];
+  parameters["code_file"] = module_parts[4];
   parameters["debug_identifier"] = compacted_id;
   std::string response;
   bool success = HTTPUpload::SendRequest(options->uploadURLStr,
                                          parameters,
                                          options->symbolsPath,
                                          "symbol_file",
                                          options->proxy,
                                          options->proxy_user_pwd,
--- a/toolkit/airbag/airbag/src/tools/mac/crash_report/crash_report.xcodeproj/project.pbxproj
+++ b/toolkit/airbag/airbag/src/tools/mac/crash_report/crash_report.xcodeproj/project.pbxproj
@@ -2,16 +2,18 @@
 {
 	archiveVersion = 1;
 	classes = {
 	};
 	objectVersion = 42;
 	objects = {
 
 /* Begin PBXBuildFile section */
+		557800400BE1F28500EC23E0 /* macho_utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = 5578003E0BE1F28500EC23E0 /* macho_utilities.cc */; };
+		557800410BE1F28500EC23E0 /* macho_utilities.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 5578003F0BE1F28500EC23E0 /* macho_utilities.h */; };
 		8DD76F9A0486AA7600D96B5E /* crash_report.mm in Sources */ = {isa = PBXBuildFile; fileRef = 08FB7796FE84155DC02AAC07 /* crash_report.mm */; settings = {ATTRIBUTES = (); }; };
 		8DD76F9C0486AA7600D96B5E /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 08FB779EFE84155DC02AAC07 /* Foundation.framework */; };
 		9B35FEE40B2675F9008DE8C7 /* code_module.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 9B35FEE20B2675F9008DE8C7 /* code_module.h */; };
 		9B35FEE50B2675F9008DE8C7 /* code_modules.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 9B35FEE30B2675F9008DE8C7 /* code_modules.h */; };
 		9B35FEE90B26761C008DE8C7 /* basic_code_module.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 9B35FEE60B26761C008DE8C7 /* basic_code_module.h */; };
 		9B35FEEA0B26761C008DE8C7 /* basic_code_modules.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9B35FEE70B26761C008DE8C7 /* basic_code_modules.cc */; };
 		9B35FEEB0B26761C008DE8C7 /* basic_code_modules.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 9B35FEE80B26761C008DE8C7 /* basic_code_modules.h */; };
 		9B3904960B2E52D90059FABE /* basic_source_line_resolver.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 9B3904940B2E52D90059FABE /* basic_source_line_resolver.h */; };
@@ -60,24 +62,27 @@
 				9B35FEE90B26761C008DE8C7 /* basic_code_module.h in CopyFiles */,
 				9B35FEEB0B26761C008DE8C7 /* basic_code_modules.h in CopyFiles */,
 				9B3904960B2E52D90059FABE /* basic_source_line_resolver.h in CopyFiles */,
 				9B3904970B2E52D90059FABE /* source_line_resolver_interface.h in CopyFiles */,
 				9BE650B30B52FE3000611104 /* file_id.h in CopyFiles */,
 				9BE650B50B52FE3000611104 /* macho_id.h in CopyFiles */,
 				9BE650B70B52FE3000611104 /* macho_walker.h in CopyFiles */,
 				9B44619E0B66C66B00BBB817 /* system_info.h in CopyFiles */,
+				557800410BE1F28500EC23E0 /* macho_utilities.h in CopyFiles */,
 			);
 			runOnlyForDeploymentPostprocessing = 1;
 		};
 /* End PBXCopyFilesBuildPhase section */
 
 /* Begin PBXFileReference section */
 		08FB7796FE84155DC02AAC07 /* crash_report.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = crash_report.mm; sourceTree = "<group>"; };
 		08FB779EFE84155DC02AAC07 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; };
+		5578003E0BE1F28500EC23E0 /* macho_utilities.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = macho_utilities.cc; path = ../../../common/mac/macho_utilities.cc; sourceTree = SOURCE_ROOT; };
+		5578003F0BE1F28500EC23E0 /* macho_utilities.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = macho_utilities.h; path = ../../../common/mac/macho_utilities.h; sourceTree = SOURCE_ROOT; };
 		8DD76FA10486AA7600D96B5E /* crash_report */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = crash_report; sourceTree = BUILT_PRODUCTS_DIR; };
 		9B35FEE20B2675F9008DE8C7 /* code_module.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = code_module.h; path = ../../../google_breakpad/processor/code_module.h; sourceTree = SOURCE_ROOT; };
 		9B35FEE30B2675F9008DE8C7 /* code_modules.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = code_modules.h; path = ../../../google_breakpad/processor/code_modules.h; sourceTree = SOURCE_ROOT; };
 		9B35FEE60B26761C008DE8C7 /* basic_code_module.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = basic_code_module.h; path = ../../../processor/basic_code_module.h; sourceTree = SOURCE_ROOT; };
 		9B35FEE70B26761C008DE8C7 /* basic_code_modules.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = basic_code_modules.cc; path = ../../../processor/basic_code_modules.cc; sourceTree = SOURCE_ROOT; };
 		9B35FEE80B26761C008DE8C7 /* basic_code_modules.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = basic_code_modules.h; path = ../../../processor/basic_code_modules.h; sourceTree = SOURCE_ROOT; };
 		9B3904940B2E52D90059FABE /* basic_source_line_resolver.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = basic_source_line_resolver.h; sourceTree = "<group>"; };
 		9B3904950B2E52D90059FABE /* source_line_resolver_interface.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = source_line_resolver_interface.h; sourceTree = "<group>"; };
@@ -128,16 +133,18 @@
 			runOnlyForDeploymentPostprocessing = 0;
 		};
 /* End PBXFrameworksBuildPhase section */
 
 /* Begin PBXGroup section */
 		08FB7794FE84155DC02AAC07 /* crash_report */ = {
 			isa = PBXGroup;
 			children = (
+				5578003E0BE1F28500EC23E0 /* macho_utilities.cc */,
+				5578003F0BE1F28500EC23E0 /* macho_utilities.h */,
 				9BDF192D0B1BC15D00F8391B /* dump_syms.h */,
 				9BDF192E0B1BC15D00F8391B /* dump_syms.mm */,
 				08FB7796FE84155DC02AAC07 /* crash_report.mm */,
 				9BDF176B0B1B8CB100F8391B /* on_demand_symbol_supplier.h */,
 				9BDF176C0B1B8CB100F8391B /* on_demand_symbol_supplier.mm */,
 				08FB7795FE84155DC02AAC07 /* breakpad */,
 				08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */,
 				1AB674ADFE9D54B511CA2CBB /* Products */,
@@ -299,16 +306,17 @@
 				9BDF176E0B1B8CB100F8391B /* on_demand_symbol_supplier.mm in Sources */,
 				9BDF1A280B1BD58200F8391B /* pathname_stripper.cc in Sources */,
 				9BDF21A70B1E825400F8391B /* dump_syms.mm in Sources */,
 				9B35FEEA0B26761C008DE8C7 /* basic_code_modules.cc in Sources */,
 				9B3904990B2E52FD0059FABE /* basic_source_line_resolver.cc in Sources */,
 				9BE650B20B52FE3000611104 /* file_id.cc in Sources */,
 				9BE650B40B52FE3000611104 /* macho_id.cc in Sources */,
 				9BE650B60B52FE3000611104 /* macho_walker.cc in Sources */,
+				557800400BE1F28500EC23E0 /* macho_utilities.cc in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
 /* End PBXSourcesBuildPhase section */
 
 /* Begin XCBuildConfiguration section */
 		1DEB927508733DD40010E9CD /* Debug */ = {
 			isa = XCBuildConfiguration;
--- a/toolkit/airbag/airbag/src/tools/mac/dump_syms/dump_syms.xcodeproj/project.pbxproj
+++ b/toolkit/airbag/airbag/src/tools/mac/dump_syms/dump_syms.xcodeproj/project.pbxproj
@@ -2,16 +2,18 @@
 {
 	archiveVersion = 1;
 	classes = {
 	};
 	objectVersion = 42;
 	objects = {
 
 /* Begin PBXBuildFile section */
+		5578008B0BE1F3AB00EC23E0 /* macho_utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = 557800890BE1F3AB00EC23E0 /* macho_utilities.cc */; };
+		5578008C0BE1F3AB00EC23E0 /* macho_utilities.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 5578008A0BE1F3AB00EC23E0 /* macho_utilities.h */; };
 		8DD76F9A0486AA7600D96B5E /* dump_syms.mm in Sources */ = {isa = PBXBuildFile; fileRef = 08FB7796FE84155DC02AAC07 /* dump_syms.mm */; settings = {ATTRIBUTES = (); }; };
 		8DD76F9C0486AA7600D96B5E /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 08FB779EFE84155DC02AAC07 /* Foundation.framework */; };
 		9BDF186F0B1BB43700F8391B /* dump_syms.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 9BDF186D0B1BB43700F8391B /* dump_syms.h */; };
 		9BDF18700B1BB43700F8391B /* dump_syms_tool.m in Sources */ = {isa = PBXBuildFile; fileRef = 9BDF186E0B1BB43700F8391B /* dump_syms_tool.m */; };
 		9BE650470B52F6D800611104 /* file_id.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BE650410B52F6D800611104 /* file_id.cc */; };
 		9BE650480B52F6D800611104 /* file_id.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 9BE650420B52F6D800611104 /* file_id.h */; };
 		9BE650490B52F6D800611104 /* macho_id.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BE650430B52F6D800611104 /* macho_id.cc */; };
 		9BE6504A0B52F6D800611104 /* macho_id.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 9BE650440B52F6D800611104 /* macho_id.h */; };
@@ -25,24 +27,27 @@
 			buildActionMask = 8;
 			dstPath = /usr/share/man/man1/;
 			dstSubfolderSpec = 0;
 			files = (
 				9BDF186F0B1BB43700F8391B /* dump_syms.h in CopyFiles */,
 				9BE650480B52F6D800611104 /* file_id.h in CopyFiles */,
 				9BE6504A0B52F6D800611104 /* macho_id.h in CopyFiles */,
 				9BE6504C0B52F6D800611104 /* macho_walker.h in CopyFiles */,
+				5578008C0BE1F3AB00EC23E0 /* macho_utilities.h in CopyFiles */,
 			);
 			runOnlyForDeploymentPostprocessing = 1;
 		};
 /* End PBXCopyFilesBuildPhase section */
 
 /* Begin PBXFileReference section */
 		08FB7796FE84155DC02AAC07 /* dump_syms.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = dump_syms.mm; path = ../../../common/mac/dump_syms.mm; sourceTree = "<group>"; };
 		08FB779EFE84155DC02AAC07 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; };
+		557800890BE1F3AB00EC23E0 /* macho_utilities.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = macho_utilities.cc; path = ../../../common/mac/macho_utilities.cc; sourceTree = SOURCE_ROOT; };
+		5578008A0BE1F3AB00EC23E0 /* macho_utilities.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = macho_utilities.h; path = ../../../common/mac/macho_utilities.h; sourceTree = SOURCE_ROOT; };
 		8DD76FA10486AA7600D96B5E /* dump_syms */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = dump_syms; sourceTree = BUILT_PRODUCTS_DIR; };
 		9BDF186D0B1BB43700F8391B /* dump_syms.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dump_syms.h; path = ../../../common/mac/dump_syms.h; sourceTree = "<group>"; };
 		9BDF186E0B1BB43700F8391B /* dump_syms_tool.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = dump_syms_tool.m; sourceTree = "<group>"; };
 		9BE650410B52F6D800611104 /* file_id.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = file_id.cc; path = ../../../common/mac/file_id.cc; sourceTree = SOURCE_ROOT; };
 		9BE650420B52F6D800611104 /* file_id.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = file_id.h; path = ../../../common/mac/file_id.h; sourceTree = SOURCE_ROOT; };
 		9BE650430B52F6D800611104 /* macho_id.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = macho_id.cc; path = ../../../common/mac/macho_id.cc; sourceTree = SOURCE_ROOT; };
 		9BE650440B52F6D800611104 /* macho_id.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = macho_id.h; path = ../../../common/mac/macho_id.h; sourceTree = SOURCE_ROOT; };
 		9BE650450B52F6D800611104 /* macho_walker.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = macho_walker.cc; path = ../../../common/mac/macho_walker.cc; sourceTree = SOURCE_ROOT; };
@@ -59,16 +64,18 @@
 			runOnlyForDeploymentPostprocessing = 0;
 		};
 /* End PBXFrameworksBuildPhase section */
 
 /* Begin PBXGroup section */
 		08FB7794FE84155DC02AAC07 /* dump_syms */ = {
 			isa = PBXGroup;
 			children = (
+				557800890BE1F3AB00EC23E0 /* macho_utilities.cc */,
+				5578008A0BE1F3AB00EC23E0 /* macho_utilities.h */,
 				9BE650410B52F6D800611104 /* file_id.cc */,
 				9BE650420B52F6D800611104 /* file_id.h */,
 				9BE650430B52F6D800611104 /* macho_id.cc */,
 				9BE650440B52F6D800611104 /* macho_id.h */,
 				9BE650450B52F6D800611104 /* macho_walker.cc */,
 				9BE650460B52F6D800611104 /* macho_walker.h */,
 				9BDF186D0B1BB43700F8391B /* dump_syms.h */,
 				08FB7796FE84155DC02AAC07 /* dump_syms.mm */,
@@ -136,16 +143,17 @@
 			isa = PBXSourcesBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
 				8DD76F9A0486AA7600D96B5E /* dump_syms.mm in Sources */,
 				9BDF18700B1BB43700F8391B /* dump_syms_tool.m in Sources */,
 				9BE650470B52F6D800611104 /* file_id.cc in Sources */,
 				9BE650490B52F6D800611104 /* macho_id.cc in Sources */,
 				9BE6504B0B52F6D800611104 /* macho_walker.cc in Sources */,
+				5578008B0BE1F3AB00EC23E0 /* macho_utilities.cc in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
 /* End PBXSourcesBuildPhase section */
 
 /* Begin XCBuildConfiguration section */
 		1DEB927508733DD40010E9CD /* Debug */ = {
 			isa = XCBuildConfiguration;
--- a/toolkit/airbag/airbag/src/tools/mac/dump_syms/dump_syms_tool.m
+++ b/toolkit/airbag/airbag/src/tools/mac/dump_syms/dump_syms_tool.m
@@ -29,16 +29,17 @@
 
 // dump_syms_tool.m: Command line tool that uses the DumpSymbols class.
 // TODO(waylonis): accept stdin
 
 #include <unistd.h>
 #include <mach-o/arch.h>
 
 #include "dump_syms.h"
+#include "common/mac/macho_utilities.h"
 
 typedef struct {
   NSString *srcPath;
   NSString *arch;
   NSString *uuidStr;
   BOOL result;
 } Options;
 
--- a/toolkit/airbag/airbag/src/tools/mac/symupload/symupload.xcodeproj/project.pbxproj
+++ b/toolkit/airbag/airbag/src/tools/mac/symupload/symupload.xcodeproj/project.pbxproj
@@ -26,17 +26,17 @@
 			);
 			runOnlyForDeploymentPostprocessing = 1;
 		};
 /* End PBXCopyFilesBuildPhase section */
 
 /* Begin PBXFileReference section */
 		08FB7796FE84155DC02AAC07 /* symupload.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = symupload.m; sourceTree = "<group>"; };
 		08FB779EFE84155DC02AAC07 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; };
-		8DD76FA10486AA7600D96B5E /* symupload */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = "compiled.mach-o.executable"; path = symupload; sourceTree = BUILT_PRODUCTS_DIR; };
+		8DD76FA10486AA7600D96B5E /* symupload */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = symupload; sourceTree = BUILT_PRODUCTS_DIR; };
 		9BD833680B03E4080055103E /* HTTPMultipartUpload.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HTTPMultipartUpload.h; path = ../../../common/mac/HTTPMultipartUpload.h; sourceTree = "<group>"; };
 		9BD833690B03E4080055103E /* HTTPMultipartUpload.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = HTTPMultipartUpload.m; path = ../../../common/mac/HTTPMultipartUpload.m; sourceTree = "<group>"; };
 		9BD835FB0B0544950055103E /* minidump_upload */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = minidump_upload; sourceTree = BUILT_PRODUCTS_DIR; };
 		9BD836000B0544BA0055103E /* minidump_upload.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = minidump_upload.m; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
 		8DD76F9B0486AA7600D96B5E /* Frameworks */ = {
--- a/toolkit/airbag/airbag/src/tools/windows/symupload/symupload.cc
+++ b/toolkit/airbag/airbag/src/tools/windows/symupload/symupload.cc
@@ -92,18 +92,20 @@ static bool GetFileVersionString(const w
   VS_FIXEDFILEINFO *file_info =
     reinterpret_cast<VS_FIXEDFILEINFO*>(file_info_buffer);
   swprintf(ver_string, sizeof(ver_string) / sizeof(ver_string[0]),
            L"%d.%d.%d.%d",
            file_info->dwFileVersionMS >> 16,
            file_info->dwFileVersionMS & 0xffff,
            file_info->dwFileVersionLS >> 16,
            file_info->dwFileVersionLS & 0xffff);
-  GB_WSU_SAFE_SWPRINTF_TERMINATE(ver_string,
-                                 sizeof(ver_string) / sizeof(ver_string[0]));
+
+  // remove when VC++7.1 is no longer supported
+  ver_string[sizeof(ver_string) / sizeof(ver_string[0]) - 1] = L'\0';
+
   *version = ver_string;
   return true;
 }
 
 // Creates a new temporary file and writes the symbol data from the given
 // exe/dll file to it.  Returns the path to the temp file in temp_file_path
 // and information about the pdb in pdb_info.
 static bool DumpSymbolsToTempFile(const wchar_t *file,