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
This commit is contained in:
waylonis 2006-12-18 23:59:48 +00:00
parent f755a85d93
commit b65dce60f1
4 changed files with 958 additions and 0 deletions

View File

@ -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;
}

View File

@ -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 */;
}

View File

@ -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__

View File

@ -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;
}