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 .
This commit is contained in:
Ted Mielczarek 2015-09-16 06:46:55 -04:00
parent d28bebcd16
commit 8079ae192d
35 changed files with 4534 additions and 202 deletions

View file

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

View file

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

View file

@ -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_];
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;
}
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);
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 objects 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,

View file

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

View file

@ -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]) {

View file

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

View file

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

View file

@ -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_64(struct section_64 *s,
uint32_t nsects,
enum NXByteOrder target_byte_order)
{
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) {
for (uint32_t i = 0; i < nsects; i++) {
s[i].addr = ByteSwap(s[i].addr);
s[i].size = ByteSwap(s[i].size);

View file

@ -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_mach_header_64(struct mach_header_64 *mh,
enum NXByteOrder target_byte_order);
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_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

View file

@ -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_))