bug 778364 - Update Breakpad to r1064. r=upstream

This commit is contained in:
Ted Mielczarek 2012-10-08 10:16:09 -04:00
parent 220a57883c
commit de78f9bc90
31 changed files with 609 additions and 242 deletions

View File

@ -0,0 +1,11 @@
Path: ../google-breakpad-svn
URL: https://google-breakpad.googlecode.com/svn/trunk
Repository Root: https://google-breakpad.googlecode.com/svn
Repository UUID: 4c0a9323-5329-0410-9bdc-e9ce6186880e
Revision: 1064
Node Kind: directory
Schedule: normal
Last Changed Author: jimblandy
Last Changed Rev: 1064
Last Changed Date: 2012-10-05 18:07:48 -0400 (Fri, 05 Oct 2012)

View File

@ -1 +0,0 @@
/usr/share/automake-1.11/compile

View File

@ -0,0 +1 @@
/usr/share/automake-1.11/compile

View File

@ -37,7 +37,7 @@ class CrashGenerationServer;
class ClientInfo {
public:
ClientInfo(pid_t pid, CrashGenerationServer* crash_server)
: crash_server_(crash_server_),
: crash_server_(crash_server),
pid_(pid) {}
CrashGenerationServer* crash_server() const { return crash_server_; }

View File

@ -60,8 +60,8 @@ const int kGUIDStringSize = 37;
void sigchld_handler(int signo) { }
int CreateTMPFile(const std::string& dir, std::string* path) {
std::string file = dir + "/exception-handler-unittest.XXXXXX";
int CreateTMPFile(const string& dir, string* path) {
string file = dir + "/exception-handler-unittest.XXXXXX";
const char* c_file = file.c_str();
// Copy that string, mkstemp needs a C string it can modify.
char* c_path = strdup(c_file);
@ -98,7 +98,7 @@ void WaitForProcessToTerminate(pid_t process_id, int expected_status) {
}
// Reads the minidump path sent over the pipe |fd| and sets it in |path|.
void ReadMinidumpPathFromPipe(int fd, std::string* path) {
void ReadMinidumpPathFromPipe(int fd, string* path) {
struct pollfd pfd;
memset(&pfd, 0, sizeof(pfd));
pfd.fd = fd;
@ -133,7 +133,7 @@ TEST(ExceptionHandlerTest, SimpleWithPath) {
TEST(ExceptionHandlerTest, SimpleWithFD) {
AutoTempDir temp_dir;
std::string path;
string path;
const int fd = CreateTMPFile(temp_dir.path(), &path);
ExceptionHandler handler(MinidumpDescriptor(fd), NULL, NULL, NULL, true, -1);
close(fd);
@ -159,7 +159,7 @@ void ChildCrash(bool use_fd) {
AutoTempDir temp_dir;
int fds[2] = {0};
int minidump_fd = -1;
std::string minidump_path;
string minidump_path;
if (use_fd) {
minidump_fd = CreateTMPFile(temp_dir.path(), &minidump_path);
} else {
@ -169,7 +169,7 @@ void ChildCrash(bool use_fd) {
const pid_t child = fork();
if (child == 0) {
{
scoped_ptr<ExceptionHandler> handler;
google_breakpad::scoped_ptr<ExceptionHandler> handler;
if (use_fd) {
handler.reset(new ExceptionHandler(MinidumpDescriptor(minidump_fd),
NULL, NULL, NULL, true, -1));
@ -222,6 +222,7 @@ static bool DoneCallbackRaiseSIGKILL(const MinidumpDescriptor& descriptor,
void* context,
bool succeeded) {
raise(SIGKILL);
return true;
}
static bool FilterCallbackReturnFalse(void* context) {
@ -916,7 +917,7 @@ TEST(ExceptionHandlerTest, WriteMinidumpExceptionStream) {
TEST(ExceptionHandlerTest, GenerateMultipleDumpsWithFD) {
AutoTempDir temp_dir;
std::string path;
string path;
const int fd = CreateTMPFile(temp_dir.path(), &path);
ExceptionHandler handler(MinidumpDescriptor(fd), NULL, NULL, NULL, false, -1);
ASSERT_TRUE(handler.WriteMinidump());
@ -941,7 +942,7 @@ TEST(ExceptionHandlerTest, GenerateMultipleDumpsWithPath) {
struct stat st;
ASSERT_EQ(0, stat(minidump_1.path(), &st));
ASSERT_GT(st.st_size, 0U);
std::string minidump_1_path(minidump_1.path());
string minidump_1_path(minidump_1.path());
// Check it is a valid minidump.
Minidump minidump1(minidump_1_path);
ASSERT_TRUE(minidump1.Read());
@ -952,7 +953,7 @@ TEST(ExceptionHandlerTest, GenerateMultipleDumpsWithPath) {
const MinidumpDescriptor& minidump_2 = handler.minidump_descriptor();
ASSERT_EQ(0, stat(minidump_2.path(), &st));
ASSERT_GT(st.st_size, 0U);
std::string minidump_2_path(minidump_2.path());
string minidump_2_path(minidump_2.path());
// Check it is a valid minidump.
Minidump minidump2(minidump_2_path);
ASSERT_TRUE(minidump2.Read());

View File

@ -62,9 +62,6 @@
#include <algorithm>
#include "client/minidump_file_writer.h"
#include "google_breakpad/common/minidump_format.h"
#include "client/linux/handler/exception_handler.h"
#include "client/linux/minidump_writer/line_reader.h"
#include "client/linux/minidump_writer/linux_dumper.h"
@ -1008,7 +1005,8 @@ class MinidumpWriter {
for (int i = 0;;) {
ElfW(Dyn) dyn;
dynamic_length += sizeof(dyn);
dumper_->CopyFromProcess(&dyn, GetCrashThread(), dynamic+i++, sizeof(dyn));
dumper_->CopyFromProcess(&dyn, GetCrashThread(), dynamic+i++,
sizeof(dyn));
if (dyn.d_tag == DT_DEBUG) {
r_debug = reinterpret_cast<struct r_debug*>(dyn.d_un.d_ptr);
continue;
@ -1083,7 +1081,7 @@ class MinidumpWriter {
debug.get()->ldbase = (void*)debug_entry.r_ldbase;
debug.get()->dynamic = dynamic;
char *dso_debug_data = new char[dynamic_length];
char* dso_debug_data = new char[dynamic_length];
dumper_->CopyFromProcess(dso_debug_data, GetCrashThread(), dynamic,
dynamic_length);
debug.CopyIndexAfterObject(0, dso_debug_data, dynamic_length);
@ -1210,8 +1208,14 @@ class MinidumpWriter {
if (space_ptr != value)
continue;
// skip past the colon and all the spaces that follow
do {
value++;
} while (my_isspace(*value));
uintptr_t val;
my_read_decimal_ptr(&val, ++value);
if (my_read_decimal_ptr(&val, value) == value)
continue;
entry->value = static_cast<int>(val);
entry->found = true;
}
@ -1223,7 +1227,7 @@ class MinidumpWriter {
if (!value)
goto popline;
// skip ':" and all the spaces that follows
// skip past the colon and all the spaces that follow
do {
value++;
} while (my_isspace(*value));

View File

@ -35,6 +35,10 @@
/* End PBXAggregateTarget section */
/* Begin PBXBuildFile section */
162F64F2161C577500CD68D5 /* arch_utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = 162F64F0161C577500CD68D5 /* arch_utilities.cc */; };
162F64F3161C577500CD68D5 /* arch_utilities.h in Headers */ = {isa = PBXBuildFile; fileRef = 162F64F1161C577500CD68D5 /* arch_utilities.h */; };
162F64F4161C579B00CD68D5 /* arch_utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = 162F64F0161C577500CD68D5 /* arch_utilities.cc */; };
162F64F5161C579B00CD68D5 /* arch_utilities.h in Sources */ = {isa = PBXBuildFile; fileRef = 162F64F1161C577500CD68D5 /* arch_utilities.h */; };
163201D61443019E00C4DBF5 /* ConfigFile.h in Headers */ = {isa = PBXBuildFile; fileRef = 163201D41443019E00C4DBF5 /* ConfigFile.h */; };
163201D71443019E00C4DBF5 /* ConfigFile.mm in Sources */ = {isa = PBXBuildFile; fileRef = 163201D51443019E00C4DBF5 /* ConfigFile.mm */; };
163201E31443029300C4DBF5 /* ConfigFile.mm in Sources */ = {isa = PBXBuildFile; fileRef = 163201D51443019E00C4DBF5 /* ConfigFile.mm */; };
@ -555,6 +559,8 @@
0867D69BFE84028FC02AAC07 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
0867D6A5FE840307C02AAC07 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; };
1058C7B1FEA5585E11CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
162F64F0161C577500CD68D5 /* arch_utilities.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = arch_utilities.cc; path = ../../common/mac/arch_utilities.cc; sourceTree = "<group>"; };
162F64F1161C577500CD68D5 /* arch_utilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = arch_utilities.h; path = ../../common/mac/arch_utilities.h; sourceTree = "<group>"; };
163201D41443019E00C4DBF5 /* ConfigFile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ConfigFile.h; path = crash_generation/ConfigFile.h; sourceTree = "<group>"; };
163201D51443019E00C4DBF5 /* ConfigFile.mm */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp; fileEncoding = 4; name = ConfigFile.mm; path = crash_generation/ConfigFile.mm; sourceTree = "<group>"; };
163202431443201300C4DBF5 /* uploader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = uploader.h; path = sender/uploader.h; sourceTree = "<group>"; };
@ -940,6 +946,8 @@
F92C53840ECCE68D009BE4BA /* mac */ = {
isa = PBXGroup;
children = (
162F64F0161C577500CD68D5 /* arch_utilities.cc */,
162F64F1161C577500CD68D5 /* arch_utilities.h */,
8B31022211F0CE1000FCF3E4 /* GTMGarbageCollection.h */,
8B31007011F0CD3C00FCF3E4 /* GTMDefines.h */,
F9C77E0F0F7DDF650045F7DB /* testing */,
@ -1142,6 +1150,7 @@
D2F9A4CC121336C7002747C1 /* crash_generation_server.h in Headers */,
163201D61443019E00C4DBF5 /* ConfigFile.h in Headers */,
16C7C918147D45AE00776EAD /* BreakpadDefines.h in Headers */,
162F64F3161C577500CD68D5 /* arch_utilities.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -1666,6 +1675,7 @@
D2F9A4CB121336C7002747C1 /* crash_generation_client.cc in Sources */,
D2F9A4CD121336C7002747C1 /* crash_generation_server.cc in Sources */,
163201D71443019E00C4DBF5 /* ConfigFile.mm in Sources */,
162F64F2161C577500CD68D5 /* arch_utilities.cc in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -1747,6 +1757,8 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
162F64F4161C579B00CD68D5 /* arch_utilities.cc in Sources */,
162F64F5161C579B00CD68D5 /* arch_utilities.h in Sources */,
D2A5DD301188633800081F03 /* breakpad_nlist_64.cc in Sources */,
F92C563F0ECD10CA009BE4BA /* convert_UTF.c in Sources */,
F92C56400ECD10CA009BE4BA /* dynamic_images.cc in Sources */,

View File

@ -475,8 +475,6 @@ void ReadImageInfo(DynamicImages& images,
mach_header_bytes) != KERN_SUCCESS)
continue;
header = reinterpret_cast<mach_header_type*>(&mach_header_bytes[0]);
// Read the file name from the task's memory space.
string file_path;
if (info.file_path_) {

View File

@ -103,11 +103,10 @@ exception_mask_t s_exception_mask = EXC_MASK_BAD_ACCESS |
EXC_MASK_BAD_INSTRUCTION | EXC_MASK_ARITHMETIC | EXC_MASK_BREAKPOINT;
#if !TARGET_OS_IPHONE
extern "C"
{
extern "C" {
// Forward declarations for functions that need "C" style compilation
boolean_t exc_server(mach_msg_header_t *request,
mach_msg_header_t *reply);
boolean_t exc_server(mach_msg_header_t* request,
mach_msg_header_t* reply);
// This symbol must be visible to dlsym() - see
// http://code.google.com/p/google-breakpad/issues/detail?id=345 for details.
@ -129,19 +128,19 @@ kern_return_t ForwardException(mach_port_t task,
#if TARGET_OS_IPHONE
// Implementation is based on the implementation generated by mig.
boolean_t breakpad_exc_server(mach_msg_header_t *InHeadP,
mach_msg_header_t *OutHeadP) {
OutHeadP->msgh_bits =
MACH_MSGH_BITS(MACH_MSGH_BITS_REMOTE(InHeadP->msgh_bits), 0);
OutHeadP->msgh_remote_port = InHeadP->msgh_remote_port;
/* Minimal size: routine() will update it if different */
OutHeadP->msgh_size = (mach_msg_size_t)sizeof(mig_reply_error_t);
OutHeadP->msgh_local_port = MACH_PORT_NULL;
OutHeadP->msgh_id = InHeadP->msgh_id + 100;
boolean_t breakpad_exc_server(mach_msg_header_t* InHeadP,
mach_msg_header_t* OutHeadP) {
OutHeadP->msgh_bits =
MACH_MSGH_BITS(MACH_MSGH_BITS_REMOTE(InHeadP->msgh_bits), 0);
OutHeadP->msgh_remote_port = InHeadP->msgh_remote_port;
/* Minimal size: routine() will update it if different */
OutHeadP->msgh_size = (mach_msg_size_t)sizeof(mig_reply_error_t);
OutHeadP->msgh_local_port = MACH_PORT_NULL;
OutHeadP->msgh_id = InHeadP->msgh_id + 100;
if (InHeadP->msgh_id != 2401) {
((mig_reply_error_t *)OutHeadP)->NDR = NDR_record;
((mig_reply_error_t *)OutHeadP)->RetCode = MIG_BAD_ID;
((mig_reply_error_t*)OutHeadP)->NDR = NDR_record;
((mig_reply_error_t*)OutHeadP)->RetCode = MIG_BAD_ID;
return FALSE;
}
@ -171,8 +170,8 @@ boolean_t breakpad_exc_server(mach_msg_header_t *InHeadP,
#pragma pack()
#endif
Request *In0P = (Request *)InHeadP;
Reply *OutP = (Reply *)OutHeadP;
Request* In0P = (Request*)InHeadP;
Reply* OutP = (Reply*)OutHeadP;
if (In0P->task.name != mach_task_self()) {
return FALSE;
@ -186,8 +185,8 @@ boolean_t breakpad_exc_server(mach_msg_header_t *InHeadP,
return TRUE;
}
#else
boolean_t breakpad_exc_server(mach_msg_header_t *request,
mach_msg_header_t *reply) {
boolean_t breakpad_exc_server(mach_msg_header_t* request,
mach_msg_header_t* reply) {
return exc_server(request, reply);
}
@ -207,9 +206,9 @@ kern_return_t catch_exception_raise(mach_port_t port, mach_port_t failed_thread,
ExceptionHandler::ExceptionHandler(const string &dump_path,
FilterCallback filter,
MinidumpCallback callback,
void *callback_context,
void* callback_context,
bool install_handler,
const char *port_name)
const char* port_name)
: dump_path_(),
filter_(filter),
callback_(callback),
@ -235,7 +234,7 @@ ExceptionHandler::ExceptionHandler(const string &dump_path,
// 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,
void* callback_context,
bool install_handler)
: dump_path_(),
filter_(NULL),
@ -287,18 +286,18 @@ bool ExceptionHandler::WriteMinidump(bool write_exception_stream) {
bool ExceptionHandler::WriteMinidump(const string &dump_path,
bool write_exception_stream,
MinidumpCallback callback,
void *callback_context) {
void* callback_context) {
ExceptionHandler handler(dump_path, NULL, callback, callback_context, false,
NULL);
NULL);
return handler.WriteMinidump(write_exception_stream);
}
// static
bool ExceptionHandler::WriteMinidumpForChild(mach_port_t child,
mach_port_t child_blamed_thread,
const string &dump_path,
MinidumpCallback callback,
void *callback_context) {
mach_port_t child_blamed_thread,
const string &dump_path,
MinidumpCallback callback,
void* callback_context) {
ScopedTaskSuspend suspend(child);
MinidumpGenerator generator(child, MACH_PORT_NULL);
@ -306,22 +305,22 @@ bool ExceptionHandler::WriteMinidumpForChild(mach_port_t child,
string dump_filename = generator.UniqueNameInDirectory(dump_path, &dump_id);
generator.SetExceptionInformation(EXC_BREAKPOINT,
#if defined (__i386__) || defined(__x86_64__)
EXC_I386_BPT,
#elif defined (__ppc__) || defined (__ppc64__)
EXC_PPC_BREAKPOINT,
#elif defined (__arm__)
EXC_ARM_BREAKPOINT,
#if defined(__i386__) || defined(__x86_64__)
EXC_I386_BPT,
#elif defined(__ppc__) || defined(__ppc64__)
EXC_PPC_BREAKPOINT,
#elif defined(__arm__)
EXC_ARM_BREAKPOINT,
#else
#error architecture not supported
#endif
0,
child_blamed_thread);
0,
child_blamed_thread);
bool result = generator.Write(dump_filename.c_str());
if (callback) {
return callback(dump_path.c_str(), dump_id.c_str(),
callback_context, result);
callback_context, result);
}
return result;
}
@ -329,7 +328,7 @@ bool ExceptionHandler::WriteMinidumpForChild(mach_port_t child,
bool ExceptionHandler::WriteMinidumpWithException(int exception_type,
int exception_code,
int exception_subcode,
ucontext_t *task_context,
ucontext_t* task_context,
mach_port_t thread_name,
bool exit_after_write,
bool report_current_thread) {
@ -350,12 +349,12 @@ bool ExceptionHandler::WriteMinidumpWithException(int exception_type,
// If this is a real exception, give the filter (if any) a chance to
// decide if this should be sent.
if (filter_ && !filter_(callback_context_))
return false;
return false;
return crash_generation_client_->RequestDumpForException(
exception_type,
exception_code,
exception_subcode,
thread_name);
exception_type,
exception_code,
exception_subcode,
thread_name);
}
#endif
} else {
@ -450,9 +449,9 @@ kern_return_t ForwardException(mach_port_t task, mach_port_t failed_thread,
}
// static
void *ExceptionHandler::WaitForMessage(void *exception_handler_class) {
ExceptionHandler *self =
reinterpret_cast<ExceptionHandler *>(exception_handler_class);
void* ExceptionHandler::WaitForMessage(void* exception_handler_class) {
ExceptionHandler* self =
reinterpret_cast<ExceptionHandler*>(exception_handler_class);
ExceptionMessage receive;
// Wait for the exception info
@ -497,11 +496,11 @@ void *ExceptionHandler::WaitForMessage(void *exception_handler_class) {
if (receive.header.msgh_id == kWriteDumpWithExceptionMessage) {
thread = receive.thread.name;
exception_type = EXC_BREAKPOINT;
#if defined (__i386__) || defined(__x86_64__)
#if defined(__i386__) || defined(__x86_64__)
exception_code = EXC_I386_BPT;
#elif defined (__ppc__) || defined (__ppc64__)
#elif defined(__ppc__) || defined(__ppc64__)
exception_code = EXC_PPC_BREAKPOINT;
#elif defined (__arm__)
#elif defined(__arm__)
exception_code = EXC_ARM_BREAKPOINT;
#else
#error architecture not supported
@ -582,7 +581,7 @@ void *ExceptionHandler::WaitForMessage(void *exception_handler_class) {
return NULL;
}
//static
// static
void ExceptionHandler::SignalHandler(int sig, siginfo_t* info, void* uc) {
#if USE_PROTECTED_ALLOCATIONS
if (gBreakpadAllocator)
@ -636,7 +635,6 @@ bool ExceptionHandler::InstallHandler() {
#else
previous_ = new ExceptionParameters();
#endif
}
catch (std::bad_alloc) {
return false;
@ -735,7 +733,7 @@ bool ExceptionHandler::Setup(bool install_handler) {
result = thread_create_result ? KERN_FAILURE : KERN_SUCCESS;
}
return result == KERN_SUCCESS ? true : false;
return result == KERN_SUCCESS;
}
bool ExceptionHandler::Teardown() {

View File

@ -31,6 +31,7 @@
#include <cstdio>
#include <mach/host_info.h>
#include <mach/machine.h>
#include <mach/vm_statistics.h>
#include <mach-o/dyld.h>
#include <mach-o/loader.h>
@ -1304,14 +1305,15 @@ bool MinidumpGenerator::WriteCVRecord(MDRawModule *module, int cpu_type,
MacFileUtilities::MachoID macho(module_path,
reinterpret_cast<void *>(module->base_of_image),
static_cast<size_t>(module->size_of_image));
result = macho.UUIDCommand(cpu_type, identifier);
result = macho.UUIDCommand(cpu_type, CPU_SUBTYPE_MULTIPLE, identifier);
if (!result)
result = macho.MD5(cpu_type, identifier);
result = macho.MD5(cpu_type, CPU_SUBTYPE_MULTIPLE, identifier);
}
if (!result) {
FileID file_id(module_path);
result = file_id.MachoIdentifier(cpu_type, identifier);
result = file_id.MachoIdentifier(cpu_type, CPU_SUBTYPE_MULTIPLE,
identifier);
}
if (result) {

View File

@ -84,6 +84,7 @@ int pthread_barrier_destroy(pthread_barrier_t *barrier) {
barrier->count = 0;
pthread_cond_destroy(&barrier->cond);
pthread_mutex_destroy(&barrier->mutex);
return 0;
}
#endif // defined(PTHREAD_BARRIER_SERIAL_THREAD)

View File

@ -39,6 +39,7 @@
#include "common/dwarf_cu_to_module.h"
#include <assert.h>
#include <cxxabi.h>
#include <inttypes.h>
#include <stdio.h>
@ -56,7 +57,7 @@ using std::set;
using std::vector;
// Data provided by a DWARF specification DIE.
//
//
// In DWARF, the DIE for a definition may contain a DW_AT_specification
// attribute giving the offset of the corresponding declaration DIE, and
// the definition DIE may omit information given in the declaration. For
@ -73,6 +74,9 @@ using std::vector;
// A Specification holds information gathered from a declaration DIE that
// we may need if we find a DW_AT_specification link pointing to it.
struct DwarfCUToModule::Specification {
// The qualified name that can be found by demangling DW_AT_MIPS_linkage_name.
string qualified_name;
// The name of the enclosing scope, or the empty string if there is none.
string enclosing_name;
@ -97,12 +101,20 @@ struct DwarfCUToModule::FilePrivate {
// A set of strings used in this CU. Before storing a string in one of
// our data structures, insert it into this set, and then use the string
// from the set.
//
// Because std::string uses reference counting internally, simply using
// strings from this set, even if passed by value, assigned, or held
// directly in structures and containers (map<string, ...>, for example),
// causes those strings to share a single instance of each distinct piece
// of text.
//
// In some STL implementations, strings are reference-counted internally,
// meaning that simply using strings from this set, even if passed by
// value, assigned, or held directly in structures and containers
// (map<string, ...>, for example), causes those strings to share a
// single instance of each distinct piece of text. GNU's libstdc++ uses
// reference counts, and I believe MSVC did as well, at some point.
// However, C++ '11 implementations are moving away from reference
// counting.
//
// In other implementations, string assignments copy the string's text,
// so this set will actually hold yet another copy of the string (although
// everything will still work). To improve memory consumption portably,
// we will probably need to use pointers to strings held in this set.
set<string> common_strings;
// A map from offsets of DIEs within the .debug_info section to
@ -218,6 +230,14 @@ class DwarfCUToModule::GenericDIEHandler: public dwarf2reader::DIEHandler {
DIEContext *parent_context_;
uint64 offset_;
// Place the name in the global set of strings. Even though this looks
// like a copy, all the major std::string implementations use reference
// counting internally, so the effect is to have all the data structures
// share copies of strings whenever possible.
// FIXME: Should this return something like a string_ref to avoid the
// assumption about how strings are implemented?
string AddStringToPool(const string &str);
// If this DIE has a DW_AT_declaration attribute, this is its value.
// It is false on DIEs with no DW_AT_declaration attribute.
bool declaration_;
@ -230,6 +250,11 @@ class DwarfCUToModule::GenericDIEHandler: public dwarf2reader::DIEHandler {
// The value of the DW_AT_name attribute, or the empty string if the
// DIE has no such attribute.
string name_attribute_;
// The demangled value of the DW_AT_MIPS_linkage_name attribute, or the empty
// string if the DIE has no such attribute or its content could not be
// demangled.
string demangled_name_;
};
void DwarfCUToModule::GenericDIEHandler::ProcessAttributeUnsigned(
@ -273,20 +298,26 @@ void DwarfCUToModule::GenericDIEHandler::ProcessAttributeReference(
}
}
string DwarfCUToModule::GenericDIEHandler::AddStringToPool(const string &str) {
pair<set<string>::iterator, bool> result =
cu_context_->file_context->file_private->common_strings.insert(str);
return *result.first;
}
void DwarfCUToModule::GenericDIEHandler::ProcessAttributeString(
enum DwarfAttribute attr,
enum DwarfForm form,
const string &data) {
switch (attr) {
case dwarf2reader::DW_AT_name: {
// Place the name in our global set of strings, and then use the
// string from the set. Even though the assignment looks like a copy,
// all the major std::string implementations use reference counting
// internally, so the effect is to have all our data structures share
// copies of strings whenever possible.
pair<set<string>::iterator, bool> result =
cu_context_->file_context->file_private->common_strings.insert(data);
name_attribute_ = *result.first;
case dwarf2reader::DW_AT_name:
name_attribute_ = AddStringToPool(data);
break;
case dwarf2reader::DW_AT_MIPS_linkage_name: {
char* demangled = abi::__cxa_demangle(data.c_str(), NULL, NULL, NULL);
if (demangled) {
demangled_name_ = AddStringToPool(demangled);
free(reinterpret_cast<void*>(demangled));
}
break;
}
default: break;
@ -294,33 +325,54 @@ void DwarfCUToModule::GenericDIEHandler::ProcessAttributeString(
}
string DwarfCUToModule::GenericDIEHandler::ComputeQualifiedName() {
// Find our unqualified name. If the DIE has its own DW_AT_name
// attribute, then use that; otherwise, check our specification.
const string *unqualified_name;
if (name_attribute_.empty() && specification_)
unqualified_name = &specification_->unqualified_name;
else
unqualified_name = &name_attribute_;
// Use the demangled name, if one is available. Demangled names are
// preferable to those inferred from the DWARF structure because they
// include argument types.
const string *qualified_name = NULL;
if (!demangled_name_.empty()) {
// Found it is this DIE.
qualified_name = &demangled_name_;
} else if (specification_ && !specification_->qualified_name.empty()) {
// Found it on the specification.
qualified_name = &specification_->qualified_name;
}
// Find the name of our enclosing context. If we have a
// specification, it's the specification's enclosing context that
// counts; otherwise, use this DIE's context.
const string *unqualified_name;
const string *enclosing_name;
if (specification_)
enclosing_name = &specification_->enclosing_name;
else
enclosing_name = &parent_context_->name;
if (!qualified_name) {
// Find our unqualified name. If the DIE has its own DW_AT_name
// attribute, then use that; otherwise, check our specification.
if (name_attribute_.empty() && specification_)
unqualified_name = &specification_->unqualified_name;
else
unqualified_name = &name_attribute_;
// Find the name of our enclosing context. If we have a
// specification, it's the specification's enclosing context that
// counts; otherwise, use this DIE's context.
if (specification_)
enclosing_name = &specification_->enclosing_name;
else
enclosing_name = &parent_context_->name;
}
// If this DIE was marked as a declaration, record its names in the
// specification table.
if (declaration_) {
FileContext *file_context = cu_context_->file_context;
Specification spec;
spec.enclosing_name = *enclosing_name;
spec.unqualified_name = *unqualified_name;
if (qualified_name)
spec.qualified_name = *qualified_name;
else {
spec.enclosing_name = *enclosing_name;
spec.unqualified_name = *unqualified_name;
}
file_context->file_private->specifications[offset_] = spec;
}
if (qualified_name)
return *qualified_name;
// Combine the enclosing name and unqualified name to produce our
// own fully-qualified name.
return cu_context_->language->MakeQualifiedName(*enclosing_name,
@ -474,7 +526,7 @@ bool DwarfCUToModule::NamedScopeHandler::EndAttributes() {
dwarf2reader::DIEHandler *DwarfCUToModule::NamedScopeHandler::FindChildHandler(
uint64 offset,
enum DwarfTag tag,
const AttributeList &attrs) {
const AttributeList &/*attrs*/) {
switch (tag) {
case dwarf2reader::DW_TAG_subprogram:
return new FuncHandler(cu_context_, &child_context_, offset);
@ -616,7 +668,7 @@ bool DwarfCUToModule::EndAttributes() {
dwarf2reader::DIEHandler *DwarfCUToModule::FindChildHandler(
uint64 offset,
enum DwarfTag tag,
const AttributeList &attrs) {
const AttributeList &/*attrs*/) {
switch (tag) {
case dwarf2reader::DW_TAG_subprogram:
return new FuncHandler(cu_context_, child_context_, offset);
@ -927,7 +979,7 @@ bool DwarfCUToModule::StartCompilationUnit(uint64 offset,
}
bool DwarfCUToModule::StartRootDIE(uint64 offset, enum DwarfTag tag,
const AttributeList& attrs) {
const AttributeList& /*attrs*/) {
// We don't deal with partial compilation units (the only other tag
// likely to be used for root DIE).
return tag == dwarf2reader::DW_TAG_compile_unit;

View File

@ -202,13 +202,15 @@ class CUFixtureBase {
// address, and size. Call EndAttributes and Finish; one cannot
// define children of the defined function's DIE.
void DefineFunction(DIEHandler *parent, const string &name,
Module::Address address, Module::Address size);
Module::Address address, Module::Address size,
const char* mangled_name);
// Create a declaration DIE as a child of PARENT with the given
// offset, tag and name. If NAME is the empty string, don't provide
// a DW_AT_name attribute. Call EndAttributes and Finish.
void DeclarationDIE(DIEHandler *parent, uint64 offset,
DwarfTag tag, const string &name);
DwarfTag tag, const string &name,
const string &mangled_name);
// Create a definition DIE as a child of PARENT with the given tag
// that refers to the declaration DIE at offset SPECIFICATION as its
@ -452,7 +454,8 @@ DIEHandler *CUFixtureBase::StartSpecifiedDIE(DIEHandler *parent,
void CUFixtureBase::DefineFunction(dwarf2reader::DIEHandler *parent,
const string &name, Module::Address address,
Module::Address size) {
Module::Address size,
const char* mangled_name) {
dwarf2reader::AttributeList func_attrs;
func_attrs.push_back(make_pair(dwarf2reader::DW_AT_name,
dwarf2reader::DW_FORM_strp));
@ -475,6 +478,11 @@ void CUFixtureBase::DefineFunction(dwarf2reader::DIEHandler *parent,
func->ProcessAttributeUnsigned(dwarf2reader::DW_AT_high_pc,
dwarf2reader::DW_FORM_addr,
address + size);
if (mangled_name)
func->ProcessAttributeString(dwarf2reader::DW_AT_MIPS_linkage_name,
dwarf2reader::DW_FORM_strp,
mangled_name);
ProcessStrangeAttributes(func);
EXPECT_TRUE(func->EndAttributes());
func->Finish();
@ -483,11 +491,14 @@ void CUFixtureBase::DefineFunction(dwarf2reader::DIEHandler *parent,
void CUFixtureBase::DeclarationDIE(DIEHandler *parent, uint64 offset,
DwarfTag tag,
const string &name) {
const string &name,
const string &mangled_name) {
dwarf2reader::AttributeList attrs;
if (!name.empty())
attrs.push_back(make_pair(dwarf2reader::DW_AT_name,
dwarf2reader::DW_FORM_strp));
attrs.push_back(make_pair(dwarf2reader::DW_AT_declaration,
dwarf2reader::DW_FORM_flag));
dwarf2reader::DIEHandler *die = parent->FindChildHandler(offset, tag, attrs);
@ -496,6 +507,11 @@ void CUFixtureBase::DeclarationDIE(DIEHandler *parent, uint64 offset,
die->ProcessAttributeString(dwarf2reader::DW_AT_name,
dwarf2reader::DW_FORM_strp,
name);
if (!mangled_name.empty())
die->ProcessAttributeString(dwarf2reader::DW_AT_MIPS_linkage_name,
dwarf2reader::DW_FORM_strp,
mangled_name);
die->ProcessAttributeUnsigned(dwarf2reader::DW_AT_declaration,
dwarf2reader::DW_FORM_flag,
1);
@ -675,8 +691,8 @@ void CUFixtureBase::TestLine(int i, int j,
#define PushLine(a,b,c,d) TRACE(PushLine((a),(b),(c),(d)))
#define SetLanguage(a) TRACE(SetLanguage(a))
#define StartCU() TRACE(StartCU())
#define DefineFunction(a,b,c,d) TRACE(DefineFunction((a),(b),(c),(d)))
#define DeclarationDIE(a,b,c,d) TRACE(DeclarationDIE((a),(b),(c),(d)))
#define DefineFunction(a,b,c,d,e) TRACE(DefineFunction((a),(b),(c),(d),(e)))
#define DeclarationDIE(a,b,c,d,e) TRACE(DeclarationDIE((a),(b),(c),(d),(e)))
#define DefinitionDIE(a,b,c,d,e,f) TRACE(DefinitionDIE((a),(b),(c),(d),(e),(f)))
#define TestFunctionCount(a) TRACE(TestFunctionCount(a))
#define TestFunction(a,b,c,d) TRACE(TestFunction((a),(b),(c),(d)))
@ -691,7 +707,7 @@ TEST_F(SimpleCU, OneFunc) {
StartCU();
DefineFunction(&root_handler_, "function1",
0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL);
0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL, NULL);
root_handler_.Finish();
TestFunctionCount(1);
@ -701,6 +717,18 @@ TEST_F(SimpleCU, OneFunc) {
246571772);
}
TEST_F(SimpleCU, MangledName) {
PushLine(0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL, "line-file", 246571772);
StartCU();
DefineFunction(&root_handler_, "function1",
0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL, "_ZN1n1fEi");
root_handler_.Finish();
TestFunctionCount(1);
TestFunction(0, "n::f(int)", 0x938cf8c07def4d34ULL, 0x55592d727f6cd01fLL);
}
TEST_F(SimpleCU, IrrelevantRootChildren) {
StartCU();
dwarf2reader::AttributeList no_attrs;
@ -805,7 +833,7 @@ TEST_F(SimpleCU, UnnamedFunction) {
StartCU();
DefineFunction(&root_handler_, "",
0x72b80e41a0ac1d40ULL, 0x537174f231ee181cULL);
0x72b80e41a0ac1d40ULL, 0x537174f231ee181cULL, NULL);
root_handler_.Finish();
TestFunctionCount(1);
@ -882,10 +910,10 @@ TEST_P(FuncLinePairing, Pairing) {
StartCU();
DefineFunction(&root_handler_, "function1",
s.functions[0].start,
s.functions[0].end - s.functions[0].start);
s.functions[0].end - s.functions[0].start, NULL);
DefineFunction(&root_handler_, "function2",
s.functions[1].start,
s.functions[1].end - s.functions[1].start);
s.functions[1].end - s.functions[1].start, NULL);
root_handler_.Finish();
TestFunctionCount(2);
@ -929,7 +957,8 @@ TEST_F(FuncLinePairing, FuncsNoLines) {
EXPECT_CALL(reporter_, UncoveredFunction(_)).WillOnce(Return());
StartCU();
DefineFunction(&root_handler_, "function1", 0x127da12ffcf5c51fULL, 0x1000U);
DefineFunction(&root_handler_, "function1", 0x127da12ffcf5c51fULL, 0x1000U,
NULL);
root_handler_.Finish();
TestFunctionCount(1);
@ -941,8 +970,8 @@ TEST_F(FuncLinePairing, GapThenFunction) {
PushLine(10, 2, "line-file-1", 263008005);
StartCU();
DefineFunction(&root_handler_, "function1", 10, 2);
DefineFunction(&root_handler_, "function2", 20, 2);
DefineFunction(&root_handler_, "function1", 10, 2, NULL);
DefineFunction(&root_handler_, "function2", 20, 2, NULL);
root_handler_.Finish();
TestFunctionCount(2);
@ -967,10 +996,10 @@ TEST_F(FuncLinePairing, GCCAlignmentStretch) {
PushLine(20, 10, "line-file", 61661044);
StartCU();
DefineFunction(&root_handler_, "function1", 10, 5);
DefineFunction(&root_handler_, "function1", 10, 5, NULL);
// five-byte gap between functions, covered by line 63351048.
// This should not elicit a warning.
DefineFunction(&root_handler_, "function2", 20, 10);
DefineFunction(&root_handler_, "function2", 20, 10, NULL);
root_handler_.Finish();
TestFunctionCount(2);
@ -991,8 +1020,8 @@ TEST_F(FuncLinePairing, LineAtEndOfAddressSpace) {
EXPECT_CALL(reporter_, UncoveredLine(_)).WillOnce(Return());
StartCU();
DefineFunction(&root_handler_, "function1", 0xfffffffffffffff0ULL, 6);
DefineFunction(&root_handler_, "function2", 0xfffffffffffffffaULL, 5);
DefineFunction(&root_handler_, "function1", 0xfffffffffffffff0ULL, 6, NULL);
DefineFunction(&root_handler_, "function2", 0xfffffffffffffffaULL, 5, NULL);
root_handler_.Finish();
TestFunctionCount(2);
@ -1012,7 +1041,7 @@ TEST_F(FuncLinePairing, WarnOnceFunc) {
EXPECT_CALL(reporter_, UncoveredFunction(_)).WillOnce(Return());
StartCU();
DefineFunction(&root_handler_, "function", 10, 11);
DefineFunction(&root_handler_, "function", 10, 11, NULL);
root_handler_.Finish();
TestFunctionCount(1);
@ -1029,8 +1058,8 @@ TEST_F(FuncLinePairing, WarnOnceLine) {
EXPECT_CALL(reporter_, UncoveredLine(_)).WillOnce(Return());
StartCU();
DefineFunction(&root_handler_, "function1", 11, 1);
DefineFunction(&root_handler_, "function2", 13, 1);
DefineFunction(&root_handler_, "function1", 11, 1, NULL);
DefineFunction(&root_handler_, "function2", 13, 1, NULL);
root_handler_.Finish();
TestFunctionCount(2);
@ -1062,8 +1091,8 @@ TEST_P(CXXQualifiedNames, TwoFunctions) {
DIEHandler *enclosure_handler = StartNamedDIE(&root_handler_, tag,
"Enclosure");
EXPECT_TRUE(enclosure_handler != NULL);
DefineFunction(enclosure_handler, "func_B", 10, 1);
DefineFunction(enclosure_handler, "func_C", 20, 1);
DefineFunction(enclosure_handler, "func_B", 10, 1, NULL);
DefineFunction(enclosure_handler, "func_C", 20, 1, NULL);
enclosure_handler->Finish();
delete enclosure_handler;
root_handler_.Finish();
@ -1087,7 +1116,7 @@ TEST_P(CXXQualifiedNames, FuncInEnclosureInNamespace) {
DIEHandler *enclosure_handler = StartNamedDIE(namespace_handler, tag,
"Enclosure");
EXPECT_TRUE(enclosure_handler != NULL);
DefineFunction(enclosure_handler, "function", 10, 1);
DefineFunction(enclosure_handler, "function", 10, 1, NULL);
enclosure_handler->Finish();
delete enclosure_handler;
namespace_handler->Finish();
@ -1114,7 +1143,7 @@ TEST_F(CXXQualifiedNames, FunctionInClassInStructInNamespace) {
DIEHandler *class_handler
= StartNamedDIE(struct_handler, dwarf2reader::DW_TAG_class_type,
"class_C");
DefineFunction(class_handler, "function_D", 10, 1);
DefineFunction(class_handler, "function_D", 10, 1, NULL);
class_handler->Finish();
delete class_handler;
struct_handler->Finish();
@ -1160,7 +1189,7 @@ TEST_P(QualifiedForLanguage, MemberFunction) {
DIEHandler *class_handler
= StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type,
"class_A");
DefineFunction(class_handler, "function_B", 10, 1);
DefineFunction(class_handler, "function_B", 10, 1, NULL);
class_handler->Finish();
delete class_handler;
root_handler_.Finish();
@ -1184,7 +1213,7 @@ TEST_P(QualifiedForLanguage, MemberFunctionSignedLanguage) {
DIEHandler *class_handler
= StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type,
"class_A");
DefineFunction(class_handler, "function_B", 10, 1);
DefineFunction(class_handler, "function_B", 10, 1, NULL);
class_handler->Finish();
delete class_handler;
root_handler_.Finish();
@ -1204,7 +1233,7 @@ TEST_F(Specifications, Function) {
StartCU();
DeclarationDIE(&root_handler_, 0xcd3c51b946fb1eeeLL,
dwarf2reader::DW_TAG_subprogram, "declaration-name");
dwarf2reader::DW_TAG_subprogram, "declaration-name", "");
DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram,
0xcd3c51b946fb1eeeLL, "",
0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL);
@ -1215,6 +1244,23 @@ TEST_F(Specifications, Function) {
0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL);
}
TEST_F(Specifications, MangledName) {
PushLine(0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL, "line-file", 54883661);
StartCU();
DeclarationDIE(&root_handler_, 0xcd3c51b946fb1eeeLL,
dwarf2reader::DW_TAG_subprogram, "declaration-name",
"_ZN1C1fEi");
DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram,
0xcd3c51b946fb1eeeLL, "",
0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL);
root_handler_.Finish();
TestFunctionCount(1);
TestFunction(0, "C::f(int)",
0x93cd3dfc1aa10097ULL, 0x0397d47a0b4ca0d4ULL);
}
TEST_F(Specifications, MemberFunction) {
PushLine(0x3341a248634e7170ULL, 0x5f6938ee5553b953ULL, "line-file", 18116691);
@ -1222,7 +1268,7 @@ TEST_F(Specifications, MemberFunction) {
DIEHandler *class_handler
= StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, "class_A");
DeclarationDIE(class_handler, 0x7d83028c431406e8ULL,
dwarf2reader::DW_TAG_subprogram, "declaration-name");
dwarf2reader::DW_TAG_subprogram, "declaration-name", "");
class_handler->Finish();
delete class_handler;
DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram,
@ -1247,7 +1293,7 @@ TEST_F(Specifications, FunctionDeclarationParent) {
"class_A");
ASSERT_TRUE(class_handler != NULL);
DeclarationDIE(class_handler, 0x0e0e877c8404544aULL,
dwarf2reader::DW_TAG_subprogram, "declaration-name");
dwarf2reader::DW_TAG_subprogram, "declaration-name", "");
class_handler->Finish();
delete class_handler;
}
@ -1275,7 +1321,8 @@ TEST_F(Specifications, NamedScopeDeclarationParent) {
"space_A");
ASSERT_TRUE(space_handler != NULL);
DeclarationDIE(space_handler, 0x419bb1d12f9a73a2ULL,
dwarf2reader::DW_TAG_class_type, "class-declaration-name");
dwarf2reader::DW_TAG_class_type, "class-declaration-name",
"");
space_handler->Finish();
delete space_handler;
}
@ -1286,7 +1333,7 @@ TEST_F(Specifications, NamedScopeDeclarationParent) {
0x419bb1d12f9a73a2ULL, "class-definition-name");
ASSERT_TRUE(class_handler != NULL);
DefineFunction(class_handler, "function",
0x5d13433d0df13d00ULL, 0x48ebebe5ade2cab4ULL);
0x5d13433d0df13d00ULL, 0x48ebebe5ade2cab4ULL, NULL);
class_handler->Finish();
delete class_handler;
}
@ -1304,7 +1351,7 @@ TEST_F(Specifications, InlineFunction) {
StartCU();
DeclarationDIE(&root_handler_, 0xcd3c51b946fb1eeeLL,
dwarf2reader::DW_TAG_subprogram, "inline-name");
dwarf2reader::DW_TAG_subprogram, "inline-name", "");
AbstractInstanceDIE(&root_handler_, 0x1e8dac5d507ed7abULL,
dwarf2reader::DW_INL_inlined, 0xcd3c51b946fb1eeeLL, "");
DefineInlineInstanceDIE(&root_handler_, "", 0x1e8dac5d507ed7abULL,
@ -1354,7 +1401,7 @@ TEST_F(Specifications, LongChain) {
= StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_namespace,
"space_A");
DeclarationDIE(space_A_handler, 0x2e111126496596e2ULL,
dwarf2reader::DW_TAG_namespace, "space_B");
dwarf2reader::DW_TAG_namespace, "space_B", "");
space_A_handler->Finish();
delete space_A_handler;
}
@ -1367,7 +1414,7 @@ TEST_F(Specifications, LongChain) {
= StartNamedDIE(space_B_handler, dwarf2reader::DW_TAG_structure_type,
"struct_C");
DeclarationDIE(struct_C_handler, 0x20cd423bf2a25a4cULL,
dwarf2reader::DW_TAG_structure_type, "struct_D");
dwarf2reader::DW_TAG_structure_type, "struct_D", "");
struct_C_handler->Finish();
delete struct_C_handler;
space_B_handler->Finish();
@ -1382,7 +1429,7 @@ TEST_F(Specifications, LongChain) {
= StartNamedDIE(struct_D_handler, dwarf2reader::DW_TAG_union_type,
"union_E");
DeclarationDIE(union_E_handler, 0xe25c84805aa58c32ULL,
dwarf2reader::DW_TAG_union_type, "union_F");
dwarf2reader::DW_TAG_union_type, "union_F", "");
union_E_handler->Finish();
delete union_E_handler;
struct_D_handler->Finish();
@ -1397,7 +1444,7 @@ TEST_F(Specifications, LongChain) {
= StartNamedDIE(union_F_handler, dwarf2reader::DW_TAG_class_type,
"class_G");
DeclarationDIE(class_G_handler, 0xb70d960dcc173b6eULL,
dwarf2reader::DW_TAG_class_type, "class_H");
dwarf2reader::DW_TAG_class_type, "class_H", "");
class_G_handler->Finish();
delete class_G_handler;
union_F_handler->Finish();
@ -1409,7 +1456,7 @@ TEST_F(Specifications, LongChain) {
= StartSpecifiedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type,
0xb70d960dcc173b6eULL);
DeclarationDIE(class_H_handler, 0x27ff829e3bf69f37ULL,
dwarf2reader::DW_TAG_subprogram, "func_I");
dwarf2reader::DW_TAG_subprogram, "func_I", "");
class_H_handler->Finish();
delete class_H_handler;
}
@ -1447,7 +1494,7 @@ TEST_F(Specifications, InterCU) {
ProcessStrangeAttributes(&root1_handler);
ASSERT_TRUE(root1_handler.EndAttributes());
DeclarationDIE(&root1_handler, 0xb8fbfdd5f0b26fceULL,
dwarf2reader::DW_TAG_class_type, "class_A");
dwarf2reader::DW_TAG_class_type, "class_A", "");
root1_handler.Finish();
}
@ -1462,7 +1509,7 @@ TEST_F(Specifications, InterCU) {
= StartSpecifiedDIE(&root2_handler, dwarf2reader::DW_TAG_class_type,
0xb8fbfdd5f0b26fceULL);
DeclarationDIE(class_A_handler, 0xb01fef8b380bd1a2ULL,
dwarf2reader::DW_TAG_subprogram, "member_func_B");
dwarf2reader::DW_TAG_subprogram, "member_func_B", "");
class_A_handler->Finish();
delete class_A_handler;
root2_handler.Finish();
@ -1494,7 +1541,7 @@ TEST_F(Specifications, BadOffset) {
StartCU();
DeclarationDIE(&root_handler_, 0xefd7f7752c27b7e4ULL,
dwarf2reader::DW_TAG_subprogram, "");
dwarf2reader::DW_TAG_subprogram, "", "");
DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram,
0x2be953efa6f9a996ULL, "function",
0xa0277efd7ce83771ULL, 0x149554a184c730c1ULL);
@ -1506,7 +1553,7 @@ TEST_F(Specifications, FunctionDefinitionHasOwnName) {
StartCU();
DeclarationDIE(&root_handler_, 0xc34ff4786cae78bdULL,
dwarf2reader::DW_TAG_subprogram, "declaration-name");
dwarf2reader::DW_TAG_subprogram, "declaration-name", "");
DefinitionDIE(&root_handler_, dwarf2reader::DW_TAG_subprogram,
0xc34ff4786cae78bdULL, "definition-name",
0xced50b3eea81022cULL, 0x08dd4d301cc7a7d2ULL);
@ -1522,7 +1569,7 @@ TEST_F(Specifications, ClassDefinitionHasOwnName) {
StartCU();
DeclarationDIE(&root_handler_, 0xd0fe467ec2f1a58cULL,
dwarf2reader::DW_TAG_class_type, "class-declaration-name");
dwarf2reader::DW_TAG_class_type, "class-declaration-name", "");
dwarf2reader::DIEHandler *class_definition
= StartSpecifiedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type,
@ -1530,7 +1577,7 @@ TEST_F(Specifications, ClassDefinitionHasOwnName) {
ASSERT_TRUE(class_definition);
DeclarationDIE(class_definition, 0x6d028229c15623dbULL,
dwarf2reader::DW_TAG_subprogram,
"function-declaration-name");
"function-declaration-name", "");
class_definition->Finish();
delete class_definition;
@ -1558,7 +1605,8 @@ TEST_F(Specifications, PreferSpecificationParents) {
dwarf2reader::DIEHandler *declaration_class_handler
= StartNamedDIE(&root_handler_, dwarf2reader::DW_TAG_class_type, "declaration-class");
DeclarationDIE(declaration_class_handler, 0x9ddb35517455ef7aULL,
dwarf2reader::DW_TAG_subprogram, "function-declaration");
dwarf2reader::DW_TAG_subprogram, "function-declaration",
"");
declaration_class_handler->Finish();
delete declaration_class_handler;
}

View File

@ -57,7 +57,7 @@ extern unsigned my_uint_len(uintmax_t i);
// Convert an unsigned integer to a string
// output: (output) the resulting string is written here. This buffer must be
// large enough to hold the resulting string. Call |my_int_len| to get the
// large enough to hold the resulting string. Call |my_uint_len| to get the
// required length.
// i: the unsigned integer to serialise.
// i_len: the length of the integer in base 10 (see |my_uint_len|).

View File

@ -19,6 +19,7 @@ LOCAL_INCLUDES = -I$(srcdir)/../..
# 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 = \
arch_utilities.cc \
bootstrap_compat.cc \
file_id.cc \
macho_id.cc \

View File

@ -0,0 +1,81 @@
// Copyright (c) 2012, 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 "common/mac/arch_utilities.h"
#include <mach-o/arch.h>
#include <stdio.h>
#include <string.h>
#ifndef CPU_TYPE_ARM
#define CPU_TYPE_ARM (static_cast<cpu_type_t>(12))
#endif // CPU_TYPE_ARM
#ifndef CPU_SUBTYPE_ARM_V7
#define CPU_SUBTYPE_ARM_V7 (static_cast<cpu_subtype_t>(9))
#endif // CPU_SUBTYPE_ARM_V7
#ifndef CPU_SUBTYPE_ARM_V7S
#define CPU_SUBTYPE_ARM_V7S (static_cast<cpu_subtype_t>(11))
#endif // CPU_SUBTYPE_ARM_V7S
namespace {
const NXArchInfo* ArchInfo_armv7s() {
NXArchInfo* armv7s = new NXArchInfo;
*armv7s = *NXGetArchInfoFromCpuType(CPU_TYPE_ARM,
CPU_SUBTYPE_ARM_V7);
armv7s->name = "armv7s";
armv7s->cpusubtype = CPU_SUBTYPE_ARM_V7S;
armv7s->description = "arm v7s";
return armv7s;
}
} // namespace
namespace google_breakpad {
const NXArchInfo* BreakpadGetArchInfoFromName(const char* arch_name) {
// TODO: Remove this when the OS knows about armv7s.
if (!strcmp("armv7s", arch_name))
return BreakpadGetArchInfoFromCpuType(CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V7S);
return NXGetArchInfoFromName(arch_name);
}
const NXArchInfo* BreakpadGetArchInfoFromCpuType(cpu_type_t cpu_type,
cpu_subtype_t cpu_subtype) {
// TODO: Remove this when the OS knows about armv7s.
if (cpu_type == CPU_TYPE_ARM && cpu_subtype == CPU_SUBTYPE_ARM_V7S) {
static const NXArchInfo* armv7s = ArchInfo_armv7s();
return armv7s;
}
return NXGetArchInfoFromCpuType(cpu_type, cpu_subtype);
}
} // namespace google_breakpad

View File

@ -0,0 +1,47 @@
// Copyright (c) 2012, 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.
// arch_utilities.h: Utilities for architecture introspection for Mac platform.
#ifndef COMMON_MAC_ARCH_UTILITIES_H__
#define COMMON_MAC_ARCH_UTILITIES_H__
#include <mach-o/arch.h>
namespace google_breakpad {
// Custom implementation of |NXGetArchInfoFromName| and
// |NXGetArchInfoFromCpuType| that handle newer CPU on older OSes.
const NXArchInfo* BreakpadGetArchInfoFromName(const char* arch_name);
const NXArchInfo* BreakpadGetArchInfoFromCpuType(cpu_type_t cpu_type,
cpu_subtype_t cpu_subtype);
} // namespace google_breakpad
#endif // COMMON_MAC_ARCH_UTILITIES_H__

View File

@ -50,6 +50,7 @@
#include "common/dwarf_cu_to_module.h"
#include "common/dwarf_line_to_module.h"
#include "common/mac/file_id.h"
#include "common/mac/arch_utilities.h"
#include "common/mac/macho_reader.h"
#include "common/module.h"
#include "common/stabs_reader.h"
@ -191,7 +192,8 @@ bool DumpSymbols::SetArchitecture(cpu_type_t cpu_type,
bool DumpSymbols::SetArchitecture(const std::string &arch_name) {
bool arch_set = false;
const NXArchInfo *arch_info = NXGetArchInfoFromName(arch_name.c_str());
const NXArchInfo *arch_info =
google_breakpad::BreakpadGetArchInfoFromName(arch_name.c_str());
if (arch_info) {
arch_set = SetArchitecture(arch_info->cputype, arch_info->cpusubtype);
}
@ -202,7 +204,8 @@ string DumpSymbols::Identifier() {
FileID file_id([object_filename_ fileSystemRepresentation]);
unsigned char identifier_bytes[16];
cpu_type_t cpu_type = selected_object_file_->cputype;
if (!file_id.MachoIdentifier(cpu_type, identifier_bytes)) {
cpu_subtype_t cpu_subtype = selected_object_file_->cpusubtype;
if (!file_id.MachoIdentifier(cpu_type, cpu_subtype, identifier_bytes)) {
fprintf(stderr, "Unable to calculate UUID of mach-o binary %s!\n",
[object_filename_ fileSystemRepresentation]);
return "";
@ -312,9 +315,8 @@ bool DumpSymbols::ReadCFI(google_breakpad::Module *module,
register_names = DwarfCFIToModule::RegisterNames::ARM();
break;
default: {
const NXArchInfo *arch =
NXGetArchInfoFromCpuType(macho_reader.cpu_type(),
macho_reader.cpu_subtype());
const NXArchInfo *arch = google_breakpad::BreakpadGetArchInfoFromCpuType(
macho_reader.cpu_type(), macho_reader.cpu_subtype());
fprintf(stderr, "%s: cannot convert DWARF call frame information for ",
selected_object_name_.c_str());
if (arch)
@ -446,9 +448,9 @@ bool DumpSymbols::WriteSymbolFile(std::ostream &stream, bool cfi) {
// Find the name of the selected file's architecture, to appear in
// the MODULE record and in error messages.
const NXArchInfo *selected_arch_info
= NXGetArchInfoFromCpuType(selected_object_file_->cputype,
selected_object_file_->cpusubtype);
const NXArchInfo *selected_arch_info =
google_breakpad::BreakpadGetArchInfoFromCpuType(
selected_object_file_->cputype, selected_object_file_->cpusubtype);
const char *selected_arch_name = selected_arch_info->name;
if (strcmp(selected_arch_name, "i386") == 0)

View File

@ -70,13 +70,15 @@ bool FileID::FileIdentifier(unsigned char identifier[16]) {
return true;
}
bool FileID::MachoIdentifier(int cpu_type, unsigned char identifier[16]) {
bool FileID::MachoIdentifier(cpu_type_t cpu_type,
cpu_subtype_t cpu_subtype,
unsigned char identifier[16]) {
MachoID macho(path_);
if (macho.UUIDCommand(cpu_type, identifier))
if (macho.UUIDCommand(cpu_type, cpu_subtype, identifier))
return true;
return macho.MD5(cpu_type, identifier);
return macho.MD5(cpu_type, cpu_subtype, identifier);
}
// static

View File

@ -35,6 +35,7 @@
#define COMMON_MAC_FILE_ID_H__
#include <limits.h>
#include <mach/machine.h>
namespace google_breakpad {
@ -50,15 +51,18 @@ class FileID {
bool FileIdentifier(unsigned char identifier[16]);
// Treat the file as a mach-o file that will contain one or more archicture.
// Accepted values for |cpu_type| (e.g., CPU_TYPE_X86 or CPU_TYPE_POWERPC)
// are listed in /usr/include/mach/machine.h.
// If |cpu_type| is 0, then the native cpu type is used.
// Returns false if opening the file failed or if the |cpu_type| is not
// present in the file.
// Accepted values for |cpu_type| and |cpu_subtype| (e.g., CPU_TYPE_X86 or
// CPU_TYPE_POWERPC) are listed in /usr/include/mach/machine.h.
// If |cpu_type| is 0, then the native cpu type is used. If |cpu_subtype| is
// CPU_SUBTYPE_MULTIPLE, the match is only done on |cpu_type|.
// Returns false if opening the file failed or if the |cpu_type|/|cpu_subtype|
// is not present in the file.
// Return the unique identifier in |identifier|.
// The current implementation will look for the (in order of priority):
// LC_UUID, LC_ID_DYLIB, or MD5 hash of the given |cpu_type|.
bool MachoIdentifier(int cpu_type, unsigned char identifier[16]);
bool MachoIdentifier(cpu_type_t cpu_type,
cpu_subtype_t cpu_subtype,
unsigned char identifier[16]);
// Convert the |identifier| data to a NULL terminated string. The string will
// be formatted as a UUID (e.g., 22F065BB-FC9C-49F7-80FE-26A7CEBD7BCE).
@ -75,4 +79,3 @@ class FileID {
} // namespace google_breakpad
#endif // COMMON_MAC_FILE_ID_H__

View File

@ -153,10 +153,12 @@ void MachoID::Update(MachoWalker *walker, off_t offset, size_t size) {
}
}
bool MachoID::UUIDCommand(int cpu_type, unsigned char bytes[16]) {
bool MachoID::UUIDCommand(cpu_type_t cpu_type,
cpu_subtype_t cpu_subtype,
unsigned char bytes[16]) {
struct breakpad_uuid_command uuid_cmd;
uuid_cmd.cmd = 0;
if (!WalkHeader(cpu_type, UUIDWalkerCB, &uuid_cmd))
if (!WalkHeader(cpu_type, cpu_subtype, UUIDWalkerCB, &uuid_cmd))
return false;
// If we found the command, we'll have initialized the uuid_command
@ -169,10 +171,12 @@ bool MachoID::UUIDCommand(int cpu_type, unsigned char bytes[16]) {
return false;
}
bool MachoID::IDCommand(int cpu_type, unsigned char identifier[16]) {
bool MachoID::IDCommand(cpu_type_t cpu_type,
cpu_subtype_t cpu_subtype,
unsigned char identifier[16]) {
struct dylib_command dylib_cmd;
dylib_cmd.cmd = 0;
if (!WalkHeader(cpu_type, IDWalkerCB, &dylib_cmd))
if (!WalkHeader(cpu_type, cpu_subtype, IDWalkerCB, &dylib_cmd))
return false;
// If we found the command, we'll have initialized the dylib_command
@ -210,37 +214,38 @@ bool MachoID::IDCommand(int cpu_type, unsigned char identifier[16]) {
return false;
}
uint32_t MachoID::Adler32(int cpu_type) {
uint32_t MachoID::Adler32(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype) {
update_function_ = &MachoID::UpdateCRC;
crc_ = 0;
if (!WalkHeader(cpu_type, WalkerCB, this))
if (!WalkHeader(cpu_type, cpu_subtype, WalkerCB, this))
return 0;
return crc_;
}
bool MachoID::MD5(int cpu_type, unsigned char identifier[16]) {
bool MachoID::MD5(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype, unsigned char identifier[16]) {
update_function_ = &MachoID::UpdateMD5;
MD5Init(&md5_context_);
if (!WalkHeader(cpu_type, WalkerCB, this))
if (!WalkHeader(cpu_type, cpu_subtype, WalkerCB, this))
return false;
MD5Final(identifier, &md5_context_);
return true;
}
bool MachoID::WalkHeader(int cpu_type,
bool MachoID::WalkHeader(cpu_type_t cpu_type,
cpu_subtype_t cpu_subtype,
MachoWalker::LoadCommandCallback callback,
void *context) {
if (memory_) {
MachoWalker walker(memory_, memory_size_, callback, context);
return walker.WalkHeader(cpu_type);
return walker.WalkHeader(cpu_type, cpu_subtype);
} else {
MachoWalker walker(path_, callback, context);
return walker.WalkHeader(cpu_type);
return walker.WalkHeader(cpu_type, cpu_subtype);
}
}

View File

@ -35,6 +35,7 @@
#define COMMON_MAC_MACHO_ID_H__
#include <limits.h>
#include <mach/machine.h>
#include <mach-o/loader.h>
#include "common/mac/macho_walker.h"
@ -48,22 +49,32 @@ class MachoID {
MachoID(const char *path, void *memory, size_t size);
~MachoID();
// For the given |cpu_type|, return a UUID from the LC_UUID command.
// For the given |cpu_type| and |cpu_subtype|, return a UUID from the LC_UUID
// command.
// Return false if there isn't a LC_UUID command.
bool UUIDCommand(int cpu_type, unsigned char identifier[16]);
bool UUIDCommand(cpu_type_t cpu_type,
cpu_subtype_t cpu_subtype,
unsigned char identifier[16]);
// For the given |cpu_type|, return a UUID from the LC_ID_DYLIB command.
// For the given |cpu_type| and |cpu_subtype|, return a UUID from the
// LC_ID_DYLIB command.
// Return false if there isn't a LC_ID_DYLIB command.
bool IDCommand(int cpu_type, unsigned char identifier[16]);
bool IDCommand(cpu_type_t cpu_type,
cpu_subtype_t cpu_subtype,
unsigned char identifier[16]);
// For the given |cpu_type|, return the Adler32 CRC for the mach-o data
// segment(s).
// For the given |cpu_type| and |cpu_subtype|, return the Adler32 CRC for the
// mach-o data segment(s).
// Return 0 on error (e.g., if the file is not a mach-o file)
uint32_t Adler32(int cpu_type);
uint32_t Adler32(cpu_type_t cpu_type,
cpu_subtype_t cpu_subtype);
// For the given |cpu_type|, return the MD5 for the mach-o data segment(s).
// For the given |cpu_type|, and |cpu_subtype| return the MD5 for the mach-o
// data segment(s).
// Return true on success, false otherwise
bool MD5(int cpu_type, unsigned char identifier[16]);
bool MD5(cpu_type_t cpu_type,
cpu_subtype_t cpu_subtype,
unsigned char identifier[16]);
private:
// Signature of class member function to be called with data read from file
@ -81,8 +92,8 @@ class MachoID {
void Update(MachoWalker *walker, off_t offset, size_t size);
// Factory for the MachoWalker
bool WalkHeader(int cpu_type, MachoWalker::LoadCommandCallback callback,
void *context);
bool WalkHeader(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype,
MachoWalker::LoadCommandCallback callback, void *context);
// The callback from the MachoWalker for CRC and MD5
static bool WalkerCB(MachoWalker *walker, load_command *cmd, off_t offset,

View File

@ -79,21 +79,18 @@ MachoWalker::~MachoWalker() {
close(file_);
}
int MachoWalker::ValidateCPUType(int cpu_type) {
// If the user didn't specify, use the local architecture.
bool MachoWalker::WalkHeader(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype) {
cpu_type_t valid_cpu_type = cpu_type;
cpu_subtype_t valid_cpu_subtype = cpu_subtype;
// if |cpu_type| is 0, use the native cpu type.
if (cpu_type == 0) {
const NXArchInfo *arch = NXGetLocalArchInfo();
assert(arch);
cpu_type = arch->cputype;
valid_cpu_type = arch->cputype;
valid_cpu_subtype = CPU_SUBTYPE_MULTIPLE;
}
return cpu_type;
}
bool MachoWalker::WalkHeader(int cpu_type) {
int valid_cpu_type = ValidateCPUType(cpu_type);
off_t offset;
if (FindHeader(valid_cpu_type, offset)) {
if (FindHeader(valid_cpu_type, valid_cpu_subtype, offset)) {
if (cpu_type & CPU_ARCH_ABI64)
return WalkHeader64AtOffset(offset);
@ -131,8 +128,9 @@ bool MachoWalker::CurrentHeader(struct mach_header_64 *header, off_t *offset) {
return false;
}
bool MachoWalker::FindHeader(int cpu_type, off_t &offset) {
int valid_cpu_type = ValidateCPUType(cpu_type);
bool MachoWalker::FindHeader(cpu_type_t cpu_type,
cpu_subtype_t cpu_subtype,
off_t &offset) {
// Read the magic bytes that's common amongst all mach-o files
uint32_t magic;
if (!ReadBytes(&magic, sizeof(magic), 0))
@ -153,15 +151,18 @@ bool MachoWalker::FindHeader(int cpu_type, off_t &offset) {
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))
struct mach_header header;
if (!ReadBytes(&header, sizeof(header), 0))
return false;
if (magic == MH_CIGAM || magic == MH_CIGAM_64)
header_cpu_type = ByteSwap(header_cpu_type);
swap_mach_header(&header, NXHostByteOrder());
if (valid_cpu_type != header_cpu_type)
if (cpu_type != header.cputype ||
(cpu_subtype != CPU_SUBTYPE_MULTIPLE &&
cpu_subtype != header.cpusubtype)) {
return false;
}
offset = 0;
return true;
@ -186,7 +187,9 @@ bool MachoWalker::FindHeader(int cpu_type, off_t &offset) {
if (NXHostByteOrder() != NX_BigEndian)
swap_fat_arch(&arch, 1, NXHostByteOrder());
if (arch.cputype == valid_cpu_type) {
if (arch.cputype == cpu_type &&
(cpu_subtype == CPU_SUBTYPE_MULTIPLE ||
arch.cpusubtype == cpu_subtype)) {
offset = arch.offset;
return true;
}

View File

@ -34,6 +34,7 @@
#ifndef COMMON_MAC_MACHO_WALKER_H__
#define COMMON_MAC_MACHO_WALKER_H__
#include <mach/machine.h>
#include <mach-o/loader.h>
#include <sys/types.h>
@ -56,16 +57,14 @@ class MachoWalker {
void *context);
~MachoWalker();
// Begin walking the header for |cpu_type|. If |cpu_type| is 0, then the
// native cpu type is used. Otherwise, accepted values are listed in
// /usr/include/mach/machine.h (e.g., CPU_TYPE_X86 or CPU_TYPE_POWERPC).
// Returns false if opening the file failed or if the |cpu_type| is not
// present in the file.
bool WalkHeader(int cpu_type);
// Locate (if any) the header offset for |cpu_type| and return in |offset|.
// Return true if found, false otherwise.
bool FindHeader(int cpu_type, off_t &offset);
// Begin walking the header for |cpu_type| and |cpu_subtype|. If |cpu_type|
// is 0, then the native cpu type is used. Otherwise, accepted values are
// listed in /usr/include/mach/machine.h (e.g., CPU_TYPE_X86 or
// CPU_TYPE_POWERPC). If |cpu_subtype| is CPU_SUBTYPE_MULTIPLE, the match is
// only done on |cpu_type|.
// Returns false if opening the file failed or if the |cpu_type|/|cpu_subtype|
// is not present in the file.
bool WalkHeader(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype);
// Read |size| bytes from the opened file at |offset| into |buffer|
bool ReadBytes(void *buffer, size_t size, off_t offset);
@ -74,8 +73,11 @@ class MachoWalker {
bool CurrentHeader(struct mach_header_64 *header, off_t *offset);
private:
// Validate the |cpu_type|
int ValidateCPUType(int cpu_type);
// Locate (if any) the header offset for |cpu_type| and return in |offset|.
// Return true if found, false otherwise.
bool FindHeader(cpu_type_t cpu_type,
cpu_subtype_t cpu_subtype,
off_t &offset);
// Process an individual header starting at |offset| from the start of the
// file. Return true if successful, false otherwise.

View File

@ -115,7 +115,7 @@ void UTF32ToUTF16Char(wchar_t in, u_int16_t out[2]) {
}
static inline u_int16_t Swap(u_int16_t value) {
return (value >> 8) | static_cast<uint16_t>(value << 8);
return (value >> 8) | static_cast<u_int16_t>(value << 8);
}
string UTF16ToUTF8(const vector<u_int16_t> &in, bool swap) {

View File

@ -80,7 +80,8 @@ typedef enum {
MD_EXCEPTION_CODE_LIN_SIGIO = 29, /* I/O now possible (4.2 BSD) */
MD_EXCEPTION_CODE_LIN_SIGPWR = 30, /* Power failure restart (System V) */
MD_EXCEPTION_CODE_LIN_SIGSYS = 31, /* Bad system call */
MD_EXCEPTION_CODE_LIN_DUMP_REQUESTED = -1 /* No exception, dump requested */
MD_EXCEPTION_CODE_LIN_DUMP_REQUESTED = 0xFFFFFFFF /* No exception,
dump requested. */
} MDExceptionCodeLinux;
#endif /* GOOGLE_BREAKPAD_COMMON_MINIDUMP_EXCEPTION_LINUX_H__ */

View File

@ -93,6 +93,16 @@ typedef enum {
/* Custom values */
MD_EXCEPTION_CODE_MAC_NS_EXCEPTION = 0xDEADC0DE, /* uncaught NSException */
/* With MD_EXCEPTION_MAC_BAD_ACCESS on arm */
MD_EXCEPTION_CODE_MAC_ARM_DA_ALIGN = 0x0101, /* EXC_ARM_DA_ALIGN */
MD_EXCEPTION_CODE_MAC_ARM_DA_DEBUG = 0x0102, /* EXC_ARM_DA_DEBUG */
/* With MD_EXCEPTION_MAC_BAD_INSTRUCTION on arm */
MD_EXCEPTION_CODE_MAC_ARM_UNDEFINED = 1, /* EXC_ARM_UNDEFINED */
/* With MD_EXCEPTION_MAC_BREAKPOINT on arm */
MD_EXCEPTION_CODE_MAC_ARM_BREAKPOINT = 1, /* EXC_ARM_BREAKPOINT */
/* With MD_EXCEPTION_MAC_BAD_ACCESS on ppc */
MD_EXCEPTION_CODE_MAC_PPC_VM_PROT_READ = 0x0101,
/* EXC_PPC_VM_PROT_READ */

View File

@ -484,26 +484,61 @@ string MinidumpProcessor::GetCrashReason(Minidump *dump, u_int64_t *address) {
case MD_EXCEPTION_CODE_MAC_MEMORY_ERROR:
reason.append("KERN_MEMORY_ERROR");
break;
// These are ppc only but shouldn't be a problem as they're
// unused on x86
case MD_EXCEPTION_CODE_MAC_PPC_VM_PROT_READ:
reason.append("EXC_PPC_VM_PROT_READ");
break;
case MD_EXCEPTION_CODE_MAC_PPC_BADSPACE:
reason.append("EXC_PPC_BADSPACE");
break;
case MD_EXCEPTION_CODE_MAC_PPC_UNALIGNED:
reason.append("EXC_PPC_UNALIGNED");
break;
default:
reason.append(flags_string);
BPLOG(INFO) << "Unknown exception reason " << reason;
// arm and ppc overlap
if (raw_system_info->processor_architecture ==
MD_CPU_ARCHITECTURE_ARM) {
switch (exception_flags) {
case MD_EXCEPTION_CODE_MAC_ARM_DA_ALIGN:
reason.append("EXC_ARM_DA_ALIGN");
break;
case MD_EXCEPTION_CODE_MAC_ARM_DA_DEBUG:
reason.append("EXC_ARM_DA_DEBUG");
break;
default:
reason.append(flags_string);
BPLOG(INFO) << "Unknown exception reason " << reason;
break;
}
} else if (raw_system_info->processor_architecture ==
MD_CPU_ARCHITECTURE_PPC) {
switch (exception_flags) {
case MD_EXCEPTION_CODE_MAC_PPC_VM_PROT_READ:
reason.append("EXC_PPC_VM_PROT_READ");
break;
case MD_EXCEPTION_CODE_MAC_PPC_BADSPACE:
reason.append("EXC_PPC_BADSPACE");
break;
case MD_EXCEPTION_CODE_MAC_PPC_UNALIGNED:
reason.append("EXC_PPC_UNALIGNED");
break;
default:
reason.append(flags_string);
BPLOG(INFO) << "Unknown exception reason " << reason;
break;
}
} else {
reason.append(flags_string);
BPLOG(INFO) << "Unknown exception reason " << reason;
}
break;
}
break;
case MD_EXCEPTION_MAC_BAD_INSTRUCTION:
reason = "EXC_BAD_INSTRUCTION / ";
switch (raw_system_info->processor_architecture) {
case MD_CPU_ARCHITECTURE_ARM: {
switch (exception_flags) {
case MD_EXCEPTION_CODE_MAC_ARM_UNDEFINED:
reason.append("EXC_ARM_UNDEFINED");
break;
default:
reason.append(flags_string);
BPLOG(INFO) << "Unknown exception reason " << reason;
break;
}
break;
}
case MD_CPU_ARCHITECTURE_PPC: {
switch (exception_flags) {
case MD_EXCEPTION_CODE_MAC_PPC_INVALID_SYSCALL:
@ -671,6 +706,24 @@ string MinidumpProcessor::GetCrashReason(Minidump *dump, u_int64_t *address) {
case MD_EXCEPTION_MAC_BREAKPOINT:
reason = "EXC_BREAKPOINT / ";
switch (raw_system_info->processor_architecture) {
case MD_CPU_ARCHITECTURE_ARM: {
switch (exception_flags) {
case MD_EXCEPTION_CODE_MAC_ARM_DA_ALIGN:
reason.append("EXC_ARM_DA_ALIGN");
break;
case MD_EXCEPTION_CODE_MAC_ARM_DA_DEBUG:
reason.append("EXC_ARM_DA_DEBUG");
break;
case MD_EXCEPTION_CODE_MAC_ARM_BREAKPOINT:
reason.append("EXC_ARM_BREAKPOINT");
break;
default:
reason.append(flags_string);
BPLOG(INFO) << "Unknown exception reason " << reason;
break;
}
break;
}
case MD_CPU_ARCHITECTURE_PPC: {
switch (exception_flags) {
case MD_EXCEPTION_CODE_MAC_PPC_BREAKPOINT:

View File

@ -7,6 +7,7 @@
objects = {
/* Begin PBXBuildFile section */
162F64FE161C5ECB00CD68D5 /* arch_utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = 162F64FC161C5ECB00CD68D5 /* arch_utilities.cc */; };
4D2C721B126F9ACC00B43EAF /* source_line_resolver_base.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C721A126F9ACC00B43EAF /* source_line_resolver_base.cc */; };
4D2C721F126F9ADE00B43EAF /* exploitability.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C721E126F9ADE00B43EAF /* exploitability.cc */; };
4D2C7223126F9AF900B43EAF /* exploitability_win.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4D2C7222126F9AF900B43EAF /* exploitability_win.cc */; };
@ -66,6 +67,8 @@
/* 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 = SDKROOT; };
162F64FC161C5ECB00CD68D5 /* arch_utilities.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = arch_utilities.cc; path = ../../../common/mac/arch_utilities.cc; sourceTree = "<group>"; };
162F64FD161C5ECB00CD68D5 /* arch_utilities.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = arch_utilities.h; path = ../../../common/mac/arch_utilities.h; sourceTree = "<group>"; };
4D2C721A126F9ACC00B43EAF /* source_line_resolver_base.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = source_line_resolver_base.cc; path = ../../../processor/source_line_resolver_base.cc; sourceTree = SOURCE_ROOT; };
4D2C721E126F9ADE00B43EAF /* exploitability.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = exploitability.cc; path = ../../../processor/exploitability.cc; sourceTree = SOURCE_ROOT; };
4D2C7222126F9AF900B43EAF /* exploitability_win.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = exploitability_win.cc; path = ../../../processor/exploitability_win.cc; sourceTree = SOURCE_ROOT; };
@ -183,6 +186,8 @@
8B3102DA11F0D65600FCF3E4 /* BreakpadDebug.xcconfig */,
8B3102DB11F0D65600FCF3E4 /* BreakpadRelease.xcconfig */,
F9C7ECE10E8ABC7F00E953AD /* DWARF */,
162F64FC161C5ECB00CD68D5 /* arch_utilities.cc */,
162F64FD161C5ECB00CD68D5 /* arch_utilities.h */,
5578003E0BE1F28500EC23E0 /* macho_utilities.cc */,
5578003F0BE1F28500EC23E0 /* macho_utilities.h */,
8B31FF7211F0C6E000FCF3E4 /* macho_reader.cc */,
@ -410,6 +415,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
162F64FE161C5ECB00CD68D5 /* arch_utilities.cc in Sources */,
8DD76F9A0486AA7600D96B5E /* crash_report.mm in Sources */,
9BDF172C0B1B8B2400F8391B /* call_stack.cc in Sources */,
9BDF172D0B1B8B2400F8391B /* minidump_processor.cc in Sources */,

View File

@ -33,6 +33,8 @@
/* End PBXAggregateTarget section */
/* Begin PBXBuildFile section */
162F64FA161C591500CD68D5 /* arch_utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = 162F64F8161C591500CD68D5 /* arch_utilities.cc */; };
162F6500161C5F2200CD68D5 /* arch_utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = 162F64F8161C591500CD68D5 /* arch_utilities.cc */; };
4D72CAF513DFBAC2006CABE3 /* md5.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4D72CAF413DFBAC2006CABE3 /* md5.cc */; };
B84A91F8116CF78F006C210E /* libgtestmockall.a in Frameworks */ = {isa = PBXBuildFile; fileRef = B88FB024116BDFFF00407530 /* libgtestmockall.a */; };
B84A91FB116CF7AF006C210E /* module.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FAE241166603300407530 /* module.cc */; };
@ -270,6 +272,8 @@
/* 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 = SDKROOT; };
162F64F8161C591500CD68D5 /* arch_utilities.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = arch_utilities.cc; path = ../../../common/mac/arch_utilities.cc; sourceTree = "<group>"; };
162F64F9161C591500CD68D5 /* arch_utilities.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = arch_utilities.h; path = ../../../common/mac/arch_utilities.h; sourceTree = "<group>"; };
4D72CAF413DFBAC2006CABE3 /* md5.cc */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; fileEncoding = 4; name = md5.cc; path = ../../../common/md5.cc; sourceTree = SOURCE_ROOT; };
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; };
@ -481,6 +485,8 @@
B89E0E6C1166569700DD08C9 /* MACHO */,
B88FAE3811666A1700407530 /* STABS */,
B88FAE1C11665FFD00407530 /* MODULE */,
162F64F8161C591500CD68D5 /* arch_utilities.cc */,
162F64F9161C591500CD68D5 /* arch_utilities.h */,
B88FAE1D1166603300407530 /* byte_cursor.h */,
B88FB0D4116CEC0600407530 /* byte_cursor_unittest.cc */,
B8E8CA0C1156C854009E61B2 /* byteswap.h */,
@ -1044,6 +1050,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
162F6500161C5F2200CD68D5 /* arch_utilities.cc in Sources */,
B89E0E781166576C00DD08C9 /* macho_reader.cc in Sources */,
B89E0E7A1166576C00DD08C9 /* macho_dump.cc in Sources */,
);
@ -1062,6 +1069,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
162F64FA161C591500CD68D5 /* arch_utilities.cc in Sources */,
B88FAE2C1166606200407530 /* macho_reader.cc in Sources */,
B8C5B5171166534700D34F4E /* dwarf2reader.cc in Sources */,
B8C5B5181166534700D34F4E /* bytereader.cc in Sources */,

View File

@ -39,6 +39,7 @@
#include <vector>
#include "common/mac/dump_syms.h"
#include "common/mac/arch_utilities.h"
#include "common/mac/macho_utilities.h"
using google_breakpad::DumpSymbols;
@ -73,7 +74,8 @@ static bool Start(const Options &options) {
for (size_t i = 0; i < available_size; i++) {
const struct fat_arch *arch = &available[i];
const NXArchInfo *arch_info =
NXGetArchInfoFromCpuType(arch->cputype, arch->cpusubtype);
google_breakpad::BreakpadGetArchInfoFromCpuType(
arch->cputype, arch->cpusubtype);
if (arch_info)
fprintf(stderr, "%s (%s)\n", arch_info->name, arch_info->description);
else
@ -107,7 +109,8 @@ static void SetupOptions(int argc, const char *argv[], Options *options) {
while ((ch = getopt(argc, (char * const *)argv, "a:ch?")) != -1) {
switch (ch) {
case 'a': {
const NXArchInfo *arch_info = NXGetArchInfoFromName(optarg);
const NXArchInfo *arch_info =
google_breakpad::BreakpadGetArchInfoFromName(optarg);
if (!arch_info) {
fprintf(stderr, "%s: Invalid architecture: %s\n", argv[0], optarg);
Usage(argc, argv);

View File

@ -47,6 +47,7 @@
#include <vector>
#include "common/byte_cursor.h"
#include "common/mac/arch_utilities.h"
#include "common/mac/macho_reader.h"
using google_breakpad::ByteBuffer;
@ -142,8 +143,9 @@ void DumpFile(const char *filename) {
printf(" object file count: %ld\n", object_files_size);
for (size_t i = 0; i < object_files_size; i++) {
const struct fat_arch &file = object_files[i];
const NXArchInfo *fat_arch_info
= NXGetArchInfoFromCpuType(file.cputype, file.cpusubtype);
const NXArchInfo *fat_arch_info =
google_breakpad::BreakpadGetArchInfoFromCpuType(
file.cputype, file.cpusubtype);
printf("\n object file %ld:\n"
" fat header:\n:"
" CPU type: %s (%s)\n"