Support object files larger than 2**32.
Reviewed at https://breakpad.appspot.com/7834002/#ps340001 git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1453 4c0a9323-5329-0410-9bdc-e9ce6186880e
This commit is contained in:
parent
0f27af628f
commit
aa75fa5d4e
7 changed files with 189 additions and 40 deletions
|
@ -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',
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
88
src/common/mac/super_fat_arch.h
Normal file
88
src/common/mac/super_fat_arch.h
Normal file
|
@ -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_
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue