diff options
author | Ted Mielczarek <ted@mielczarek.org> | 2015-09-16 06:46:55 -0400 |
---|---|---|
committer | Ted Mielczarek <ted@mielczarek.org> | 2015-09-16 06:46:55 -0400 |
commit | 8079ae192d6465c2fa0f1241f9a0436932509ed6 (patch) | |
tree | 10877e4154da99087e8bc6f8b2c8ba7eefbfcbd5 /src/common/mac | |
parent | Update gitignore to ignore more GYP things (diff) | |
download | breakpad-8079ae192d6465c2fa0f1241f9a0436932509ed6.tar.xz |
Fix Mac Breakpad host tools to build in Linux cross-compile
We're working on building our Firefox Mac builds as a Linux cross-compile
(https://bugzilla.mozilla.org/show_bug.cgi?id=921040) and we need symbol
dumping to work. This change ports the Mac dump_syms tool to build and work
on Linux. I've tested it and it produces identical output to running the
tool on Mac.
The bulk of the work here was converting src/common/mac/dump_syms.mm and
src/tools/mac/dump_syms/dump_syms_tool.mm from ObjC++ to C++ and removing
their use of Foundation classes in favor of standard C/C++.
This won't compile out-of-the-box on Linux, it requires some Mac system
headers that are not included in this patch. I have those tentatively in
a separate patch to land in Gecko
(http://hg.mozilla.org/users/tmielczarek_mozilla.com/mc/rev/5fb8da23c83c),
but I wasn't sure if you'd be interested in having them in the Breakpad tree.
We could almost certainly pare down the set of headers included there, I
didn't spend too much time trying to minimize them (we primarily just need
the Mach-O structs and a few associated bits).
I just realized that this patch is missing updating the XCode project files
(ugh). I'll fix that up in a bit.
R=mark@chromium.org
BUG=https://bugzilla.mozilla.org/show_bug.cgi?id=543111
Review URL: https://codereview.chromium.org/1340543002 .
Diffstat (limited to 'src/common/mac')
-rw-r--r-- | src/common/mac/arch_utilities.cc | 118 | ||||
-rw-r--r-- | src/common/mac/byteswap.h | 25 | ||||
-rw-r--r-- | src/common/mac/dump_syms.cc (renamed from src/common/mac/dump_syms.mm) | 173 | ||||
-rw-r--r-- | src/common/mac/dump_syms.h | 17 | ||||
-rw-r--r-- | src/common/mac/file_id.cc | 3 | ||||
-rw-r--r-- | src/common/mac/macho_id.cc | 36 | ||||
-rw-r--r-- | src/common/mac/macho_reader_unittest.cc | 26 | ||||
-rw-r--r-- | src/common/mac/macho_utilities.cc | 89 | ||||
-rw-r--r-- | src/common/mac/macho_utilities.h | 27 | ||||
-rw-r--r-- | src/common/mac/macho_walker.cc | 28 |
10 files changed, 379 insertions, 163 deletions
diff --git a/src/common/mac/arch_utilities.cc b/src/common/mac/arch_utilities.cc index 94e3be3b..bfafc0d9 100644 --- a/src/common/mac/arch_utilities.cc +++ b/src/common/mac/arch_utilities.cc @@ -30,27 +30,20 @@ #include "common/mac/arch_utilities.h" #include <mach-o/arch.h> +#include <mach-o/fat.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 #ifndef CPU_TYPE_ARM64 -#define CPU_TYPE_ARM64 (static_cast<cpu_type_t>(16777228)) +#define CPU_TYPE_ARM64 (CPU_TYPE_ARM | CPU_ARCH_ABI64) #endif // CPU_TYPE_ARM64 #ifndef CPU_SUBTYPE_ARM64_ALL -#define CPU_SUBTYPE_ARM64_ALL (static_cast<cpu_type_t>(0)) +#define CPU_SUBTYPE_ARM64_ALL (static_cast<cpu_subtype_t>(0)) #endif // CPU_SUBTYPE_ARM64_ALL namespace { @@ -111,3 +104,108 @@ const NXArchInfo* BreakpadGetArchInfoFromCpuType(cpu_type_t cpu_type, } } // namespace google_breakpad + +#ifndef __APPLE__ +namespace { + +enum Architecture { + kArch_i386 = 0, + kArch_x86_64, + kArch_arm, + kArch_arm64, + kArch_ppc, + // This must be last. + kNumArchitectures +}; + +// enum Architecture above and kKnownArchitectures below +// must be kept in sync. +const NXArchInfo kKnownArchitectures[] = { + { + "i386", + CPU_TYPE_I386, + CPU_SUBTYPE_I386_ALL, + NX_LittleEndian, + "Intel 80x86" + }, + { + "x86_64", + CPU_TYPE_X86_64, + CPU_SUBTYPE_X86_64_ALL, + NX_LittleEndian, + "Intel x86-64" + }, + { + "arm", + CPU_TYPE_ARM, + CPU_SUBTYPE_ARM_ALL, + NX_LittleEndian, + "ARM" + }, + { + "arm64", + CPU_TYPE_ARM64, + CPU_SUBTYPE_ARM64_ALL, + NX_LittleEndian, + "ARM64" + }, + { + "ppc", + CPU_TYPE_POWERPC, + CPU_SUBTYPE_POWERPC_ALL, + NX_BigEndian, + "PowerPC" + } +}; + +} // namespace + +const NXArchInfo *NXGetLocalArchInfo(void) { + Architecture arch; +#if defined(__i386__) + arch = kArch_i386; +#elif defined(__x86_64__) + arch = kArch_x86_64; +#elif defined(__arm64) + arch = kArch_arm64; +#elif defined(__arm__) + arch = kArch_arm; +#elif defined(__powerpc__) + arch = kArch_ppc; +#else + #error "Unsupported CPU architecture" +#endif + return &kKnownArchitectures[arch]; +} + +const NXArchInfo *NXGetArchInfoFromName(const char *name) { + for (int arch = 0; arch < kNumArchitectures; ++arch) { + if (strcmp(name, kKnownArchitectures[arch].name)) { + return &kKnownArchitectures[arch]; + } + } + return NULL; +} + +const NXArchInfo *NXGetArchInfoFromCpuType(cpu_type_t cputype, + cpu_subtype_t cpusubtype) { + for (int arch = 0; arch < kNumArchitectures; ++arch) { + if (kKnownArchitectures[arch].cputype == cputype) { + return &kKnownArchitectures[arch]; + } + } + return NULL; +} + +struct fat_arch *NXFindBestFatArch(cpu_type_t cputype, + cpu_subtype_t cpusubtype, + struct fat_arch *fat_archs, + uint32_t nfat_archs) { + for (uint32_t f = 0; f < nfat_archs; ++f) { + if (fat_archs[f].cputype == cputype) { + return &fat_archs[f]; + } + } + return NULL; +} +#endif // !__APPLE__ diff --git a/src/common/mac/byteswap.h b/src/common/mac/byteswap.h index a5d745b3..b7bbc0b9 100644 --- a/src/common/mac/byteswap.h +++ b/src/common/mac/byteswap.h @@ -36,6 +36,7 @@ #ifndef COMMON_MAC_BYTESWAP_H_ #define COMMON_MAC_BYTESWAP_H_ +#ifdef __APPLE__ #include <libkern/OSByteOrder.h> static inline uint16_t ByteSwap(uint16_t v) { return OSSwapInt16(v); } @@ -45,4 +46,28 @@ static inline int16_t ByteSwap(int16_t v) { return OSSwapInt16(v); } static inline int32_t ByteSwap(int32_t v) { return OSSwapInt32(v); } static inline int64_t ByteSwap(int64_t v) { return OSSwapInt64(v); } +#elif defined(__linux__) +// For NXByteOrder +#include <architecture/byte_order.h> +#include <stdint.h> +#include <endian.h> +#include_next <byteswap.h> + +static inline uint16_t ByteSwap(uint16_t v) { return bswap_16(v); } +static inline uint32_t ByteSwap(uint32_t v) { return bswap_32(v); } +static inline uint64_t ByteSwap(uint64_t v) { return bswap_64(v); } +static inline int16_t ByteSwap(int16_t v) { return bswap_16(v); } +static inline int32_t ByteSwap(int32_t v) { return bswap_32(v); } +static inline int64_t ByteSwap(int64_t v) { return bswap_64(v); } + +static inline NXByteOrder NXHostByteOrder() { +#ifdef __LITTLE_ENDIAN + return NX_LittleEndian; +#else + return NX_BigEndian; +#endif +} + +#endif // __APPLE__ + #endif // COMMON_MAC_BYTESWAP_H_ diff --git a/src/common/mac/dump_syms.mm b/src/common/mac/dump_syms.cc index 58cf4c20..4dcdb73e 100644 --- a/src/common/mac/dump_syms.mm +++ b/src/common/mac/dump_syms.cc @@ -36,10 +36,15 @@ #include "common/mac/dump_syms.h" #include <assert.h> -#include <Foundation/Foundation.h> +#include <dirent.h> +#include <errno.h> +#include <libgen.h> #include <mach-o/arch.h> #include <mach-o/fat.h> #include <stdio.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> #include <ostream> #include <string> @@ -83,89 +88,105 @@ using std::pair; using std::string; using std::vector; +namespace { +// Return a vector<string> with absolute paths to all the entries +// in directory (excluding . and ..). +vector<string> list_directory(const string& directory) { + vector<string> entries; + DIR* dir = opendir(directory.c_str()); + if (!dir) { + return entries; + } + + string path = directory; + if (path[path.length() - 1] != '/') { + path += '/'; + } + + struct dirent* entry = NULL; + while ((entry = readdir(dir))) { + if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) { + entries.push_back(path + entry->d_name); + } + } + + closedir(dir); + return entries; +} +} + namespace google_breakpad { -bool DumpSymbols::Read(NSString *filename) { - if (![[NSFileManager defaultManager] fileExistsAtPath:filename]) { - fprintf(stderr, "Object file does not exist: %s\n", - [filename fileSystemRepresentation]); +bool DumpSymbols::Read(const string &filename) { + struct stat st; + if (stat(filename.c_str(), &st) == -1) { + fprintf(stderr, "Could not access object file %s: %s\n", + filename.c_str(), strerror(errno)); return false; } - input_pathname_ = [filename retain]; + input_pathname_ = filename; // Does this filename refer to a dSYM bundle? - NSBundle *bundle = [NSBundle bundleWithPath:input_pathname_]; - - if (bundle) { - // Filenames referring to bundles usually have names of the form - // "<basename>.dSYM"; however, if the user has specified a wrapper - // suffix (the WRAPPER_SUFFIX and WRAPPER_EXTENSION build settings), - // then the name may have the form "<basename>.<extension>.dSYM". In - // either case, the resource name for the file containing the DWARF - // info within the bundle is <basename>. - // - // Since there's no way to tell how much to strip off, remove one - // extension at a time, and use the first one that - // pathForResource:ofType:inDirectory likes. - NSString *base_name = [input_pathname_ lastPathComponent]; - NSString *dwarf_resource; - - do { - NSString *new_base_name = [base_name stringByDeletingPathExtension]; - - // If stringByDeletingPathExtension returned the name unchanged, then - // there's nothing more for us to strip off --- lose. - if ([new_base_name isEqualToString:base_name]) { - fprintf(stderr, "Unable to find DWARF-bearing file in bundle: %s\n", - [input_pathname_ fileSystemRepresentation]); - return false; - } - - // Take the shortened result as our new base_name. - base_name = new_base_name; - - // Try to find a DWARF resource in the bundle under the new base_name. - dwarf_resource = [bundle pathForResource:base_name - ofType:nil inDirectory:@"DWARF"]; - } while (!dwarf_resource); + string contents_path = input_pathname_ + "/Contents/Resources/DWARF"; + if (S_ISDIR(st.st_mode) && + access(contents_path.c_str(), F_OK) == 0) { + // If there's one file under Contents/Resources/DWARF then use that, + // otherwise bail out. + const vector<string> entries = list_directory(contents_path); + if (entries.size() == 0) { + fprintf(stderr, "Unable to find DWARF-bearing file in bundle: %s\n", + input_pathname_.c_str()); + return false; + } + if (entries.size() > 1) { + fprintf(stderr, "Too many DWARF files in bundle: %s\n", + input_pathname_.c_str()); + return false; + } - object_filename_ = [dwarf_resource retain]; + object_filename_ = entries[0]; } else { - object_filename_ = [input_pathname_ retain]; + object_filename_ = input_pathname_; } // Read the file's contents into memory. - // - // The documentation for dataWithContentsOfMappedFile says: - // - // Because of file mapping restrictions, this method should only be - // used if the file is guaranteed to exist for the duration of the - // data object’s existence. It is generally safer to use the - // dataWithContentsOfFile: method. - // - // I gather this means that OS X doesn't have (or at least, that method - // doesn't use) a form of mapping like Linux's MAP_PRIVATE, where the - // process appears to get its own copy of the data, and changes to the - // file don't affect memory and vice versa). - NSError *error; - contents_ = [NSData dataWithContentsOfFile:object_filename_ - options:0 - error:&error]; - if (!contents_) { + bool read_ok = true; + string error; + if (stat(object_filename_.c_str(), &st) != -1) { + FILE* f = fopen(object_filename_.c_str(), "rb"); + if (f) { + contents_.reset(new uint8_t[st.st_size]); + off_t total = 0; + while (total < st.st_size && !feof(f)) { + size_t read = fread(&contents_[0] + total, 1, st.st_size - total, f); + if (read == 0) { + if (ferror(f)) { + read_ok = false; + error = strerror(errno); + } + break; + } + total += read; + } + fclose(f); + } else { + error = strerror(errno); + } + } + + if (!read_ok) { fprintf(stderr, "Error reading object file: %s: %s\n", - [object_filename_ fileSystemRepresentation], - [[error localizedDescription] UTF8String]); + object_filename_.c_str(), + error.c_str()); return false; } - [contents_ retain]; // Get the list of object files present in the file. - FatReader::Reporter fat_reporter([object_filename_ - fileSystemRepresentation]); + FatReader::Reporter fat_reporter(object_filename_); FatReader fat_reader(&fat_reporter); - if (!fat_reader.Read(reinterpret_cast<const uint8_t *>([contents_ bytes]), - [contents_ length])) { + if (!fat_reader.Read(&contents_[0], + st.st_size)) { return false; } @@ -175,7 +196,7 @@ bool DumpSymbols::Read(NSString *filename) { fat_reader.object_files(&object_files_count); if (object_files_count == 0) { fprintf(stderr, "Fat binary file contains *no* architectures: %s\n", - [object_filename_ fileSystemRepresentation]); + object_filename_.c_str()); return false; } object_files_.resize(object_files_count); @@ -243,7 +264,8 @@ SuperFatArch* DumpSymbols::FindBestMatchForArchitecture( for (vector<SuperFatArch>::iterator it = object_files_.begin(); it != object_files_.end(); ++it) { - if (it->cputype == cpu_type && it->cpusubtype == cpu_subtype) + if (static_cast<cpu_type_t>(it->cputype) == cpu_type && + static_cast<cpu_subtype_t>(it->cpusubtype) == cpu_subtype) return &*it; } @@ -258,13 +280,13 @@ SuperFatArch* DumpSymbols::FindBestMatchForArchitecture( } string DumpSymbols::Identifier() { - FileID file_id([object_filename_ fileSystemRepresentation]); + FileID file_id(object_filename_.c_str()); unsigned char identifier_bytes[16]; cpu_type_t cpu_type = selected_object_file_->cputype; 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]); + object_filename_.c_str()); return ""; } @@ -526,7 +548,7 @@ bool DumpSymbols::ReadSymbolData(Module** out_module) { " architecture, none of which match the current" " architecture; specify an architecture explicitly" " with '-a ARCH' to resolve the ambiguity\n", - [object_filename_ fileSystemRepresentation]); + object_filename_.c_str()); return false; } } @@ -546,14 +568,15 @@ bool DumpSymbols::ReadSymbolData(Module** out_module) { // Produce a name to use in error messages that includes the // filename, and the architecture, if there is more than one. - selected_object_name_ = [object_filename_ UTF8String]; + selected_object_name_ = object_filename_; if (object_files_.size() > 1) { selected_object_name_ += ", architecture "; selected_object_name_ + selected_arch_name; } // Compute a module name, to appear in the MODULE record. - NSString *module_name = [object_filename_ lastPathComponent]; + string module_name = object_filename_; + module_name = basename(&module_name[0]); // Choose an identifier string, to appear in the MODULE record. string identifier = Identifier(); @@ -562,7 +585,7 @@ bool DumpSymbols::ReadSymbolData(Module** out_module) { identifier += "0"; // Create a module to hold the debugging information. - scoped_ptr<Module> module(new Module([module_name UTF8String], + scoped_ptr<Module> module(new Module(module_name, "mac", selected_arch_name, identifier)); @@ -570,7 +593,7 @@ bool DumpSymbols::ReadSymbolData(Module** out_module) { // Parse the selected object file. mach_o::Reader::Reporter reporter(selected_object_name_); mach_o::Reader reader(&reporter); - if (!reader.Read(reinterpret_cast<const uint8_t *>([contents_ bytes]) + if (!reader.Read(&contents_[0] + selected_object_file_->offset, selected_object_file_->size, selected_object_file_->cputype, diff --git a/src/common/mac/dump_syms.h b/src/common/mac/dump_syms.h index babed701..b09928c9 100644 --- a/src/common/mac/dump_syms.h +++ b/src/common/mac/dump_syms.h @@ -35,7 +35,6 @@ // reading debugging information from Mach-O files and writing it out as a // Breakpad symbol file. -#include <Foundation/Foundation.h> #include <mach-o/loader.h> #include <stdio.h> #include <stdlib.h> @@ -48,6 +47,7 @@ #include "common/mac/macho_reader.h" #include "common/mac/super_fat_arch.h" #include "common/module.h" +#include "common/scoped_ptr.h" #include "common/symbol_data.h" namespace google_breakpad { @@ -64,20 +64,13 @@ class DumpSymbols { selected_object_file_(), selected_object_name_() { } ~DumpSymbols() { - [input_pathname_ release]; - [object_filename_ release]; - [contents_ release]; } // Prepare to read debugging information from |filename|. |filename| may be // the name of a universal binary, a Mach-O file, or a dSYM bundle // containing either of the above. On success, return true; if there is a // problem reading |filename|, report it and return false. - // - // (This class uses NSString for filenames and related values, - // because the Mac Foundation framework seems to support - // filename-related operations more fully on NSString values.) - bool Read(NSString *filename); + bool Read(const std::string &filename); // If this dumper's file includes an object file for |cpu_type| and // |cpu_subtype|, then select that object file for dumping, and return @@ -163,16 +156,16 @@ class DumpSymbols { // The name of the file or bundle whose symbols this will dump. // This is the path given to Read, for use in error messages. - NSString *input_pathname_; + std::string input_pathname_; // The name of the file this DumpSymbols will actually read debugging // information from. Normally, this is the same as input_pathname_, but if // filename refers to a dSYM bundle, then this is the resource file // within that bundle. - NSString *object_filename_; + std::string object_filename_; // The complete contents of object_filename_, mapped into memory. - NSData *contents_; + scoped_array<uint8_t> contents_; // A vector of SuperFatArch structures describing the object files // object_filename_ contains. If object_filename_ refers to a fat binary, diff --git a/src/common/mac/file_id.cc b/src/common/mac/file_id.cc index c5d7ed56..4661d5d6 100644 --- a/src/common/mac/file_id.cc +++ b/src/common/mac/file_id.cc @@ -34,6 +34,7 @@ // Author: Dan Waylonis #include <fcntl.h> +#include <stdio.h> #include <string.h> #include <unistd.h> @@ -45,7 +46,7 @@ using MacFileUtilities::MachoID; namespace google_breakpad { FileID::FileID(const char *path) { - strlcpy(path_, path, sizeof(path_)); + snprintf(path_, sizeof(path_), "%s", path); } bool FileID::FileIdentifier(unsigned char identifier[16]) { diff --git a/src/common/mac/macho_id.cc b/src/common/mac/macho_id.cc index 09a2a82e..c396ad88 100644 --- a/src/common/mac/macho_id.cc +++ b/src/common/mac/macho_id.cc @@ -33,17 +33,15 @@ // // Author: Dan Waylonis -extern "C" { // necessary for Leopard - #include <fcntl.h> - #include <mach-o/loader.h> - #include <mach-o/swap.h> - #include <stdio.h> - #include <stdlib.h> - #include <string.h> - #include <sys/time.h> - #include <sys/types.h> - #include <unistd.h> -} + +#include <fcntl.h> +#include <mach-o/loader.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/time.h> +#include <sys/types.h> +#include <unistd.h> #include "common/mac/macho_id.h" #include "common/mac/macho_walker.h" @@ -61,7 +59,7 @@ MachoID::MachoID(const char *path) crc_(0), md5_context_(), update_function_(NULL) { - strlcpy(path_, path, sizeof(path_)); + snprintf(path_, sizeof(path_), "%s", path); } MachoID::MachoID(const char *path, void *memory, size_t size) @@ -70,7 +68,7 @@ MachoID::MachoID(const char *path, void *memory, size_t size) crc_(0), md5_context_(), update_function_(NULL) { - strlcpy(path_, path, sizeof(path_)); + snprintf(path_, sizeof(path_), "%s", path); } MachoID::~MachoID() { @@ -261,7 +259,7 @@ bool MachoID::WalkerCB(MachoWalker *walker, load_command *cmd, off_t offset, return false; if (swap) - swap_segment_command(&seg, NXHostByteOrder()); + breakpad_swap_segment_command(&seg); struct mach_header_64 header; off_t header_offset; @@ -278,7 +276,7 @@ bool MachoID::WalkerCB(MachoWalker *walker, load_command *cmd, off_t offset, return false; if (swap) - swap_section(&sec, 1, NXHostByteOrder()); + breakpad_swap_section(&sec, 1); // sections of type S_ZEROFILL are "virtual" and contain no data // in the file itself @@ -294,7 +292,7 @@ bool MachoID::WalkerCB(MachoWalker *walker, load_command *cmd, off_t offset, return false; if (swap) - breakpad_swap_segment_command_64(&seg64, NXHostByteOrder()); + breakpad_swap_segment_command_64(&seg64); struct mach_header_64 header; off_t header_offset; @@ -311,7 +309,7 @@ bool MachoID::WalkerCB(MachoWalker *walker, load_command *cmd, off_t offset, return false; if (swap) - breakpad_swap_section_64(&sec64, 1, NXHostByteOrder()); + breakpad_swap_section_64(&sec64, 1); // sections of type S_ZEROFILL are "virtual" and contain no data // in the file itself @@ -340,7 +338,7 @@ bool MachoID::UUIDWalkerCB(MachoWalker *walker, load_command *cmd, off_t offset, return false; if (swap) - breakpad_swap_uuid_command(uuid_cmd, NXHostByteOrder()); + breakpad_swap_uuid_command(uuid_cmd); return false; } @@ -359,7 +357,7 @@ bool MachoID::IDWalkerCB(MachoWalker *walker, load_command *cmd, off_t offset, return false; if (swap) - swap_dylib_command(dylib_cmd, NXHostByteOrder()); + breakpad_swap_dylib_command(dylib_cmd); return false; } diff --git a/src/common/mac/macho_reader_unittest.cc b/src/common/mac/macho_reader_unittest.cc index 9bc6d25a..8ceab14b 100644 --- a/src/common/mac/macho_reader_unittest.cc +++ b/src/common/mac/macho_reader_unittest.cc @@ -196,7 +196,7 @@ struct FatReaderFixture { FatReaderFixture() : fat(kBigEndian), reporter("reporter filename"), - reader(&reporter), object_files(), object_files_size() { + reader(&reporter), object_files() { EXPECT_CALL(reporter, BadHeader()).Times(0); EXPECT_CALL(reporter, TooShort()).Times(0); @@ -224,7 +224,12 @@ struct FatReaderFixture { fat_bytes = reinterpret_cast<const uint8_t *>(contents.data()); if (expect_parse_success) { EXPECT_TRUE(reader.Read(fat_bytes, contents.size())); - object_files = reader.object_files(&object_files_size); + size_t fat_files_count; + const SuperFatArch* fat_files = reader.object_files(&fat_files_count); + object_files.resize(fat_files_count); + for (size_t i = 0; i < fat_files_count; ++i) { + EXPECT_TRUE(fat_files[i].ConvertToFatArch(&object_files[i])); + } } else EXPECT_FALSE(reader.Read(fat_bytes, contents.size())); @@ -234,8 +239,7 @@ struct FatReaderFixture { FatReader reader; string contents; const uint8_t *fat_bytes; - const struct fat_arch *object_files; - size_t object_files_size; + vector<struct fat_arch> object_files; }; class FatReaderTest: public FatReaderFixture, public Test { }; @@ -289,7 +293,7 @@ TEST_F(FatReaderTest, NoObjectFiles) { .B32(0xcafebabe) // magic number .B32(0); // number of architectures ReadFat(); - EXPECT_EQ(0U, object_files_size); + EXPECT_EQ(0U, object_files.size()); } TEST_F(FatReaderTest, OneObjectFile) { @@ -304,7 +308,7 @@ TEST_F(FatReaderTest, OneObjectFile) { .Mark(&obj1_offset) .Append(0x42, '*'); // dummy contents ReadFat(); - ASSERT_EQ(1U, object_files_size); + ASSERT_EQ(1U, object_files.size()); EXPECT_EQ(0x5e3a6e91, object_files[0].cputype); EXPECT_EQ(0x52ccd852, object_files[0].cpusubtype); EXPECT_EQ(obj1_offset.Value(), object_files[0].offset); @@ -334,7 +338,7 @@ TEST_F(FatReaderTest, ThreeObjectFiles) { ReadFat(); - ASSERT_EQ(3U, object_files_size); + ASSERT_EQ(3U, object_files.size()); // First object file. EXPECT_EQ(0x0cb92c30, object_files[0].cputype); @@ -373,7 +377,7 @@ TEST_F(FatReaderTest, BigEndianMachO32) { // FatReader should treat a Mach-O file as if it were a fat binary file // containing one object file --- the whole thing. - ASSERT_EQ(1U, object_files_size); + ASSERT_EQ(1U, object_files.size()); EXPECT_EQ(0x1a9d0518, object_files[0].cputype); EXPECT_EQ(0x1b779357, object_files[0].cpusubtype); EXPECT_EQ(0U, object_files[0].offset); @@ -395,7 +399,7 @@ TEST_F(FatReaderTest, BigEndianMachO64) { // FatReader should treat a Mach-O file as if it were a fat binary file // containing one object file --- the whole thing. - ASSERT_EQ(1U, object_files_size); + ASSERT_EQ(1U, object_files.size()); EXPECT_EQ(0x5aff8487, object_files[0].cputype); EXPECT_EQ(0x4c6a57f7, object_files[0].cpusubtype); EXPECT_EQ(0U, object_files[0].offset); @@ -417,7 +421,7 @@ TEST_F(FatReaderTest, LittleEndianMachO32) { // FatReader should treat a Mach-O file as if it were a fat binary file // containing one object file --- the whole thing. - ASSERT_EQ(1U, object_files_size); + ASSERT_EQ(1U, object_files.size()); EXPECT_EQ(0x1a9d0518, object_files[0].cputype); EXPECT_EQ(0x1b779357, object_files[0].cpusubtype); EXPECT_EQ(0U, object_files[0].offset); @@ -439,7 +443,7 @@ TEST_F(FatReaderTest, LittleEndianMachO64) { // FatReader should treat a Mach-O file as if it were a fat binary file // containing one object file --- the whole thing. - ASSERT_EQ(1U, object_files_size); + ASSERT_EQ(1U, object_files.size()); EXPECT_EQ(0x5aff8487, object_files[0].cputype); EXPECT_EQ(0x4c6a57f7, object_files[0].cpusubtype); EXPECT_EQ(0U, object_files[0].offset); diff --git a/src/common/mac/macho_utilities.cc b/src/common/mac/macho_utilities.cc index 89f9e775..f56fe768 100644 --- a/src/common/mac/macho_utilities.cc +++ b/src/common/mac/macho_utilities.cc @@ -34,16 +34,44 @@ #include "common/mac/byteswap.h" #include "common/mac/macho_utilities.h" -void breakpad_swap_uuid_command(struct breakpad_uuid_command *uc, - enum NXByteOrder target_byte_order) -{ +#include <mach-o/fat.h> +#include <mach-o/loader.h> + +void breakpad_swap_uuid_command(struct breakpad_uuid_command *uc) { uc->cmd = ByteSwap(uc->cmd); uc->cmdsize = ByteSwap(uc->cmdsize); } -void breakpad_swap_segment_command_64(struct segment_command_64 *sg, - enum NXByteOrder target_byte_order) -{ +void breakpad_swap_load_command(struct load_command *lc) { + lc->cmd = ByteSwap(lc->cmd); + lc->cmdsize = ByteSwap(lc->cmdsize); +} + +void breakpad_swap_dylib_command(struct dylib_command *dc) { + dc->cmd = ByteSwap(dc->cmd); + dc->cmdsize = ByteSwap(dc->cmdsize); + + dc->dylib.name.offset = ByteSwap(dc->dylib.name.offset); + dc->dylib.timestamp = ByteSwap(dc->dylib.timestamp); + dc->dylib.current_version = ByteSwap(dc->dylib.current_version); + dc->dylib.compatibility_version = ByteSwap(dc->dylib.compatibility_version); +} + +void breakpad_swap_segment_command(struct segment_command *sc) { + sc->cmd = ByteSwap(sc->cmd); + sc->cmdsize = ByteSwap(sc->cmdsize); + + sc->vmaddr = ByteSwap(sc->vmaddr); + sc->vmsize = ByteSwap(sc->vmsize); + sc->fileoff = ByteSwap(sc->fileoff); + sc->filesize = ByteSwap(sc->filesize); + sc->maxprot = ByteSwap(sc->maxprot); + sc->initprot = ByteSwap(sc->initprot); + sc->nsects = ByteSwap(sc->nsects); + sc->flags = ByteSwap(sc->flags); +} + +void breakpad_swap_segment_command_64(struct segment_command_64 *sg) { sg->cmd = ByteSwap(sg->cmd); sg->cmdsize = ByteSwap(sg->cmdsize); @@ -58,9 +86,32 @@ void breakpad_swap_segment_command_64(struct segment_command_64 *sg, sg->flags = ByteSwap(sg->flags); } -void breakpad_swap_mach_header_64(struct mach_header_64 *mh, - enum NXByteOrder target_byte_order) -{ +void breakpad_swap_fat_header(struct fat_header *fh) { + fh->magic = ByteSwap(fh->magic); + fh->nfat_arch = ByteSwap(fh->nfat_arch); +} + +void breakpad_swap_fat_arch(struct fat_arch *fa, uint32_t narchs) { + for (uint32_t i = 0; i < narchs; ++i) { + fa[i].cputype = ByteSwap(fa[i].cputype); + fa[i].cpusubtype = ByteSwap(fa[i].cpusubtype); + fa[i].offset = ByteSwap(fa[i].offset); + fa[i].size = ByteSwap(fa[i].size); + fa[i].align = ByteSwap(fa[i].align); + } +} + +void breakpad_swap_mach_header(struct mach_header *mh) { + mh->magic = ByteSwap(mh->magic); + mh->cputype = ByteSwap(mh->cputype); + mh->cpusubtype = ByteSwap(mh->cpusubtype); + mh->filetype = ByteSwap(mh->filetype); + mh->ncmds = ByteSwap(mh->ncmds); + mh->sizeofcmds = ByteSwap(mh->sizeofcmds); + mh->flags = ByteSwap(mh->flags); +} + +void breakpad_swap_mach_header_64(struct mach_header_64 *mh) { mh->magic = ByteSwap(mh->magic); mh->cputype = ByteSwap(mh->cputype); mh->cpusubtype = ByteSwap(mh->cpusubtype); @@ -71,10 +122,24 @@ void breakpad_swap_mach_header_64(struct mach_header_64 *mh, mh->reserved = ByteSwap(mh->reserved); } +void breakpad_swap_section(struct section *s, + uint32_t nsects) { + for (uint32_t i = 0; i < nsects; i++) { + s[i].addr = ByteSwap(s[i].addr); + s[i].size = ByteSwap(s[i].size); + + s[i].offset = ByteSwap(s[i].offset); + s[i].align = ByteSwap(s[i].align); + s[i].reloff = ByteSwap(s[i].reloff); + s[i].nreloc = ByteSwap(s[i].nreloc); + s[i].flags = ByteSwap(s[i].flags); + s[i].reserved1 = ByteSwap(s[i].reserved1); + s[i].reserved2 = ByteSwap(s[i].reserved2); + } +} + void breakpad_swap_section_64(struct section_64 *s, - uint32_t nsects, - enum NXByteOrder target_byte_order) -{ + uint32_t nsects) { for (uint32_t i = 0; i < nsects; i++) { s[i].addr = ByteSwap(s[i].addr); s[i].size = ByteSwap(s[i].size); diff --git a/src/common/mac/macho_utilities.h b/src/common/mac/macho_utilities.h index a200c0f7..00563a77 100644 --- a/src/common/mac/macho_utilities.h +++ b/src/common/mac/macho_utilities.h @@ -62,23 +62,34 @@ struct breakpad_uuid_command { uint8_t uuid[16]; /* the 128-bit uuid */ }; -void breakpad_swap_uuid_command(struct breakpad_uuid_command *uc, - enum NXByteOrder target_byte_order); +void breakpad_swap_uuid_command(struct breakpad_uuid_command *uc); + +void breakpad_swap_load_command(struct load_command *lc); + +void breakpad_swap_dylib_command(struct dylib_command *dc); // Older SDKs defines thread_state_data_t as an int[] instead // of the natural_t[] it should be. typedef natural_t breakpad_thread_state_data_t[THREAD_STATE_MAX]; +void breakpad_swap_segment_command(struct segment_command *sc); + // The 64-bit swap routines were added during the 10.4 series, their // presence isn't guaranteed. -void breakpad_swap_segment_command_64(struct segment_command_64 *sg, - enum NXByteOrder target_byte_order); +void breakpad_swap_segment_command_64(struct segment_command_64 *sg); + +void breakpad_swap_fat_header(struct fat_header *fh); + +void breakpad_swap_fat_arch(struct fat_arch *fa, uint32_t narchs); + +void breakpad_swap_mach_header(struct mach_header *mh); + +void breakpad_swap_mach_header_64(struct mach_header_64 *mh); -void breakpad_swap_mach_header_64(struct mach_header_64 *mh, - enum NXByteOrder target_byte_order); +void breakpad_swap_section(struct section *s, + uint32_t nsects); void breakpad_swap_section_64(struct section_64 *s, - uint32_t nsects, - enum NXByteOrder target_byte_order); + uint32_t nsects); #endif diff --git a/src/common/mac/macho_walker.cc b/src/common/mac/macho_walker.cc index eee27d64..1acd8665 100644 --- a/src/common/mac/macho_walker.cc +++ b/src/common/mac/macho_walker.cc @@ -33,15 +33,13 @@ // // Author: Dan Waylonis -extern "C" { // necessary for Leopard - #include <assert.h> - #include <fcntl.h> - #include <mach-o/arch.h> - #include <mach-o/loader.h> - #include <mach-o/swap.h> - #include <string.h> - #include <unistd.h> -} +#include <assert.h> +#include <fcntl.h> +#include <mach-o/arch.h> +#include <mach-o/fat.h> +#include <mach-o/loader.h> +#include <string.h> +#include <unistd.h> #include "common/mac/byteswap.h" #include "common/mac/macho_walker.h" @@ -156,7 +154,7 @@ bool MachoWalker::FindHeader(cpu_type_t cpu_type, return false; if (magic == MH_CIGAM || magic == MH_CIGAM_64) - swap_mach_header(&header, NXHostByteOrder()); + breakpad_swap_mach_header(&header); if (cpu_type != header.cputype || (cpu_subtype != CPU_SUBTYPE_MULTIPLE && @@ -174,7 +172,7 @@ bool MachoWalker::FindHeader(cpu_type_t cpu_type, return false; if (NXHostByteOrder() != NX_BigEndian) - swap_fat_header(&fat, NXHostByteOrder()); + breakpad_swap_fat_header(&fat); offset += sizeof(fat); @@ -185,7 +183,7 @@ bool MachoWalker::FindHeader(cpu_type_t cpu_type, return false; if (NXHostByteOrder() != NX_BigEndian) - swap_fat_arch(&arch, 1, NXHostByteOrder()); + breakpad_swap_fat_arch(&arch, 1); if (arch.cputype == cpu_type && (cpu_subtype == CPU_SUBTYPE_MULTIPLE || @@ -208,7 +206,7 @@ bool MachoWalker::WalkHeaderAtOffset(off_t offset) { bool swap = (header.magic == MH_CIGAM); if (swap) - swap_mach_header(&header, NXHostByteOrder()); + breakpad_swap_mach_header(&header); // Copy the data into the mach_header_64 structure. Since the 32-bit and // 64-bit only differ in the last field (reserved), this is safe to do. @@ -234,7 +232,7 @@ bool MachoWalker::WalkHeader64AtOffset(off_t offset) { bool swap = (header.magic == MH_CIGAM_64); if (swap) - breakpad_swap_mach_header_64(&header, NXHostByteOrder()); + breakpad_swap_mach_header_64(&header); current_header_ = &header; current_header_size_ = sizeof(header); @@ -255,7 +253,7 @@ bool MachoWalker::WalkHeaderCore(off_t offset, uint32_t number_of_commands, return false; if (swap) - swap_load_command(&cmd, NXHostByteOrder()); + breakpad_swap_load_command(&cmd); // Call the user callback if (callback_ && !callback_(this, &cmd, offset, swap, callback_context_)) |