aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorwaylonis <waylonis@4c0a9323-5329-0410-9bdc-e9ce6186880e>2006-12-18 23:59:48 +0000
committerwaylonis <waylonis@4c0a9323-5329-0410-9bdc-e9ce6186880e>2006-12-18 23:59:48 +0000
commitb65dce60f1b911e23bda2a02be36fd991c14815e (patch)
treeea2cb7e2ecbe612b8abbc53564aba1dc37b6898c
parentAdd Mac tools directories. (diff)
downloadbreakpad-b65dce60f1b911e23bda2a02be36fd991c14815e.tar.xz
Add crash_report tool that will:
- Generate local symbol file for module - Output minidump report in a format similar to Apple's crash reporter git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@93 4c0a9323-5329-0410-9bdc-e9ce6186880e
-rw-r--r--src/tools/mac/crash_report/crash_report.mm330
-rw-r--r--src/tools/mac/crash_report/crash_report.xcodeproj/project.pbxproj358
-rw-r--r--src/tools/mac/crash_report/on_demand_symbol_supplier.h92
-rw-r--r--src/tools/mac/crash_report/on_demand_symbol_supplier.mm178
4 files changed, 958 insertions, 0 deletions
diff --git a/src/tools/mac/crash_report/crash_report.mm b/src/tools/mac/crash_report/crash_report.mm
new file mode 100644
index 00000000..bd026cf1
--- /dev/null
+++ b/src/tools/mac/crash_report/crash_report.mm
@@ -0,0 +1,330 @@
+//
+// 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.
+
+// crash_report.mm: Convert the contents of a minidump into a format that
+// looks more like Apple's CrashReporter format
+
+#include <unistd.h>
+
+#include <mach/machine.h>
+#include <mach-o/arch.h>
+
+#include <string>
+
+#include <Foundation/Foundation.h>
+
+#include "google_airbag/processor/basic_source_line_resolver.h"
+#include "google_airbag/processor/call_stack.h"
+#include "google_airbag/processor/code_module.h"
+#include "google_airbag/processor/minidump.h"
+#include "google_airbag/processor/minidump_processor.h"
+#include "google_airbag/processor/process_state.h"
+#include "google_airbag/processor/stack_frame_cpu.h"
+#include "processor/pathname_stripper.h"
+#include "processor/scoped_ptr.h"
+#include "processor/simple_symbol_supplier.h"
+
+#include "on_demand_symbol_supplier.h"
+
+using std::string;
+
+using google_airbag::BasicSourceLineResolver;
+using google_airbag::CallStack;
+using google_airbag::CodeModule;
+using google_airbag::CodeModules;
+using google_airbag::MinidumpProcessor;
+using google_airbag::OnDemandSymbolSupplier;
+using google_airbag::PathnameStripper;
+using google_airbag::ProcessState;
+using google_airbag::scoped_ptr;
+using google_airbag::StackFrame;
+using google_airbag::StackFramePPC;
+using google_airbag::StackFrameX86;
+
+typedef struct {
+ NSString *minidumpPath;
+ NSString *searchDir;
+} Options;
+
+//=============================================================================
+static int PrintRegister(const char *name, u_int32_t value, int sequence) {
+ if (sequence % 4 == 0) {
+ printf("\n");
+ }
+ printf("%6s = 0x%08x ", name, value);
+ return ++sequence;
+}
+
+//=============================================================================
+static void PrintStack(const CallStack *stack, const string &cpu) {
+ int frame_count = stack->frames()->size();
+ char buffer[1024];
+ for (int frame_index = 0; frame_index < frame_count; ++frame_index) {
+ const StackFrame *frame = stack->frames()->at(frame_index);
+ const CodeModule *module = frame->module;
+ printf("%2d ", frame_index);
+
+ if (module) {
+ // Module name (20 chars max)
+ strcpy(buffer, PathnameStripper::File(module->code_file()).c_str());
+ int maxStr = 20;
+ buffer[maxStr] = 0;
+ printf("%-*s", maxStr, buffer);
+ u_int64_t instruction = frame->instruction;
+
+ // PPC only: Adjust the instruction to match that of Crash reporter. The
+ // instruction listed is actually the return address. See the detailed
+ // comments in stackwalker_ppc.cc for more information.
+ if (cpu == "ppc" && frame_index)
+ instruction += 4;
+
+ printf(" 0x%08llx ", instruction);
+
+ // Function name
+ if (!frame->function_name.empty()) {
+ printf("%s", frame->function_name.c_str());
+ if (!frame->source_file_name.empty()) {
+ string source_file = PathnameStripper::File(frame->source_file_name);
+ printf(" + 0x%llx (%s:%d)",
+ instruction - frame->source_line_base,
+ source_file.c_str(), frame->source_line);
+ } else {
+ printf(" + 0x%llx", instruction - frame->function_base);
+ }
+ }
+ }
+ printf("\n");
+ }
+}
+
+//=============================================================================
+static void PrintRegisters(const CallStack *stack, const string &cpu) {
+ int sequence = 0;
+ const StackFrame *frame = stack->frames()->at(0);
+ if (cpu == "x86") {
+ const StackFrameX86 *frame_x86 =
+ reinterpret_cast<const StackFrameX86*>(frame);
+
+ if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_EIP)
+ sequence = PrintRegister("eip", frame_x86->context.eip, sequence);
+ if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_ESP)
+ sequence = PrintRegister("esp", frame_x86->context.esp, sequence);
+ if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_EBP)
+ sequence = PrintRegister("ebp", frame_x86->context.ebp, sequence);
+ if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_EBX)
+ sequence = PrintRegister("ebx", frame_x86->context.ebx, sequence);
+ if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_ESI)
+ sequence = PrintRegister("esi", frame_x86->context.esi, sequence);
+ if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_EDI)
+ sequence = PrintRegister("edi", frame_x86->context.edi, sequence);
+ if (frame_x86->context_validity == StackFrameX86::CONTEXT_VALID_ALL) {
+ sequence = PrintRegister("eax", frame_x86->context.eax, sequence);
+ sequence = PrintRegister("ecx", frame_x86->context.ecx, sequence);
+ sequence = PrintRegister("edx", frame_x86->context.edx, sequence);
+ sequence = PrintRegister("efl", frame_x86->context.eflags, sequence);
+ }
+ } else if (cpu == "ppc") {
+ const StackFramePPC *frame_ppc =
+ reinterpret_cast<const StackFramePPC*>(frame);
+
+ if (frame_ppc->context_validity & StackFramePPC::CONTEXT_VALID_ALL ==
+ StackFramePPC::CONTEXT_VALID_ALL) {
+ sequence = PrintRegister("srr0", frame_ppc->context.srr0, sequence);
+ sequence = PrintRegister("srr1", frame_ppc->context.srr1, sequence);
+ sequence = PrintRegister("cr", frame_ppc->context.cr, sequence);
+ sequence = PrintRegister("xer", frame_ppc->context.xer, sequence);
+ sequence = PrintRegister("lr", frame_ppc->context.lr, sequence);
+ sequence = PrintRegister("ctr", frame_ppc->context.ctr, sequence);
+ sequence = PrintRegister("mq", frame_ppc->context.mq, sequence);
+ sequence = PrintRegister("vrsave", frame_ppc->context.vrsave, sequence);
+
+ sequence = 0;
+ char buffer[5];
+ for (int i = 0; i < MD_CONTEXT_PPC_GPR_COUNT; ++i) {
+ sprintf(buffer, "r%d", i);
+ sequence = PrintRegister(buffer, frame_ppc->context.gpr[i], sequence);
+ }
+ } else {
+ if (frame_ppc->context_validity & StackFramePPC::CONTEXT_VALID_SRR0)
+ sequence = PrintRegister("srr0", frame_ppc->context.srr0, sequence);
+ if (frame_ppc->context_validity & StackFramePPC::CONTEXT_VALID_GPR1)
+ sequence = PrintRegister("r1", frame_ppc->context.gpr[1], sequence);
+ }
+ }
+
+ printf("\n");
+}
+
+//=============================================================================
+static void Start(Options *options) {
+ string minidump_file([options->minidumpPath fileSystemRepresentation]);
+
+ // Guess that the symbols are for our default architecture
+ const NXArchInfo *localArchInfo = NXGetLocalArchInfo();
+ string arch = "ppc";
+
+ if (!localArchInfo)
+ return;
+
+ if (localArchInfo->cputype & CPU_ARCH_ABI64)
+ arch = ((localArchInfo->cputype & ~CPU_ARCH_ABI64) == CPU_TYPE_X86) ?
+ "x86_64" : "ppc64";
+ else
+ arch = (localArchInfo->cputype == CPU_TYPE_X86) ? "x86" : "ppc";
+
+ BasicSourceLineResolver resolver;
+ string search_dir = options->searchDir ?
+ [options->searchDir fileSystemRepresentation] : "";
+ scoped_ptr<OnDemandSymbolSupplier> symbol_supplier(
+ new OnDemandSymbolSupplier(arch, search_dir));
+ scoped_ptr<MinidumpProcessor>
+ minidump_processor(new MinidumpProcessor(symbol_supplier.get(), &resolver));
+ ProcessState process_state;
+ if (minidump_processor->Process(minidump_file, &process_state) !=
+ MinidumpProcessor::PROCESS_OK) {
+ fprintf(stderr, "MinidumpProcessor::Process failed\n");
+ return;
+ }
+
+ string cpu = process_state.cpu();
+ // If the minidump is different than the default architecture
+ if (cpu != arch) {
+ symbol_supplier.reset(new OnDemandSymbolSupplier(cpu, search_dir));
+ minidump_processor.reset(new MinidumpProcessor(symbol_supplier.get(),
+ &resolver));
+
+ if (minidump_processor->Process(minidump_file, &process_state) !=
+ MinidumpProcessor::PROCESS_OK) {
+ fprintf(stderr, "MinidumpProcessor::Process failed\n");
+ return;
+ }
+ }
+
+ // Convert the time to a string
+ u_int32_t time_date_stamp = process_state.time_date_stamp();
+ struct tm timestruct;
+ gmtime_r(reinterpret_cast<time_t*>(&time_date_stamp), &timestruct);
+ char timestr[20];
+ strftime(timestr, 20, "%Y-%m-%d %H:%M:%S", &timestruct);
+ printf("Date: %s GMT\n", timestr);
+
+ string cpu_info = process_state.cpu_info();
+ printf("Operating system: %s (%s)\n", process_state.os().c_str(),
+ process_state.os_version().c_str());
+ printf("Architecture: %s\n", cpu.c_str());
+
+ if (process_state.crashed()) {
+ printf("Crash reason: %s\n", process_state.crash_reason().c_str());
+ printf("Crash address: 0x%llx\n", process_state.crash_address());
+ } else {
+ printf("No crash\n");
+ }
+
+ int requesting_thread = process_state.requesting_thread();
+ if (requesting_thread != -1) {
+ printf("\n");
+ printf("Thread %d (%s)\n",
+ requesting_thread,
+ process_state.crashed() ? "crashed" :
+ "requested dump, did not crash");
+ PrintStack(process_state.threads()->at(requesting_thread), cpu);
+ }
+
+ // Print all of the threads in the dump.
+ int thread_count = process_state.threads()->size();
+ for (int thread_index = 0; thread_index < thread_count; ++thread_index) {
+ if (thread_index != requesting_thread) {
+ // Don't print the crash thread again, it was already printed.
+ printf("\n");
+ printf("Thread %d\n", thread_index);
+ PrintStack(process_state.threads()->at(thread_index), cpu);
+ }
+ }
+
+ // Print the crashed registers
+ if (requesting_thread != -1) {
+ printf("\nThread %d:", requesting_thread);
+ PrintRegisters(process_state.threads()->at(requesting_thread), cpu);
+ }
+}
+
+//=============================================================================
+static void Usage(int argc, const char *argv[]) {
+ fprintf(stderr, "Convert a minidump to a crash report. Airbag symbol files\n");
+ fprintf(stderr, "will be used (or created if missing) in /tmp.\n");
+ fprintf(stderr, "Usage: %s [-s search-dir] minidump-file\n", argv[0]);
+ fprintf(stderr, "\t-s: Specify a search directory to use for missing modules\n");
+ fprintf(stderr, "\t-h: Usage\n");
+ fprintf(stderr, "\t-?: Usage\n");
+}
+
+//=============================================================================
+static void SetupOptions(int argc, const char *argv[], Options *options) {
+ extern int optind;
+ char ch;
+
+ while ((ch = getopt(argc, (char * const *)argv, "s:h?")) != -1) {
+ switch (ch) {
+ case 's':
+ options->searchDir = [[NSFileManager defaultManager]
+ stringWithFileSystemRepresentation:optarg
+ length:strlen(optarg)];
+ break;
+
+ case 'h':
+ case '?':
+ Usage(argc, argv);
+ exit(1);
+ break;
+ }
+ }
+
+ if ((argc - optind) != 1) {
+ fprintf(stderr, "%s: Missing minidump file\n", argv[0]);
+ Usage(argc, argv);
+ }
+
+ options->minidumpPath = [[NSFileManager defaultManager]
+ stringWithFileSystemRepresentation:argv[optind]
+ length:strlen(argv[optind])];
+}
+
+//=============================================================================
+int main (int argc, const char * argv[]) {
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ Options options;
+
+ bzero(&options, sizeof(Options));
+ SetupOptions(argc, argv, &options);
+ Start(&options);
+ [pool release];
+
+ return 0;
+}
diff --git a/src/tools/mac/crash_report/crash_report.xcodeproj/project.pbxproj b/src/tools/mac/crash_report/crash_report.xcodeproj/project.pbxproj
new file mode 100644
index 00000000..2c1eccc1
--- /dev/null
+++ b/src/tools/mac/crash_report/crash_report.xcodeproj/project.pbxproj
@@ -0,0 +1,358 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 42;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 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 */; };
+ 9B3904970B2E52D90059FABE /* source_line_resolver_interface.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 9B3904950B2E52D90059FABE /* source_line_resolver_interface.h */; };
+ 9B3904990B2E52FD0059FABE /* basic_source_line_resolver.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9B3904980B2E52FD0059FABE /* basic_source_line_resolver.cc */; };
+ 9BDF172C0B1B8B2400F8391B /* call_stack.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BDF172A0B1B8B2400F8391B /* call_stack.cc */; };
+ 9BDF172D0B1B8B2400F8391B /* minidump_processor.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BDF172B0B1B8B2400F8391B /* minidump_processor.cc */; };
+ 9BDF17410B1B8B9A00F8391B /* minidump.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BDF173F0B1B8B9A00F8391B /* minidump.cc */; };
+ 9BDF17540B1B8BF900F8391B /* stackwalker_ppc.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BDF17510B1B8BF900F8391B /* stackwalker_ppc.cc */; };
+ 9BDF17550B1B8BF900F8391B /* stackwalker_x86.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BDF17520B1B8BF900F8391B /* stackwalker_x86.cc */; };
+ 9BDF17560B1B8BF900F8391B /* stackwalker.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BDF17530B1B8BF900F8391B /* stackwalker.cc */; };
+ 9BDF175D0B1B8C1B00F8391B /* process_state.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BDF175B0B1B8C1B00F8391B /* process_state.cc */; };
+ 9BDF176D0B1B8CB100F8391B /* on_demand_symbol_supplier.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 9BDF176B0B1B8CB100F8391B /* on_demand_symbol_supplier.h */; };
+ 9BDF176E0B1B8CB100F8391B /* on_demand_symbol_supplier.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9BDF176C0B1B8CB100F8391B /* on_demand_symbol_supplier.mm */; };
+ 9BDF1A280B1BD58200F8391B /* pathname_stripper.cc in Sources */ = {isa = PBXBuildFile; fileRef = 9BDF1A270B1BD58200F8391B /* pathname_stripper.cc */; };
+ 9BDF1AB90B1BE70C00F8391B /* range_map.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 9BDF1A7B0B1BE30100F8391B /* range_map.h */; };
+ 9BDF1ABA0B1BE70D00F8391B /* range_map-inl.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 9BDF1A7A0B1BE30100F8391B /* range_map-inl.h */; };
+ 9BDF1AFC0B1BEB6300F8391B /* address_map-inl.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 9BDF1AFA0B1BEB6300F8391B /* address_map-inl.h */; };
+ 9BDF1AFD0B1BEB6300F8391B /* address_map.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 9BDF1AFB0B1BEB6300F8391B /* address_map.h */; };
+ 9BDF21A60B1E825400F8391B /* dump_syms.h in CopyFiles */ = {isa = PBXBuildFile; fileRef = 9BDF192D0B1BC15D00F8391B /* dump_syms.h */; };
+ 9BDF21A70B1E825400F8391B /* dump_syms.m in Sources */ = {isa = PBXBuildFile; fileRef = 9BDF192E0B1BC15D00F8391B /* dump_syms.m */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+ 8DD76F9E0486AA7600D96B5E /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ 9BDF176D0B1B8CB100F8391B /* on_demand_symbol_supplier.h in CopyFiles */,
+ 9BDF1AB90B1BE70C00F8391B /* range_map.h in CopyFiles */,
+ 9BDF1ABA0B1BE70D00F8391B /* range_map-inl.h in CopyFiles */,
+ 9BDF1AFC0B1BEB6300F8391B /* address_map-inl.h in CopyFiles */,
+ 9BDF1AFD0B1BEB6300F8391B /* address_map.h in CopyFiles */,
+ 9BDF21A60B1E825400F8391B /* dump_syms.h in CopyFiles */,
+ 9B35FEE40B2675F9008DE8C7 /* code_module.h in CopyFiles */,
+ 9B35FEE50B2675F9008DE8C7 /* code_modules.h in CopyFiles */,
+ 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 */,
+ );
+ 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>"; };
+ 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_airbag/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_airbag/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>"; };
+ 9B3904980B2E52FD0059FABE /* basic_source_line_resolver.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = basic_source_line_resolver.cc; path = ../../../processor/basic_source_line_resolver.cc; sourceTree = SOURCE_ROOT; };
+ 9BDF16F90B1B8ACD00F8391B /* airbag_types.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = airbag_types.h; sourceTree = "<group>"; };
+ 9BDF16FA0B1B8ACD00F8391B /* minidump_format.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = minidump_format.h; sourceTree = "<group>"; };
+ 9BDF16FC0B1B8ACD00F8391B /* call_stack.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = call_stack.h; sourceTree = "<group>"; };
+ 9BDF16FD0B1B8ACD00F8391B /* memory_region.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = memory_region.h; sourceTree = "<group>"; };
+ 9BDF16FE0B1B8ACD00F8391B /* minidump.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = minidump.h; sourceTree = "<group>"; };
+ 9BDF16FF0B1B8ACD00F8391B /* minidump_processor.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = minidump_processor.h; sourceTree = "<group>"; };
+ 9BDF17000B1B8ACD00F8391B /* process_state.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = process_state.h; sourceTree = "<group>"; };
+ 9BDF17010B1B8ACD00F8391B /* stack_frame.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = stack_frame.h; sourceTree = "<group>"; };
+ 9BDF17020B1B8ACD00F8391B /* stack_frame_cpu.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = stack_frame_cpu.h; sourceTree = "<group>"; };
+ 9BDF17030B1B8ACD00F8391B /* stackwalker.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = stackwalker.h; sourceTree = "<group>"; };
+ 9BDF17040B1B8ACD00F8391B /* symbol_supplier.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = symbol_supplier.h; sourceTree = "<group>"; };
+ 9BDF172A0B1B8B2400F8391B /* call_stack.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = call_stack.cc; path = ../../../processor/call_stack.cc; sourceTree = SOURCE_ROOT; };
+ 9BDF172B0B1B8B2400F8391B /* minidump_processor.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = minidump_processor.cc; path = ../../../processor/minidump_processor.cc; sourceTree = SOURCE_ROOT; };
+ 9BDF173F0B1B8B9A00F8391B /* minidump.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = minidump.cc; path = ../../../processor/minidump.cc; sourceTree = SOURCE_ROOT; };
+ 9BDF17510B1B8BF900F8391B /* stackwalker_ppc.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = stackwalker_ppc.cc; path = ../../../processor/stackwalker_ppc.cc; sourceTree = SOURCE_ROOT; };
+ 9BDF17520B1B8BF900F8391B /* stackwalker_x86.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = stackwalker_x86.cc; path = ../../../processor/stackwalker_x86.cc; sourceTree = SOURCE_ROOT; };
+ 9BDF17530B1B8BF900F8391B /* stackwalker.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = stackwalker.cc; path = ../../../processor/stackwalker.cc; sourceTree = SOURCE_ROOT; };
+ 9BDF175B0B1B8C1B00F8391B /* process_state.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = process_state.cc; path = ../../../processor/process_state.cc; sourceTree = SOURCE_ROOT; };
+ 9BDF176B0B1B8CB100F8391B /* on_demand_symbol_supplier.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = on_demand_symbol_supplier.h; sourceTree = "<group>"; };
+ 9BDF176C0B1B8CB100F8391B /* on_demand_symbol_supplier.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = on_demand_symbol_supplier.mm; sourceTree = "<group>"; };
+ 9BDF192D0B1BC15D00F8391B /* dump_syms.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = dump_syms.h; path = ../../../common/mac/dump_syms.h; sourceTree = SOURCE_ROOT; };
+ 9BDF192E0B1BC15D00F8391B /* dump_syms.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; name = dump_syms.m; path = ../../../common/mac/dump_syms.m; sourceTree = SOURCE_ROOT; };
+ 9BDF1A270B1BD58200F8391B /* pathname_stripper.cc */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = pathname_stripper.cc; path = ../../../processor/pathname_stripper.cc; sourceTree = SOURCE_ROOT; };
+ 9BDF1A7A0B1BE30100F8391B /* range_map-inl.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = "range_map-inl.h"; path = "../../../processor/range_map-inl.h"; sourceTree = SOURCE_ROOT; };
+ 9BDF1A7B0B1BE30100F8391B /* range_map.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = range_map.h; path = ../../../processor/range_map.h; sourceTree = SOURCE_ROOT; };
+ 9BDF1AFA0B1BEB6300F8391B /* address_map-inl.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = "address_map-inl.h"; path = "../../../processor/address_map-inl.h"; sourceTree = SOURCE_ROOT; };
+ 9BDF1AFB0B1BEB6300F8391B /* address_map.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = address_map.h; path = ../../../processor/address_map.h; sourceTree = SOURCE_ROOT; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 8DD76F9B0486AA7600D96B5E /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 8DD76F9C0486AA7600D96B5E /* Foundation.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 08FB7794FE84155DC02AAC07 /* crash_report */ = {
+ isa = PBXGroup;
+ children = (
+ 9BDF192D0B1BC15D00F8391B /* dump_syms.h */,
+ 9BDF192E0B1BC15D00F8391B /* dump_syms.m */,
+ 08FB7796FE84155DC02AAC07 /* crash_report.mm */,
+ 9BDF176B0B1B8CB100F8391B /* on_demand_symbol_supplier.h */,
+ 9BDF176C0B1B8CB100F8391B /* on_demand_symbol_supplier.mm */,
+ 08FB7795FE84155DC02AAC07 /* airbag */,
+ 08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */,
+ 1AB674ADFE9D54B511CA2CBB /* Products */,
+ );
+ name = crash_report;
+ sourceTree = "<group>";
+ };
+ 08FB7795FE84155DC02AAC07 /* airbag */ = {
+ isa = PBXGroup;
+ children = (
+ 9BDF17280B1B8B0200F8391B /* processor */,
+ 9BDF16F70B1B8ACD00F8391B /* google_airbag */,
+ );
+ name = airbag;
+ sourceTree = "<group>";
+ };
+ 08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */ = {
+ isa = PBXGroup;
+ children = (
+ 08FB779EFE84155DC02AAC07 /* Foundation.framework */,
+ );
+ name = "External Frameworks and Libraries";
+ sourceTree = "<group>";
+ };
+ 1AB674ADFE9D54B511CA2CBB /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 8DD76FA10486AA7600D96B5E /* crash_report */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 9BDF16F70B1B8ACD00F8391B /* google_airbag */ = {
+ isa = PBXGroup;
+ children = (
+ 9BDF16F80B1B8ACD00F8391B /* common */,
+ 9BDF16FB0B1B8ACD00F8391B /* processor */,
+ );
+ name = google_airbag;
+ path = ../../../google_airbag;
+ sourceTree = SOURCE_ROOT;
+ };
+ 9BDF16F80B1B8ACD00F8391B /* common */ = {
+ isa = PBXGroup;
+ children = (
+ 9BDF16F90B1B8ACD00F8391B /* airbag_types.h */,
+ 9BDF16FA0B1B8ACD00F8391B /* minidump_format.h */,
+ );
+ path = common;
+ sourceTree = "<group>";
+ };
+ 9BDF16FB0B1B8ACD00F8391B /* processor */ = {
+ isa = PBXGroup;
+ children = (
+ 9B3904940B2E52D90059FABE /* basic_source_line_resolver.h */,
+ 9B3904950B2E52D90059FABE /* source_line_resolver_interface.h */,
+ 9BDF16FC0B1B8ACD00F8391B /* call_stack.h */,
+ 9B35FEE20B2675F9008DE8C7 /* code_module.h */,
+ 9B35FEE30B2675F9008DE8C7 /* code_modules.h */,
+ 9BDF16FD0B1B8ACD00F8391B /* memory_region.h */,
+ 9BDF16FE0B1B8ACD00F8391B /* minidump.h */,
+ 9BDF16FF0B1B8ACD00F8391B /* minidump_processor.h */,
+ 9BDF17000B1B8ACD00F8391B /* process_state.h */,
+ 9BDF17010B1B8ACD00F8391B /* stack_frame.h */,
+ 9BDF17020B1B8ACD00F8391B /* stack_frame_cpu.h */,
+ 9BDF17030B1B8ACD00F8391B /* stackwalker.h */,
+ 9BDF17040B1B8ACD00F8391B /* symbol_supplier.h */,
+ );
+ path = processor;
+ sourceTree = "<group>";
+ };
+ 9BDF17280B1B8B0200F8391B /* processor */ = {
+ isa = PBXGroup;
+ children = (
+ 9B3904980B2E52FD0059FABE /* basic_source_line_resolver.cc */,
+ 9BDF1AFA0B1BEB6300F8391B /* address_map-inl.h */,
+ 9BDF1AFB0B1BEB6300F8391B /* address_map.h */,
+ 9B35FEE60B26761C008DE8C7 /* basic_code_module.h */,
+ 9B35FEE70B26761C008DE8C7 /* basic_code_modules.cc */,
+ 9B35FEE80B26761C008DE8C7 /* basic_code_modules.h */,
+ 9BDF172A0B1B8B2400F8391B /* call_stack.cc */,
+ 9BDF173F0B1B8B9A00F8391B /* minidump.cc */,
+ 9BDF172B0B1B8B2400F8391B /* minidump_processor.cc */,
+ 9BDF1A270B1BD58200F8391B /* pathname_stripper.cc */,
+ 9BDF175B0B1B8C1B00F8391B /* process_state.cc */,
+ 9BDF1A7A0B1BE30100F8391B /* range_map-inl.h */,
+ 9BDF1A7B0B1BE30100F8391B /* range_map.h */,
+ 9BDF17530B1B8BF900F8391B /* stackwalker.cc */,
+ 9BDF17510B1B8BF900F8391B /* stackwalker_ppc.cc */,
+ 9BDF17520B1B8BF900F8391B /* stackwalker_x86.cc */,
+ );
+ name = processor;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ 8DD76F960486AA7600D96B5E /* crash_report */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 1DEB927408733DD40010E9CD /* Build configuration list for PBXNativeTarget "crash_report" */;
+ buildPhases = (
+ 8DD76F990486AA7600D96B5E /* Sources */,
+ 8DD76F9B0486AA7600D96B5E /* Frameworks */,
+ 8DD76F9E0486AA7600D96B5E /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = crash_report;
+ productInstallPath = "$(HOME)/bin";
+ productName = crash_report;
+ productReference = 8DD76FA10486AA7600D96B5E /* crash_report */;
+ productType = "com.apple.product-type.tool";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 08FB7793FE84155DC02AAC07 /* Project object */ = {
+ isa = PBXProject;
+ buildConfigurationList = 1DEB927808733DD40010E9CD /* Build configuration list for PBXProject "crash_report" */;
+ hasScannedForEncodings = 1;
+ mainGroup = 08FB7794FE84155DC02AAC07 /* crash_report */;
+ projectDirPath = "";
+ targets = (
+ 8DD76F960486AA7600D96B5E /* crash_report */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 8DD76F990486AA7600D96B5E /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 8DD76F9A0486AA7600D96B5E /* crash_report.mm in Sources */,
+ 9BDF172C0B1B8B2400F8391B /* call_stack.cc in Sources */,
+ 9BDF172D0B1B8B2400F8391B /* minidump_processor.cc in Sources */,
+ 9BDF17410B1B8B9A00F8391B /* minidump.cc in Sources */,
+ 9BDF17540B1B8BF900F8391B /* stackwalker_ppc.cc in Sources */,
+ 9BDF17550B1B8BF900F8391B /* stackwalker_x86.cc in Sources */,
+ 9BDF17560B1B8BF900F8391B /* stackwalker.cc in Sources */,
+ 9BDF175D0B1B8C1B00F8391B /* process_state.cc in Sources */,
+ 9BDF176E0B1B8CB100F8391B /* on_demand_symbol_supplier.mm in Sources */,
+ 9BDF1A280B1BD58200F8391B /* pathname_stripper.cc in Sources */,
+ 9BDF21A70B1E825400F8391B /* dump_syms.m in Sources */,
+ 9B35FEEA0B26761C008DE8C7 /* basic_code_modules.cc in Sources */,
+ 9B3904990B2E52FD0059FABE /* basic_source_line_resolver.cc in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin XCBuildConfiguration section */
+ 1DEB927508733DD40010E9CD /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = NO;
+ GCC_C_LANGUAGE_STANDARD = c99;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_ENABLE_FIX_AND_CONTINUE = YES;
+ GCC_ENABLE_OBJC_EXCEPTIONS = YES;
+ GCC_MODEL_TUNING = G5;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PRECOMPILE_PREFIX_HEADER = NO;
+ INSTALL_PATH = "$(HOME)/bin";
+ PRODUCT_NAME = crash_report;
+ USER_HEADER_SEARCH_PATHS = "../../../../** $(inherited)";
+ ZERO_LINK = NO;
+ };
+ name = Debug;
+ };
+ 1DEB927608733DD40010E9CD /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = (
+ ppc,
+ i386,
+ );
+ GCC_C_LANGUAGE_STANDARD = c99;
+ GCC_ENABLE_OBJC_EXCEPTIONS = YES;
+ GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
+ GCC_MODEL_TUNING = G5;
+ GCC_PRECOMPILE_PREFIX_HEADER = NO;
+ INSTALL_PATH = "$(HOME)/bin";
+ PRODUCT_NAME = crash_report;
+ USER_HEADER_SEARCH_PATHS = "../../../../** $(inherited)";
+ ZERO_LINK = NO;
+ };
+ name = Release;
+ };
+ 1DEB927908733DD40010E9CD /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ PREBINDING = NO;
+ SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk;
+ };
+ name = Debug;
+ };
+ 1DEB927A08733DD40010E9CD /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ PREBINDING = NO;
+ SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk;
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 1DEB927408733DD40010E9CD /* Build configuration list for PBXNativeTarget "crash_report" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 1DEB927508733DD40010E9CD /* Debug */,
+ 1DEB927608733DD40010E9CD /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 1DEB927808733DD40010E9CD /* Build configuration list for PBXProject "crash_report" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 1DEB927908733DD40010E9CD /* Debug */,
+ 1DEB927A08733DD40010E9CD /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 08FB7793FE84155DC02AAC07 /* Project object */;
+}
diff --git a/src/tools/mac/crash_report/on_demand_symbol_supplier.h b/src/tools/mac/crash_report/on_demand_symbol_supplier.h
new file mode 100644
index 00000000..16ab7a49
--- /dev/null
+++ b/src/tools/mac/crash_report/on_demand_symbol_supplier.h
@@ -0,0 +1,92 @@
+// 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.
+
+// on_demand_symbol_supplier.h: Provides a Symbol Supplier that will create
+// an airbag symbol file on demand.
+
+#ifndef TOOLS_MAC_CRASH_REPORT_ON_DEMAND_SYMBOL_SUPPLIER_H__
+#define TOOLS_MAC_CRASH_REPORT_ON_DEMAND_SYMBOL_SUPPLIER_H__
+
+#include <map>
+#include <string>
+#include "google_airbag/processor/symbol_supplier.h"
+
+namespace google_airbag {
+
+using std::map;
+using std::string;
+class MinidumpModule;
+
+class OnDemandSymbolSupplier : public SymbolSupplier {
+ public:
+ // |architecture| should be one of ppc, i386, x86, ppc64, x86_64
+ // |search_dir| is the directory to search for alternative symbols with
+ // the same name as the module in the minidump
+ OnDemandSymbolSupplier(const string &architecture, const string &search_dir);
+ virtual ~OnDemandSymbolSupplier() {}
+
+ // Returns the path to the symbol file for the given module.
+ virtual SymbolResult GetSymbolFile(const CodeModule *module,
+ string *symbol_file);
+
+ protected:
+ // Return symbols for this architecture
+ string architecture_;
+
+ // Search directory
+ string search_dir_;
+
+ // When we create a symbol file for a module, save the name of the module
+ // and the path to that module's symbol file.
+ map<string, string> module_file_map_;
+
+ // Return the name for |module| This will be the value used as the key
+ // to the |module_file_map_|.
+ string GetNameForModule(const CodeModule *module);
+
+ // Find the module on local system. If the module resides in a different
+ // location than the full path in the minidump, this will be the location
+ // used.
+ string GetLocalModulePath(const CodeModule *module);
+
+ // Return the full path for |module|.
+ string GetModulePath(const CodeModule *module);
+
+ // Return the path to the symbol file for |module|. If an empty string is
+ // returned, then |module| doesn't have a symbol file.
+ string GetModuleSymbolFile(const CodeModule *module);
+
+ // Generate the airbag symbol file for |module|. Return true if successful.
+ // File is generated in /tmp.
+ bool GenerateSymbolFile(const CodeModule *module);
+};
+
+} // namespace google_airbag
+
+#endif // TOOLS_MAC_CRASH_REPORT_ON_DEMAND_SYMBOL_SUPPLIER_H__
diff --git a/src/tools/mac/crash_report/on_demand_symbol_supplier.mm b/src/tools/mac/crash_report/on_demand_symbol_supplier.mm
new file mode 100644
index 00000000..d37313d7
--- /dev/null
+++ b/src/tools/mac/crash_report/on_demand_symbol_supplier.mm
@@ -0,0 +1,178 @@
+// 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.
+
+#include <sys/stat.h>
+#include <map>
+#include <string>
+
+#include "google_airbag/processor/basic_source_line_resolver.h"
+#include "google_airbag/processor/minidump.h"
+#include "processor/pathname_stripper.h"
+
+#include "on_demand_symbol_supplier.h"
+#include "dump_syms.h"
+
+using std::map;
+using std::string;
+
+using google_airbag::OnDemandSymbolSupplier;
+using google_airbag::PathnameStripper;
+using google_airbag::SymbolSupplier;
+
+OnDemandSymbolSupplier::OnDemandSymbolSupplier(const string &architecture,
+ const string &search_dir)
+ : architecture_(architecture),
+ search_dir_(search_dir) {
+}
+
+SymbolSupplier::SymbolResult
+OnDemandSymbolSupplier::GetSymbolFile(const CodeModule *module,
+ string *symbol_file) {
+ string path(GetModuleSymbolFile(module));
+
+ if (path.empty()) {
+ if (!GenerateSymbolFile(module))
+ return NOT_FOUND;
+
+ path = GetModuleSymbolFile(module);
+ }
+
+ if (path.empty())
+ return NOT_FOUND;
+
+ *symbol_file = path;
+ return FOUND;
+}
+
+string OnDemandSymbolSupplier::GetLocalModulePath(const CodeModule *module) {
+ NSFileManager *mgr = [NSFileManager defaultManager];
+ const char *moduleStr = module->code_file().c_str();
+ NSString *modulePath =
+ [mgr stringWithFileSystemRepresentation:moduleStr length:strlen(moduleStr)];
+ const char *searchStr = search_dir_.c_str();
+ NSString *searchDir =
+ [mgr stringWithFileSystemRepresentation:searchStr length:strlen(searchStr)];
+
+ if ([mgr fileExistsAtPath:modulePath])
+ return module->code_file();
+
+ // If the module is not found, try to start appending the components to the
+ // search string and stop if a file (not dir) is found or all components
+ // have been appended
+ NSArray *pathComponents = [modulePath componentsSeparatedByString:@"/"];
+ int count = [pathComponents count];
+ NSMutableString *path = [NSMutableString string];
+
+ for (int i = 0; i < count; ++i) {
+ [path setString:searchDir];
+
+ for (int j = 0; j < i + 1; ++j) {
+ int idx = count - 1 - i + j;
+ [path appendFormat:@"/%@", [pathComponents objectAtIndex:idx]];
+ }
+
+ BOOL isDir;
+ if ([mgr fileExistsAtPath:path isDirectory:&isDir] && (!isDir)) {
+ return [path fileSystemRepresentation];
+ }
+ }
+
+ return "";
+}
+
+string OnDemandSymbolSupplier::GetModulePath(const CodeModule *module) {
+ return module->code_file();
+}
+
+string OnDemandSymbolSupplier::GetNameForModule(const CodeModule *module) {
+ return PathnameStripper::File(module->code_file());
+}
+
+string OnDemandSymbolSupplier::GetModuleSymbolFile(const CodeModule *module) {
+ string name(GetNameForModule(module));
+ map<string, string>::iterator result = module_file_map_.find(name);
+
+ return (result == module_file_map_.end()) ? "" : (*result).second;
+}
+
+static float GetFileModificationTime(const char *path) {
+ float result = 0;
+ struct stat file_stat;
+ if (stat(path, &file_stat) == 0)
+ result = (float)file_stat.st_mtimespec.tv_sec +
+ (float)file_stat.st_mtimespec.tv_nsec / 1.0e9;
+
+ return result;
+}
+
+bool OnDemandSymbolSupplier::GenerateSymbolFile(const CodeModule *module) {
+ bool result = true;
+ string name = GetNameForModule(module);
+ string module_path = GetLocalModulePath(module);
+ NSString *symbol_path = [NSString stringWithFormat:@"/tmp/%s.%s.sym",
+ name.c_str(), architecture_.c_str()];
+
+ if (module_path.empty())
+ return false;
+
+ // Check if there's already a symbol file cached. Ensure that the file is
+ // newer than the module. Otherwise, generate a new one.
+ BOOL generate_file = YES;
+ if ([[NSFileManager defaultManager] fileExistsAtPath:symbol_path]) {
+ // Check if the module file is newer than the saved symbols
+ float cache_time =
+ GetFileModificationTime([symbol_path fileSystemRepresentation]);
+ float module_time =
+ GetFileModificationTime(module_path.c_str());
+
+ if (cache_time > module_time)
+ generate_file = NO;
+ }
+
+ if (generate_file) {
+ NSString *module_str = [[NSFileManager defaultManager]
+ stringWithFileSystemRepresentation:module_path.c_str()
+ length:module_path.length()];
+ DumpSymbols *dump = [[DumpSymbols alloc] initWithContentsOfFile:module_str];
+ const char *archStr = architecture_.c_str();
+ if ([dump setArchitecture:[NSString stringWithUTF8String:archStr]]) {
+ [dump writeSymbolFile:symbol_path];
+ } else {
+ printf("Architecture %s not available for %s\n", archStr, name.c_str());
+ result = false;
+ }
+ [dump release];
+ }
+
+ // Add the mapping
+ if (result)
+ module_file_map_[name] = [symbol_path fileSystemRepresentation];
+
+ return result;
+}