Breakpad Mac symbol dumper: Unify with Linux dumper; support DWARF CFI.

This patch rewrites the Mac symbol dumper to use the same set of classes
the Linux dumper does for reading debugging information from various
sources, consolidating them into a single table, and writing that out as a
Breakpad symbol file.

In the process, it also adds support for dumping DWARF call frame
information and .eh_frame exception-handling information as Breakpad 'STACK
CFI' records. This allows the Breakpad processor to generate stack traces
from code compiled with -fomit-frame-pointer.

The patch also replaces the DumpSymbols Objective C++ class with
google_breakpad::DumpSymbols, a plain C++ class. The code still uses some
Objective C++ to use the Foundation facilities for dealing with file names
in a file-system-independent fashion, and for examining the contents of
.dSYM bundles.

Since the code has been entirely rewritten, I have changed the author
lines.
A=jimb R=mark

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@614 4c0a9323-5329-0410-9bdc-e9ce6186880e
This commit is contained in:
ted.mielczarek 2010-06-25 16:56:42 +00:00
parent 9c1e16eaaa
commit 1adc07f0ff
5 changed files with 632 additions and 1228 deletions

View File

@ -1,4 +1,6 @@
// Copyright (c) 2006, Google Inc.
// -*- mode: c++ -*-
// Copyright (c) 2010, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@ -27,53 +29,133 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// dump_syms.h: Interface for DumpSymbols. This class will take a mach-o file
// and extract the symbol information and write it to a file using the
// breakpad symbol file format.
// Author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
#import <Foundation/Foundation.h>
// dump_syms.h: Declaration of google_breakpad::DumpSymbols, a class for
// 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 "common/dwarf/dwarf2reader.h"
#include <stdio.h>
#include <stdlib.h>
// This will map from an architecture string to a SectionMap, which
// will contain the offsets for all the sections in the dictionary
typedef map<string, dwarf2reader::SectionMap *> ArchSectionMap;
#include <string>
#include <vector>
@interface DumpSymbols : NSObject {
@protected
NSString *sourcePath_; // Source of symbols (STRONG)
NSString *architecture_; // Architecture to extract (STRONG)
NSMutableDictionary *addresses_; // Addresses and symbols (STRONG)
NSMutableSet *functionAddresses_; // Function addresses (STRONG)
NSMutableDictionary *sources_; // Address and Source file paths (STRONG)
NSMutableDictionary *headers_; // Mach-o header information (STRONG)
NSMutableDictionary *sectionData_; // Keyed by seg/sect name (STRONG)
uint32_t lastStartAddress_;
ArchSectionMap *sectionsForArch_;
}
#include "common/byte_cursor.h"
#include "common/mac/macho_reader.h"
#include "common/module.h"
- (id)initWithContentsOfFile:(NSString *)machoFile;
namespace google_breakpad {
- (NSArray *)availableArchitectures;
class DumpSymbols {
public:
DumpSymbols()
: input_pathname_(),
object_filename_(),
contents_(),
selected_object_file_(),
selected_object_name_() { }
~DumpSymbols() {
[input_pathname_ release];
[object_filename_ release];
[contents_ release];
}
// One of ppc, x86, i386, ppc64, x86_64
// If the architecture is not available, it will return NO
// If not set, the native architecture will be used
- (BOOL)setArchitecture:(NSString *)architecture;
- (NSString *)architecture;
// 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);
// Write the symbols to |symbolFilePath|. Return YES if successful.
- (BOOL)writeSymbolFile:(NSString *)symbolFilePath;
// If this dumper's file includes an object file for |cpu_type| and
// |cpu_subtype|, then select that object file for dumping, and return
// true. Otherwise, return false, and leave this dumper's selected
// architecture unchanged.
//
// By default, if this dumper's file contains only one object file, then
// the dumper will dump those symbols; and if it contains more than one
// object file, then the dumper will dump the object file whose
// architecture matches that of this dumper program.
bool SetArchitecture(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype);
@end
// 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.
//
// If there are no available architectures, this function
// may return NULL.
const struct fat_arch *AvailableArchitectures(size_t *count) {
*count = object_files_.size();
if (object_files_.size() > 0)
return &object_files_[0];
return NULL;
}
@interface MachSection : NSObject {
@protected
struct section *sect_;
uint32_t sectionNumber_;
}
- (id)initWithMachSection:(struct section *)sect andNumber:(uint32_t)sectionNumber;
- (struct section*)sectionPointer;
- (uint32_t)sectionNumber;
// Read the selected object file's debugging information, and write it
// out to |stream|. Return true on success; if an error occurs, report it
// and return false.
bool WriteSymbolFile(FILE *stream);
@end
private:
// Used internally.
class DumperLineToModule;
class LoadCommandDumper;
// Return an identifier string for the file this DumpSymbols is dumping.
std::string Identifier();
// Read debugging information from |dwarf_sections|, which was taken from
// |macho_reader|, and add it to |module|. On success, return true;
// on failure, report the problem and return false.
bool ReadDwarf(google_breakpad::Module *module,
const mach_o::Reader &macho_reader,
const mach_o::SectionMap &dwarf_sections) const;
// Read DWARF CFI or .eh_frame data from |section|, belonging to
// |macho_reader|, and record it in |module|. If |eh_frame| is true,
// then the data is .eh_frame-format data; otherwise, it is standard DWARF
// .debug_frame data. On success, return true; on failure, report
// the problem and return false.
bool ReadCFI(google_breakpad::Module *module,
const mach_o::Reader &macho_reader,
const mach_o::Section &section,
bool eh_frame) const;
// 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_;
// 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_;
// The complete contents of object_filename_, mapped into memory.
NSData *contents_;
// A vector of fat_arch 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_;
// 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_;
// A string that identifies the selected object file, for use in error
// messages. This is usually object_filename_, but if that refers to a
// fat binary, it includes an indication of the particular architecture
// within that binary.
string selected_object_name_;
};
} // namespace google_breakpad

File diff suppressed because it is too large Load Diff

View File

@ -62,22 +62,11 @@ MachoWalker::~MachoWalker() {
}
int MachoWalker::ValidateCPUType(int cpu_type) {
// If the user didn't specify, try to use the local architecture. If that
// fails, use the base type for the executable.
// If the user didn't specify, use the local architecture.
if (cpu_type == 0) {
const NXArchInfo *arch = NXGetLocalArchInfo();
if (arch)
cpu_type = arch->cputype;
else
#if __ppc__
cpu_type = CPU_TYPE_POWERPC;
#elif __i386__
cpu_type = CPU_TYPE_X86;
#elif __x86_64__
cpu_type = CPU_TYPE_X86_64;
#else
#error Unknown architecture -- are you on a PDP-11?
#endif
assert(arch);
cpu_type = arch->cputype;
}
return cpu_type;

View File

@ -8,6 +8,15 @@
/* Begin PBXBuildFile section */
B88FAE0B11665B5700407530 /* test_assembler.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FAE0911665B5700407530 /* test_assembler.cc */; };
B88FAE1911665FE400407530 /* dwarf2diehandler.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FAE1711665FE400407530 /* dwarf2diehandler.cc */; };
B88FAE261166603300407530 /* dwarf_cu_to_module.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FAE1E1166603300407530 /* dwarf_cu_to_module.cc */; };
B88FAE271166603300407530 /* dwarf_line_to_module.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FAE201166603300407530 /* dwarf_line_to_module.cc */; };
B88FAE281166603300407530 /* language.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FAE221166603300407530 /* language.cc */; };
B88FAE291166603300407530 /* module.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FAE241166603300407530 /* module.cc */; };
B88FAE2C1166606200407530 /* macho_reader.cc in Sources */ = {isa = PBXBuildFile; fileRef = B89E0E6E1166571D00DD08C9 /* macho_reader.cc */; };
B88FAE351166673E00407530 /* dwarf_cfi_to_module.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FAE331166673E00407530 /* dwarf_cfi_to_module.cc */; };
B88FAE3B11666C6F00407530 /* stabs_reader.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FAE3911666C6F00407530 /* stabs_reader.cc */; settings = {COMPILER_FLAGS = "-DHAVE_MACH_O_NLIST_H"; }; };
B88FAE3E11666C8900407530 /* stabs_to_module.cc in Sources */ = {isa = PBXBuildFile; fileRef = B88FAE3C11666C8900407530 /* stabs_to_module.cc */; };
B89E0E601166556C00DD08C9 /* libcrypto.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = B89E0E5F1166556C00DD08C9 /* libcrypto.dylib */; };
B89E0E781166576C00DD08C9 /* macho_reader.cc in Sources */ = {isa = PBXBuildFile; fileRef = B89E0E6E1166571D00DD08C9 /* macho_reader.cc */; };
B89E0E7A1166576C00DD08C9 /* macho_dump.cc in Sources */ = {isa = PBXBuildFile; fileRef = B89E0E701166573700DD08C9 /* macho_dump.cc */; };
@ -16,7 +25,6 @@
B89E0EA111665AC300DD08C9 /* gtest_main.cc in Sources */ = {isa = PBXBuildFile; fileRef = B89E0E9F11665AC300DD08C9 /* gtest_main.cc */; };
B89E0EA211665AC300DD08C9 /* gtest-all.cc in Sources */ = {isa = PBXBuildFile; fileRef = B89E0EA011665AC300DD08C9 /* gtest-all.cc */; };
B89E0EA411665AEA00DD08C9 /* gmock-all.cc in Sources */ = {isa = PBXBuildFile; fileRef = B89E0EA311665AEA00DD08C9 /* gmock-all.cc */; };
B8C5B5161166534700D34F4E /* functioninfo.cc in Sources */ = {isa = PBXBuildFile; fileRef = F9C7ED420E8AD93000E953AD /* functioninfo.cc */; };
B8C5B5171166534700D34F4E /* dwarf2reader.cc in Sources */ = {isa = PBXBuildFile; fileRef = F95B422F0E0E22D100DBDE83 /* dwarf2reader.cc */; };
B8C5B5181166534700D34F4E /* bytereader.cc in Sources */ = {isa = PBXBuildFile; fileRef = F95B422C0E0E22D100DBDE83 /* bytereader.cc */; };
B8C5B5191166534700D34F4E /* macho_utilities.cc in Sources */ = {isa = PBXBuildFile; fileRef = 557800890BE1F3AB00EC23E0 /* macho_utilities.cc */; };
@ -43,6 +51,23 @@
9BE650460B52F6D800611104 /* macho_walker.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = macho_walker.h; path = ../../../common/mac/macho_walker.h; sourceTree = SOURCE_ROOT; };
B88FAE0911665B5700407530 /* test_assembler.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = test_assembler.cc; path = ../../../common/test_assembler.cc; sourceTree = SOURCE_ROOT; };
B88FAE0A11665B5700407530 /* test_assembler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = test_assembler.h; path = ../../../common/test_assembler.h; sourceTree = SOURCE_ROOT; };
B88FAE1711665FE400407530 /* dwarf2diehandler.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf2diehandler.cc; path = ../../../common/dwarf/dwarf2diehandler.cc; sourceTree = SOURCE_ROOT; };
B88FAE1811665FE400407530 /* dwarf2diehandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf2diehandler.h; path = ../../../common/dwarf/dwarf2diehandler.h; sourceTree = SOURCE_ROOT; };
B88FAE1D1166603300407530 /* byte_cursor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = byte_cursor.h; path = ../../../common/byte_cursor.h; sourceTree = SOURCE_ROOT; };
B88FAE1E1166603300407530 /* dwarf_cu_to_module.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf_cu_to_module.cc; path = ../../../common/dwarf_cu_to_module.cc; sourceTree = SOURCE_ROOT; };
B88FAE1F1166603300407530 /* dwarf_cu_to_module.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf_cu_to_module.h; path = ../../../common/dwarf_cu_to_module.h; sourceTree = SOURCE_ROOT; };
B88FAE201166603300407530 /* dwarf_line_to_module.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf_line_to_module.cc; path = ../../../common/dwarf_line_to_module.cc; sourceTree = SOURCE_ROOT; };
B88FAE211166603300407530 /* dwarf_line_to_module.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf_line_to_module.h; path = ../../../common/dwarf_line_to_module.h; sourceTree = SOURCE_ROOT; };
B88FAE221166603300407530 /* language.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = language.cc; path = ../../../common/language.cc; sourceTree = SOURCE_ROOT; };
B88FAE231166603300407530 /* language.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = language.h; path = ../../../common/language.h; sourceTree = SOURCE_ROOT; };
B88FAE241166603300407530 /* module.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = module.cc; path = ../../../common/module.cc; sourceTree = SOURCE_ROOT; };
B88FAE251166603300407530 /* module.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = module.h; path = ../../../common/module.h; sourceTree = SOURCE_ROOT; };
B88FAE331166673E00407530 /* dwarf_cfi_to_module.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf_cfi_to_module.cc; path = ../../../common/dwarf_cfi_to_module.cc; sourceTree = SOURCE_ROOT; };
B88FAE341166673E00407530 /* dwarf_cfi_to_module.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf_cfi_to_module.h; path = ../../../common/dwarf_cfi_to_module.h; sourceTree = SOURCE_ROOT; };
B88FAE3911666C6F00407530 /* stabs_reader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = stabs_reader.cc; path = ../../../common/stabs_reader.cc; sourceTree = SOURCE_ROOT; };
B88FAE3A11666C6F00407530 /* stabs_reader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = stabs_reader.h; path = ../../../common/stabs_reader.h; sourceTree = SOURCE_ROOT; };
B88FAE3C11666C8900407530 /* stabs_to_module.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = stabs_to_module.cc; path = ../../../common/stabs_to_module.cc; sourceTree = SOURCE_ROOT; };
B88FAE3D11666C8900407530 /* stabs_to_module.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = stabs_to_module.h; path = ../../../common/stabs_to_module.h; sourceTree = SOURCE_ROOT; };
B89E0E5F1166556C00DD08C9 /* libcrypto.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libcrypto.dylib; path = /usr/lib/libcrypto.dylib; sourceTree = "<absolute>"; };
B89E0E6D1166571D00DD08C9 /* macho_reader_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = macho_reader_unittest.cc; path = ../../../common/mac/macho_reader_unittest.cc; sourceTree = SOURCE_ROOT; };
B89E0E6E1166571D00DD08C9 /* macho_reader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = macho_reader.cc; path = ../../../common/mac/macho_reader.cc; sourceTree = SOURCE_ROOT; };
@ -62,8 +87,6 @@
F95B422F0E0E22D100DBDE83 /* dwarf2reader.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = dwarf2reader.cc; path = ../../../common/dwarf/dwarf2reader.cc; sourceTree = SOURCE_ROOT; };
F95B42300E0E22D100DBDE83 /* dwarf2reader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dwarf2reader.h; path = ../../../common/dwarf/dwarf2reader.h; sourceTree = SOURCE_ROOT; };
F95B42310E0E22D100DBDE83 /* line_state_machine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = line_state_machine.h; path = ../../../common/dwarf/line_state_machine.h; sourceTree = SOURCE_ROOT; };
F9C7ED420E8AD93000E953AD /* functioninfo.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = functioninfo.cc; path = ../../../common/dwarf/functioninfo.cc; sourceTree = SOURCE_ROOT; };
F9F5344D0E7C902C0012363F /* functioninfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = functioninfo.h; path = ../../../common/dwarf/functioninfo.h; sourceTree = SOURCE_ROOT; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -99,6 +122,8 @@
B89E0E9D11665A9500DD08C9 /* TESTING */,
F9F5344B0E7C8FFC0012363F /* DWARF */,
B89E0E6C1166569700DD08C9 /* MACHO */,
B88FAE3811666A1700407530 /* STABS */,
B88FAE1C11665FFD00407530 /* MODULE */,
B8E8CA0C1156C854009E61B2 /* byteswap.h */,
9BE650410B52F6D800611104 /* file_id.cc */,
9BE650420B52F6D800611104 /* file_id.h */,
@ -131,6 +156,35 @@
name = Products;
sourceTree = "<group>";
};
B88FAE1C11665FFD00407530 /* MODULE */ = {
isa = PBXGroup;
children = (
B88FAE1D1166603300407530 /* byte_cursor.h */,
B88FAE1E1166603300407530 /* dwarf_cu_to_module.cc */,
B88FAE1F1166603300407530 /* dwarf_cu_to_module.h */,
B88FAE201166603300407530 /* dwarf_line_to_module.cc */,
B88FAE211166603300407530 /* dwarf_line_to_module.h */,
B88FAE221166603300407530 /* language.cc */,
B88FAE231166603300407530 /* language.h */,
B88FAE241166603300407530 /* module.cc */,
B88FAE251166603300407530 /* module.h */,
B88FAE331166673E00407530 /* dwarf_cfi_to_module.cc */,
B88FAE341166673E00407530 /* dwarf_cfi_to_module.h */,
B88FAE3C11666C8900407530 /* stabs_to_module.cc */,
B88FAE3D11666C8900407530 /* stabs_to_module.h */,
);
name = MODULE;
sourceTree = "<group>";
};
B88FAE3811666A1700407530 /* STABS */ = {
isa = PBXGroup;
children = (
B88FAE3911666C6F00407530 /* stabs_reader.cc */,
B88FAE3A11666C6F00407530 /* stabs_reader.h */,
);
name = STABS;
sourceTree = "<group>";
};
B89E0E6C1166569700DD08C9 /* MACHO */ = {
isa = PBXGroup;
children = (
@ -162,8 +216,6 @@
F9F5344B0E7C8FFC0012363F /* DWARF */ = {
isa = PBXGroup;
children = (
F9C7ED420E8AD93000E953AD /* functioninfo.cc */,
F9F5344D0E7C902C0012363F /* functioninfo.h */,
F95B422E0E0E22D100DBDE83 /* dwarf2enums.h */,
F95B422F0E0E22D100DBDE83 /* dwarf2reader.cc */,
F95B42300E0E22D100DBDE83 /* dwarf2reader.h */,
@ -171,6 +223,8 @@
F95B422B0E0E22D100DBDE83 /* bytereader-inl.h */,
F95B422C0E0E22D100DBDE83 /* bytereader.cc */,
F95B42310E0E22D100DBDE83 /* line_state_machine.h */,
B88FAE1711665FE400407530 /* dwarf2diehandler.cc */,
B88FAE1811665FE400407530 /* dwarf2diehandler.h */,
);
name = DWARF;
sourceTree = "<group>";
@ -231,9 +285,6 @@
/* Begin PBXProject section */
08FB7793FE84155DC02AAC07 /* Project object */ = {
isa = PBXProject;
attributes = {
BuildIndependentTargetsInParallel = NO;
};
buildConfigurationList = 1DEB927808733DD40010E9CD /* Build configuration list for PBXProject "dump_syms" */;
compatibilityVersion = "Xcode 2.4";
hasScannedForEncodings = 1;
@ -275,7 +326,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
B8C5B5161166534700D34F4E /* functioninfo.cc in Sources */,
B88FAE2C1166606200407530 /* macho_reader.cc in Sources */,
B8C5B5171166534700D34F4E /* dwarf2reader.cc in Sources */,
B8C5B5181166534700D34F4E /* bytereader.cc in Sources */,
B8C5B5191166534700D34F4E /* macho_utilities.cc in Sources */,
@ -284,6 +335,14 @@
B8C5B51C1166534700D34F4E /* macho_walker.cc in Sources */,
B8C5B51D1166534700D34F4E /* dump_syms.mm in Sources */,
B8C5B51E1166534700D34F4E /* dump_syms_tool.mm in Sources */,
B88FAE1911665FE400407530 /* dwarf2diehandler.cc in Sources */,
B88FAE261166603300407530 /* dwarf_cu_to_module.cc in Sources */,
B88FAE271166603300407530 /* dwarf_line_to_module.cc in Sources */,
B88FAE281166603300407530 /* language.cc in Sources */,
B88FAE291166603300407530 /* module.cc in Sources */,
B88FAE351166673E00407530 /* dwarf_cfi_to_module.cc in Sources */,
B88FAE3B11666C6F00407530 /* stabs_reader.cc in Sources */,
B88FAE3E11666C8900407530 /* stabs_to_module.cc in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

View File

@ -35,9 +35,14 @@
#include <mach-o/arch.h>
#include <unistd.h>
#include <vector>
#include "common/mac/dump_syms.h"
#include "common/mac/macho_utilities.h"
using google_breakpad::DumpSymbols;
using std::vector;
struct Options {
Options() : srcPath(), arch() { }
NSString *srcPath;
@ -46,24 +51,38 @@ struct Options {
//=============================================================================
static bool Start(const Options &options) {
DumpSymbols *dump = [[DumpSymbols alloc]
initWithContentsOfFile:options.srcPath];
if (!dump) {
fprintf(stderr, "%s is not a valid Mach-o file\n",
[options.srcPath fileSystemRepresentation]);
return false;
}
DumpSymbols dump_symbols;
if (![dump setArchitecture:[NSString
stringWithUTF8String:options.arch->name]]) {
fprintf(stderr, "Architecture: %s not available in %s\n",
options.arch->name,
[options.srcPath fileSystemRepresentation]);
if (!dump_symbols.Read(options.srcPath))
return false;
if (options.arch) {
if (!dump_symbols.SetArchitecture(options.arch->cputype,
options.arch->cpusubtype)) {
fprintf(stderr, "%s: no architecture '%s' is present in file.\n",
[options.srcPath fileSystemRepresentation], options.arch->name);
size_t available_size;
const struct fat_arch *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 NXArchInfo *arch_info =
NXGetArchInfoFromCpuType(arch->cputype, arch->cpusubtype);
if (arch_info)
fprintf(stderr, "%s (%s)\n", arch_info->name, arch_info->description);
else
fprintf(stderr, "unrecognized cpu type 0x%x, subtype 0x%x\n",
arch->cputype, arch->cpusubtype);
}
return false;
}
}
return [dump writeSymbolFile:@"-"];
return dump_symbols.WriteSymbolFile(stdout);
}
//=============================================================================
@ -71,7 +90,8 @@ static void Usage(int argc, const char *argv[]) {
fprintf(stderr, "Output a Breakpad symbol file from a Mach-o file.\n");
fprintf(stderr, "Usage: %s [-a ARCHITECTURE] <Mach-o file>\n",
argv[0]);
fprintf(stderr, "\t-a: Architecture type [default: native]\n");
fprintf(stderr, "\t-a: Architecture type [default: native, or whatever is\n");
fprintf(stderr, "\t in the file, if it contains only one architecture]\n");
fprintf(stderr, "\t-h: Usage\n");
fprintf(stderr, "\t-?: Usage\n");
}
@ -81,8 +101,6 @@ static void SetupOptions(int argc, const char *argv[], Options *options) {
extern int optind;
signed char ch;
options->arch = NXGetLocalArchInfo();
while ((ch = getopt(argc, (char * const *)argv, "a:h?")) != -1) {
switch (ch) {
case 'a': {