aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/common/common.gyp1
-rw-r--r--src/common/mac/dump_syms.h23
-rw-r--r--src/common/mac/dump_syms.mm60
-rw-r--r--src/common/mac/macho_reader.cc32
-rw-r--r--src/common/mac/macho_reader.h21
-rw-r--r--src/common/mac/super_fat_arch.h88
-rw-r--r--src/tools/mac/dump_syms/dump_syms_tool.mm4
7 files changed, 189 insertions, 40 deletions
diff --git a/src/common/common.gyp b/src/common/common.gyp
index f01ede57..6ccd21a2 100644
--- a/src/common/common.gyp
+++ b/src/common/common.gyp
@@ -141,6 +141,7 @@
'mac/scoped_task_suspend-inl.h',
'mac/string_utilities.cc',
'mac/string_utilities.h',
+ 'mac/super_fat_arch.h',
'md5.cc',
'md5.h',
'memory.h',
diff --git a/src/common/mac/dump_syms.h b/src/common/mac/dump_syms.h
index 34e83976..babed701 100644
--- a/src/common/mac/dump_syms.h
+++ b/src/common/mac/dump_syms.h
@@ -46,6 +46,7 @@
#include "common/byte_cursor.h"
#include "common/mac/macho_reader.h"
+#include "common/mac/super_fat_arch.h"
#include "common/module.h"
#include "common/symbol_data.h"
@@ -59,6 +60,7 @@ class DumpSymbols {
input_pathname_(),
object_filename_(),
contents_(),
+ object_files_(),
selected_object_file_(),
selected_object_name_() { }
~DumpSymbols() {
@@ -98,14 +100,14 @@ class DumpSymbols {
// architecture matches that of this dumper program.
bool SetArchitecture(const std::string &arch_name);
- // Return a pointer to an array of 'struct fat_arch' structures,
- // describing the object files contained in this dumper's file. Set
- // *|count| to the number of elements in the array. The returned array is
- // owned by this DumpSymbols instance.
+ // Return a pointer to an array of SuperFatArch structures describing the
+ // object files contained in this dumper's file. Set *|count| to the number
+ // of elements in the array. The returned array is owned by this DumpSymbols
+ // instance.
//
// If there are no available architectures, this function
// may return NULL.
- const struct fat_arch *AvailableArchitectures(size_t *count) {
+ const SuperFatArch* AvailableArchitectures(size_t *count) {
*count = object_files_.size();
if (object_files_.size() > 0)
return &object_files_[0];
@@ -127,6 +129,11 @@ class DumpSymbols {
class DumperLineToModule;
class LoadCommandDumper;
+ // This method behaves similarly to NXFindBestFatArch, but it supports
+ // SuperFatArch.
+ SuperFatArch* FindBestMatchForArchitecture(
+ cpu_type_t cpu_type, cpu_subtype_t cpu_subtype);
+
// Return an identifier string for the file this DumpSymbols is dumping.
std::string Identifier();
@@ -167,15 +174,15 @@ class DumpSymbols {
// The complete contents of object_filename_, mapped into memory.
NSData *contents_;
- // A vector of fat_arch structures describing the object files
+ // A vector of SuperFatArch structures describing the object files
// object_filename_ contains. If object_filename_ refers to a fat binary,
// this may have more than one element; if it refers to a Mach-O file, this
// has exactly one element.
- vector<struct fat_arch> object_files_;
+ vector<SuperFatArch> object_files_;
// The object file in object_files_ selected to dump, or NULL if
// SetArchitecture hasn't been called yet.
- const struct fat_arch *selected_object_file_;
+ const SuperFatArch *selected_object_file_;
// A string that identifies the selected object file, for use in error
// messages. This is usually object_filename_, but if that refers to a
diff --git a/src/common/mac/dump_syms.mm b/src/common/mac/dump_syms.mm
index f2420f17..58cf4c20 100644
--- a/src/common/mac/dump_syms.mm
+++ b/src/common/mac/dump_syms.mm
@@ -35,6 +35,7 @@
#include "common/mac/dump_syms.h"
+#include <assert.h>
#include <Foundation/Foundation.h>
#include <mach-o/arch.h>
#include <mach-o/fat.h>
@@ -170,7 +171,7 @@ bool DumpSymbols::Read(NSString *filename) {
// Get our own copy of fat_reader's object file list.
size_t object_files_count;
- const struct fat_arch *object_files =
+ const SuperFatArch *object_files =
fat_reader.object_files(&object_files_count);
if (object_files_count == 0) {
fprintf(stderr, "Fat binary file contains *no* architectures: %s\n",
@@ -179,7 +180,7 @@ bool DumpSymbols::Read(NSString *filename) {
}
object_files_.resize(object_files_count);
memcpy(&object_files_[0], object_files,
- sizeof(struct fat_arch) * object_files_count);
+ sizeof(SuperFatArch) * object_files_count);
return true;
}
@@ -187,9 +188,8 @@ bool DumpSymbols::Read(NSString *filename) {
bool DumpSymbols::SetArchitecture(cpu_type_t cpu_type,
cpu_subtype_t cpu_subtype) {
// Find the best match for the architecture the user requested.
- const struct fat_arch *best_match
- = NXFindBestFatArch(cpu_type, cpu_subtype, &object_files_[0],
- static_cast<uint32_t>(object_files_.size()));
+ const SuperFatArch *best_match = FindBestMatchForArchitecture(
+ cpu_type, cpu_subtype);
if (!best_match) return false;
// Record the selected object file.
@@ -207,6 +207,56 @@ bool DumpSymbols::SetArchitecture(const std::string &arch_name) {
return arch_set;
}
+SuperFatArch* DumpSymbols::FindBestMatchForArchitecture(
+ cpu_type_t cpu_type, cpu_subtype_t cpu_subtype) {
+ // Check if all the object files can be converted to struct fat_arch.
+ bool can_convert_to_fat_arch = true;
+ vector<struct fat_arch> fat_arch_vector;
+ for (vector<SuperFatArch>::const_iterator it = object_files_.begin();
+ it != object_files_.end();
+ ++it) {
+ struct fat_arch arch;
+ bool success = it->ConvertToFatArch(&arch);
+ if (!success) {
+ can_convert_to_fat_arch = false;
+ break;
+ }
+ fat_arch_vector.push_back(arch);
+ }
+
+ // If all the object files can be converted to struct fat_arch, use
+ // NXFindBestFatArch.
+ if (can_convert_to_fat_arch) {
+ const struct fat_arch *best_match
+ = NXFindBestFatArch(cpu_type, cpu_subtype, &fat_arch_vector[0],
+ static_cast<uint32_t>(fat_arch_vector.size()));
+
+ for (size_t i = 0; i < fat_arch_vector.size(); ++i) {
+ if (best_match == &fat_arch_vector[i])
+ return &object_files_[i];
+ }
+ assert(best_match == NULL);
+ return NULL;
+ }
+
+ // Check for an exact match with cpu_type and cpu_subtype.
+ for (vector<SuperFatArch>::iterator it = object_files_.begin();
+ it != object_files_.end();
+ ++it) {
+ if (it->cputype == cpu_type && it->cpusubtype == cpu_subtype)
+ return &*it;
+ }
+
+ // No exact match found.
+ // TODO(erikchen): If it becomes necessary, we can copy the implementation of
+ // NXFindBestFatArch, located at
+ // http://web.mit.edu/darwin/src/modules/cctools/libmacho/arch.c.
+ fprintf(stderr, "Failed to find an exact match for an object file with cpu "
+ "type: %d and cpu subtype: %d. Furthermore, at least one object file is "
+ "larger than 2**32.\n", cpu_type, cpu_subtype);
+ return NULL;
+}
+
string DumpSymbols::Identifier() {
FileID file_id([object_filename_ fileSystemRepresentation]);
unsigned char identifier_bytes[16];
diff --git a/src/common/mac/macho_reader.cc b/src/common/mac/macho_reader.cc
index 84b595a3..9fcb58e3 100644
--- a/src/common/mac/macho_reader.cc
+++ b/src/common/mac/macho_reader.cc
@@ -101,22 +101,26 @@ bool FatReader::Read(const uint8_t *buffer, size_t size) {
// Read the list of object files.
object_files_.resize(object_files_count);
for (size_t i = 0; i < object_files_count; i++) {
- struct fat_arch *objfile = &object_files_[i];
+ struct fat_arch objfile;
// Read this object file entry, byte-swapping as appropriate.
- cursor >> objfile->cputype
- >> objfile->cpusubtype
- >> objfile->offset
- >> objfile->size
- >> objfile->align;
+ cursor >> objfile.cputype
+ >> objfile.cpusubtype
+ >> objfile.offset
+ >> objfile.size
+ >> objfile.align;
+
+ SuperFatArch super_fat_arch(objfile);
+ object_files_[i] = super_fat_arch;
+
if (!cursor) {
reporter_->TooShort();
return false;
}
// Does the file actually have the bytes this entry refers to?
size_t fat_size = buffer_.Size();
- if (objfile->offset > fat_size ||
- objfile->size > fat_size - objfile->offset) {
+ if (objfile.offset > fat_size ||
+ objfile.size > fat_size - objfile.offset) {
reporter_->MisplacedObjectFile();
return false;
}
@@ -139,16 +143,14 @@ bool FatReader::Read(const uint8_t *buffer, size_t size) {
}
object_files_[0].offset = 0;
- object_files_[0].size = static_cast<uint32_t>(buffer_.Size());
+ object_files_[0].size = static_cast<uint64_t>(buffer_.Size());
// This alignment is correct for 32 and 64-bit x86 and ppc.
// See get_align in the lipo source for other architectures:
// http://www.opensource.apple.com/source/cctools/cctools-773/misc/lipo.c
object_files_[0].align = 12; // 2^12 == 4096
-
return true;
}
}
-
reporter_->BadHeader();
return false;
}
@@ -315,7 +317,7 @@ bool Reader::WalkLoadCommands(Reader::LoadCommandHandler *handler) const {
// remainder of the load command series.
ByteBuffer command(list_cursor.here(), list_cursor.Available());
ByteCursor cursor(&command, big_endian_);
-
+
// Read the command type and size --- fields common to all commands.
uint32_t type, size;
if (!(cursor >> type)) {
@@ -400,7 +402,7 @@ bool Reader::WalkLoadCommands(Reader::LoadCommandHandler *handler) const {
return false;
break;
}
-
+
default: {
if (!handler->UnknownCommand(type, command))
return false;
@@ -419,7 +421,7 @@ class Reader::SegmentFinder : public LoadCommandHandler {
public:
// Create a load command handler that looks for a segment named NAME,
// and sets SEGMENT to describe it if found.
- SegmentFinder(const string &name, Segment *segment)
+ SegmentFinder(const string &name, Segment *segment)
: name_(name), segment_(segment), found_() { }
// Return true if the traversal found the segment, false otherwise.
@@ -482,7 +484,7 @@ bool Reader::WalkSegmentSections(const Segment &segment,
if ((section.flags & SECTION_TYPE) == S_ZEROFILL) {
// Zero-fill sections have a size, but no contents.
section.contents.start = section.contents.end = NULL;
- } else if (segment.contents.start == NULL &&
+ } else if (segment.contents.start == NULL &&
segment.contents.end == NULL) {
// Mach-O files in .dSYM bundles have the contents of the loaded
// segments removed, and their file offsets and file sizes zeroed
diff --git a/src/common/mac/macho_reader.h b/src/common/mac/macho_reader.h
index 75376482..30db742d 100644
--- a/src/common/mac/macho_reader.h
+++ b/src/common/mac/macho_reader.h
@@ -47,6 +47,7 @@
#include <vector>
#include "common/byte_cursor.h"
+#include "common/mac/super_fat_arch.h"
namespace google_breakpad {
namespace mach_o {
@@ -93,7 +94,7 @@ class FatReader {
// complete header, or the header implies that contents are present
// beyond the actual end of the file.
virtual void TooShort();
-
+
private:
// The filename to which the reader should attribute problems.
string filename_;
@@ -101,7 +102,7 @@ class FatReader {
// Create a fat binary file reader that uses |reporter| to report problems.
explicit FatReader(Reporter *reporter) : reporter_(reporter) { }
-
+
// Read the |size| bytes at |buffer| as a fat binary file. On success,
// return true; on failure, report the problem to reporter_ and return
// false.
@@ -111,13 +112,13 @@ class FatReader {
// single object file is the Mach-O file.
bool Read(const uint8_t *buffer, size_t size);
- // Return an array of 'struct fat_arch' structures describing the
+ // Return an array of 'SuperFatArch' structures describing the
// object files present in this fat binary file. Set |size| to the
// number of elements in the array.
//
- // Assuming Read returned true, the entries are validated: it is
- // safe to assume that the offsets and sizes in each 'struct
- // fat_arch' refer to subranges of the bytes passed to Read.
+ // Assuming Read returned true, the entries are validated: it is safe to
+ // assume that the offsets and sizes in each SuperFatArch refer to subranges
+ // of the bytes passed to Read.
//
// If there are no object files in this fat binary, then this
// function can return NULL.
@@ -129,7 +130,7 @@ class FatReader {
// possible to use the result with OS X functions like NXFindBestFatArch,
// so that the symbol dumper will behave consistently with other OS X
// utilities that work with fat binaries.
- const struct fat_arch *object_files(size_t *count) const {
+ const SuperFatArch* object_files(size_t *count) const {
*count = object_files_.size();
if (object_files_.size() > 0)
return &object_files_[0];
@@ -149,7 +150,7 @@ class FatReader {
// The list of object files in this binary.
// object_files_.size() == fat_header.nfat_arch
- vector<struct fat_arch> object_files_;
+ vector<SuperFatArch> object_files_;
};
// A segment in a Mach-O file. All these fields have been byte-swapped as
@@ -177,7 +178,7 @@ struct Segment {
// The maximum and initial VM protection of this segment's contents.
uint32_t maxprot;
uint32_t initprot;
-
+
// The number of sections in section_list.
uint32_t nsects;
@@ -376,7 +377,7 @@ class Reader {
return Read(buffer.start,
buffer.Size(),
expected_cpu_type,
- expected_cpu_subtype);
+ expected_cpu_subtype);
}
// Return this file's characteristics, as found in the Mach-O header.
diff --git a/src/common/mac/super_fat_arch.h b/src/common/mac/super_fat_arch.h
new file mode 100644
index 00000000..501c8652
--- /dev/null
+++ b/src/common/mac/super_fat_arch.h
@@ -0,0 +1,88 @@
+// Copyright (c) 2015, 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.
+
+// Original author: Erik Chen <erikchen@chromium.org>
+
+// super_fat_arch.h: A class to handle 64-bit object files. Has conversions to
+// and from struct fat_arch.
+
+#ifndef BREAKPAD_COMMON_MAC_SUPER_FAT_ARCH_H_
+#define BREAKPAD_COMMON_MAC_SUPER_FAT_ARCH_H_
+
+#include <limits>
+#include <mach-o/fat.h>
+#include <stdint.h>
+
+// Similar to struct fat_arch, except size-related parameters support
+// 64-bits.
+class SuperFatArch {
+ public:
+ uint32_t cputype;
+ uint32_t cpusubtype;
+ uint64_t offset;
+ uint64_t size;
+ uint64_t align;
+
+ SuperFatArch() :
+ cputype(0),
+ cpusubtype(0),
+ offset(0),
+ size(0),
+ align(0) {
+ }
+
+ explicit SuperFatArch(const struct fat_arch &arch) :
+ cputype(arch.cputype),
+ cpusubtype(arch.cpusubtype),
+ offset(arch.offset),
+ size(arch.size),
+ align(arch.align) {
+ }
+
+ // Returns false if the conversion cannot be made.
+ // If the conversion succeeds, the result is placed in |output_arch|.
+ bool ConvertToFatArch(struct fat_arch* output_arch) const {
+ if (offset > std::numeric_limits<uint32_t>::max())
+ return false;
+ if (size > std::numeric_limits<uint32_t>::max())
+ return false;
+ if (align > std::numeric_limits<uint32_t>::max())
+ return false;
+ struct fat_arch arch;
+ arch.cputype = cputype;
+ arch.cpusubtype = cpusubtype;
+ arch.offset = offset;
+ arch.size = size;
+ arch.align = align;
+ *output_arch = arch;
+ return true;
+ }
+};
+
+#endif // BREAKPAD_COMMON_MAC_SUPER_FAT_ARCH_H_
diff --git a/src/tools/mac/dump_syms/dump_syms_tool.mm b/src/tools/mac/dump_syms/dump_syms_tool.mm
index 1880cd3b..7d56809a 100644
--- a/src/tools/mac/dump_syms/dump_syms_tool.mm
+++ b/src/tools/mac/dump_syms/dump_syms_tool.mm
@@ -126,14 +126,14 @@ static bool Start(const Options &options) {
fprintf(stderr, "%s: no architecture '%s' is present in file.\n",
[primary_file fileSystemRepresentation], options.arch->name);
size_t available_size;
- const struct fat_arch *available =
+ const SuperFatArch *available =
dump_symbols.AvailableArchitectures(&available_size);
if (available_size == 1)
fprintf(stderr, "the file's architecture is: ");
else
fprintf(stderr, "architectures present in the file are:\n");
for (size_t i = 0; i < available_size; i++) {
- const struct fat_arch *arch = &available[i];
+ const SuperFatArch *arch = &available[i];
const NXArchInfo *arch_info =
google_breakpad::BreakpadGetArchInfoFromCpuType(
arch->cputype, arch->cpusubtype);