mirror of
https://github.com/yuzu-emu/breakpad.git
synced 2024-12-23 23:25:33 +00:00
Linux/Mac: Add option to omit the CFI section in dump_syms.
Review URL: http://breakpad.appspot.com/304001 git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@835 4c0a9323-5329-0410-9bdc-e9ce6186880e
This commit is contained in:
parent
912c99fc8e
commit
8d54c75092
|
@ -1,4 +1,4 @@
|
||||||
// Copyright (c) 2010 Google Inc.
|
// Copyright (c) 2011 Google Inc.
|
||||||
// All rights reserved.
|
// All rights reserved.
|
||||||
//
|
//
|
||||||
// Redistribution and use in source and binary forms, with or without
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
@ -728,6 +728,7 @@ namespace google_breakpad {
|
||||||
bool WriteSymbolFileInternal(uint8_t* obj_file,
|
bool WriteSymbolFileInternal(uint8_t* obj_file,
|
||||||
const std::string &obj_filename,
|
const std::string &obj_filename,
|
||||||
const std::string &debug_dir,
|
const std::string &debug_dir,
|
||||||
|
bool cfi,
|
||||||
std::ostream &sym_stream) {
|
std::ostream &sym_stream) {
|
||||||
ElfW(Ehdr) *elf_header = reinterpret_cast<ElfW(Ehdr) *>(obj_file);
|
ElfW(Ehdr) *elf_header = reinterpret_cast<ElfW(Ehdr) *>(obj_file);
|
||||||
|
|
||||||
|
@ -803,7 +804,7 @@ bool WriteSymbolFileInternal(uint8_t* obj_file,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!module.Write(sym_stream))
|
if (!module.Write(sym_stream, cfi))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -811,6 +812,7 @@ bool WriteSymbolFileInternal(uint8_t* obj_file,
|
||||||
|
|
||||||
bool WriteSymbolFile(const std::string &obj_file,
|
bool WriteSymbolFile(const std::string &obj_file,
|
||||||
const std::string &debug_dir,
|
const std::string &debug_dir,
|
||||||
|
bool cfi,
|
||||||
std::ostream &sym_stream) {
|
std::ostream &sym_stream) {
|
||||||
MmapWrapper map_wrapper;
|
MmapWrapper map_wrapper;
|
||||||
ElfW(Ehdr) *elf_header = NULL;
|
ElfW(Ehdr) *elf_header = NULL;
|
||||||
|
@ -818,7 +820,7 @@ bool WriteSymbolFile(const std::string &obj_file,
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return WriteSymbolFileInternal(reinterpret_cast<uint8_t*>(elf_header),
|
return WriteSymbolFileInternal(reinterpret_cast<uint8_t*>(elf_header),
|
||||||
obj_file, debug_dir, sym_stream);
|
obj_file, debug_dir, cfi, sym_stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace google_breakpad
|
} // namespace google_breakpad
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// -*- mode: c++ -*-
|
// -*- mode: c++ -*-
|
||||||
|
|
||||||
// Copyright (c) 2010, Google Inc.
|
// Copyright (c) 2011, Google Inc.
|
||||||
// All rights reserved.
|
// All rights reserved.
|
||||||
//
|
//
|
||||||
// Redistribution and use in source and binary forms, with or without
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
@ -45,8 +45,10 @@ namespace google_breakpad {
|
||||||
// file format.
|
// file format.
|
||||||
// If OBJ_FILE has been stripped but contains a .gnu_debuglink section,
|
// If OBJ_FILE has been stripped but contains a .gnu_debuglink section,
|
||||||
// then look for the debug file in DEBUG_DIR.
|
// then look for the debug file in DEBUG_DIR.
|
||||||
|
// If CFI is set to false, then omit the CFI section.
|
||||||
bool WriteSymbolFile(const std::string &obj_file,
|
bool WriteSymbolFile(const std::string &obj_file,
|
||||||
const std::string &debug_dir,
|
const std::string &debug_dir,
|
||||||
|
bool cfi,
|
||||||
std::ostream &sym_stream);
|
std::ostream &sym_stream);
|
||||||
|
|
||||||
} // namespace google_breakpad
|
} // namespace google_breakpad
|
||||||
|
|
|
@ -47,6 +47,7 @@ namespace google_breakpad {
|
||||||
bool WriteSymbolFileInternal(uint8_t* obj_file,
|
bool WriteSymbolFileInternal(uint8_t* obj_file,
|
||||||
const std::string &obj_filename,
|
const std::string &obj_filename,
|
||||||
const std::string &debug_dir,
|
const std::string &debug_dir,
|
||||||
|
bool cfi,
|
||||||
std::ostream &sym_stream);
|
std::ostream &sym_stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,7 +63,7 @@ using std::vector;
|
||||||
using ::testing::Test;
|
using ::testing::Test;
|
||||||
|
|
||||||
class DumpSymbols : public Test {
|
class DumpSymbols : public Test {
|
||||||
public:
|
public:
|
||||||
void GetElfContents(ELF& elf) {
|
void GetElfContents(ELF& elf) {
|
||||||
string contents;
|
string contents;
|
||||||
ASSERT_TRUE(elf.GetContents(&contents));
|
ASSERT_TRUE(elf.GetContents(&contents));
|
||||||
|
@ -84,6 +85,7 @@ TEST_F(DumpSymbols, Invalid) {
|
||||||
EXPECT_FALSE(WriteSymbolFileInternal(reinterpret_cast<uint8_t*>(&header),
|
EXPECT_FALSE(WriteSymbolFileInternal(reinterpret_cast<uint8_t*>(&header),
|
||||||
"foo",
|
"foo",
|
||||||
"",
|
"",
|
||||||
|
true,
|
||||||
s));
|
s));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,11 +107,11 @@ TEST_F(DumpSymbols, SimplePublic32) {
|
||||||
SHN_UNDEF + 1);
|
SHN_UNDEF + 1);
|
||||||
int index = elf.AddSection(".dynstr", table, SHT_STRTAB);
|
int index = elf.AddSection(".dynstr", table, SHT_STRTAB);
|
||||||
elf.AddSection(".dynsym", syms,
|
elf.AddSection(".dynsym", syms,
|
||||||
SHT_DYNSYM, // type
|
SHT_DYNSYM, // type
|
||||||
SHF_ALLOC, // flags
|
SHF_ALLOC, // flags
|
||||||
0, // addr
|
0, // addr
|
||||||
index, // link
|
index, // link
|
||||||
sizeof(Elf32_Sym)); // entsize
|
sizeof(Elf32_Sym)); // entsize
|
||||||
|
|
||||||
elf.Finish();
|
elf.Finish();
|
||||||
GetElfContents(elf);
|
GetElfContents(elf);
|
||||||
|
@ -118,6 +120,7 @@ TEST_F(DumpSymbols, SimplePublic32) {
|
||||||
ASSERT_TRUE(WriteSymbolFileInternal(elfdata,
|
ASSERT_TRUE(WriteSymbolFileInternal(elfdata,
|
||||||
"foo",
|
"foo",
|
||||||
"",
|
"",
|
||||||
|
true,
|
||||||
s));
|
s));
|
||||||
EXPECT_EQ("MODULE Linux x86 000000000000000000000000000000000 foo\n"
|
EXPECT_EQ("MODULE Linux x86 000000000000000000000000000000000 foo\n"
|
||||||
"PUBLIC 1000 0 superfunc\n",
|
"PUBLIC 1000 0 superfunc\n",
|
||||||
|
@ -141,11 +144,11 @@ TEST_F(DumpSymbols, SimplePublic64) {
|
||||||
SHN_UNDEF + 1);
|
SHN_UNDEF + 1);
|
||||||
int index = elf.AddSection(".dynstr", table, SHT_STRTAB);
|
int index = elf.AddSection(".dynstr", table, SHT_STRTAB);
|
||||||
elf.AddSection(".dynsym", syms,
|
elf.AddSection(".dynsym", syms,
|
||||||
SHT_DYNSYM, // type
|
SHT_DYNSYM, // type
|
||||||
SHF_ALLOC, // flags
|
SHF_ALLOC, // flags
|
||||||
0, // addr
|
0, // addr
|
||||||
index, // link
|
index, // link
|
||||||
sizeof(Elf64_Sym)); // entsize
|
sizeof(Elf64_Sym)); // entsize
|
||||||
|
|
||||||
elf.Finish();
|
elf.Finish();
|
||||||
GetElfContents(elf);
|
GetElfContents(elf);
|
||||||
|
@ -154,6 +157,7 @@ TEST_F(DumpSymbols, SimplePublic64) {
|
||||||
ASSERT_TRUE(WriteSymbolFileInternal(elfdata,
|
ASSERT_TRUE(WriteSymbolFileInternal(elfdata,
|
||||||
"foo",
|
"foo",
|
||||||
"",
|
"",
|
||||||
|
true,
|
||||||
s));
|
s));
|
||||||
EXPECT_EQ("MODULE Linux x86_64 000000000000000000000000000000000 foo\n"
|
EXPECT_EQ("MODULE Linux x86_64 000000000000000000000000000000000 foo\n"
|
||||||
"PUBLIC 1000 0 superfunc\n",
|
"PUBLIC 1000 0 superfunc\n",
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// -*- mode: c++ -*-
|
// -*- mode: c++ -*-
|
||||||
|
|
||||||
// Copyright (c) 2010, Google Inc.
|
// Copyright (c) 2011, Google Inc.
|
||||||
// All rights reserved.
|
// All rights reserved.
|
||||||
//
|
//
|
||||||
// Redistribution and use in source and binary forms, with or without
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
@ -109,10 +109,10 @@ class DumpSymbols {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read the selected object file's debugging information, and write it
|
// Read the selected object file's debugging information, and write it out to
|
||||||
// out to |stream|. Return true on success; if an error occurs, report it
|
// |stream|. Write the CFI section if |cfi| is true. Return true on success;
|
||||||
// and return false.
|
// if an error occurs, report it and return false.
|
||||||
bool WriteSymbolFile(std::ostream &stream);
|
bool WriteSymbolFile(std::ostream &stream, bool cfi);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Used internally.
|
// Used internally.
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// -*- mode: c++ -*-
|
// -*- mode: c++ -*-
|
||||||
|
|
||||||
// Copyright (c) 2010, Google Inc.
|
// Copyright (c) 2011, Google Inc.
|
||||||
// All rights reserved.
|
// All rights reserved.
|
||||||
//
|
//
|
||||||
// Redistribution and use in source and binary forms, with or without
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
@ -79,7 +79,7 @@ namespace google_breakpad {
|
||||||
bool DumpSymbols::Read(NSString *filename) {
|
bool DumpSymbols::Read(NSString *filename) {
|
||||||
if (![[NSFileManager defaultManager] fileExistsAtPath:filename]) {
|
if (![[NSFileManager defaultManager] fileExistsAtPath:filename]) {
|
||||||
fprintf(stderr, "Object file does not exist: %s\n",
|
fprintf(stderr, "Object file does not exist: %s\n",
|
||||||
[filename fileSystemRepresentation]);
|
[filename fileSystemRepresentation]);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,8 +108,8 @@ bool DumpSymbols::Read(NSString *filename) {
|
||||||
// If stringByDeletingPathExtension returned the name unchanged, then
|
// If stringByDeletingPathExtension returned the name unchanged, then
|
||||||
// there's nothing more for us to strip off --- lose.
|
// there's nothing more for us to strip off --- lose.
|
||||||
if ([new_base_name isEqualToString:base_name]) {
|
if ([new_base_name isEqualToString:base_name]) {
|
||||||
fprintf(stderr, "Unable to find DWARF-bearing file in bundle: %s\n",
|
fprintf(stderr, "Unable to find DWARF-bearing file in bundle: %s\n",
|
||||||
[input_pathname_ fileSystemRepresentation]);
|
[input_pathname_ fileSystemRepresentation]);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -141,12 +141,12 @@ bool DumpSymbols::Read(NSString *filename) {
|
||||||
// file don't affect memory and vice versa).
|
// file don't affect memory and vice versa).
|
||||||
NSError *error;
|
NSError *error;
|
||||||
contents_ = [NSData dataWithContentsOfFile:object_filename_
|
contents_ = [NSData dataWithContentsOfFile:object_filename_
|
||||||
options:0
|
options:0
|
||||||
error:&error];
|
error:&error];
|
||||||
if (!contents_) {
|
if (!contents_) {
|
||||||
fprintf(stderr, "Error reading object file: %s: %s\n",
|
fprintf(stderr, "Error reading object file: %s: %s\n",
|
||||||
[object_filename_ fileSystemRepresentation],
|
[object_filename_ fileSystemRepresentation],
|
||||||
[[error localizedDescription] UTF8String]);
|
[[error localizedDescription] UTF8String]);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
[contents_ retain];
|
[contents_ retain];
|
||||||
|
@ -166,7 +166,7 @@ bool DumpSymbols::Read(NSString *filename) {
|
||||||
fat_reader.object_files(&object_files_count);
|
fat_reader.object_files(&object_files_count);
|
||||||
if (object_files_count == 0) {
|
if (object_files_count == 0) {
|
||||||
fprintf(stderr, "Fat binary file contains *no* architectures: %s\n",
|
fprintf(stderr, "Fat binary file contains *no* architectures: %s\n",
|
||||||
[object_filename_ fileSystemRepresentation]);
|
[object_filename_ fileSystemRepresentation]);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
object_files_.resize(object_files_count);
|
object_files_.resize(object_files_count);
|
||||||
|
@ -204,7 +204,7 @@ string DumpSymbols::Identifier() {
|
||||||
cpu_type_t cpu_type = selected_object_file_->cputype;
|
cpu_type_t cpu_type = selected_object_file_->cputype;
|
||||||
if (!file_id.MachoIdentifier(cpu_type, identifier_bytes)) {
|
if (!file_id.MachoIdentifier(cpu_type, identifier_bytes)) {
|
||||||
fprintf(stderr, "Unable to calculate UUID of mach-o binary %s!\n",
|
fprintf(stderr, "Unable to calculate UUID of mach-o binary %s!\n",
|
||||||
[object_filename_ fileSystemRepresentation]);
|
[object_filename_ fileSystemRepresentation]);
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -265,7 +265,7 @@ bool DumpSymbols::ReadDwarf(google_breakpad::Module *module,
|
||||||
// There had better be a __debug_info section!
|
// There had better be a __debug_info section!
|
||||||
if (!debug_info_section.first) {
|
if (!debug_info_section.first) {
|
||||||
fprintf(stderr, "%s: __DWARF segment of file has no __debug_info section\n",
|
fprintf(stderr, "%s: __DWARF segment of file has no __debug_info section\n",
|
||||||
selected_object_name_.c_str());
|
selected_object_name_.c_str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -421,7 +421,7 @@ bool DumpSymbols::LoadCommandDumper::SymtabCommand(const ByteBuffer &entries,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DumpSymbols::WriteSymbolFile(std::ostream &stream) {
|
bool DumpSymbols::WriteSymbolFile(std::ostream &stream, bool cfi) {
|
||||||
// Select an object file, if SetArchitecture hasn't been called to set one
|
// Select an object file, if SetArchitecture hasn't been called to set one
|
||||||
// explicitly.
|
// explicitly.
|
||||||
if (!selected_object_file_) {
|
if (!selected_object_file_) {
|
||||||
|
@ -433,10 +433,10 @@ bool DumpSymbols::WriteSymbolFile(std::ostream &stream) {
|
||||||
const NXArchInfo *local_arch = NXGetLocalArchInfo();
|
const NXArchInfo *local_arch = NXGetLocalArchInfo();
|
||||||
if (!SetArchitecture(local_arch->cputype, local_arch->cpusubtype)) {
|
if (!SetArchitecture(local_arch->cputype, local_arch->cpusubtype)) {
|
||||||
fprintf(stderr, "%s: object file contains more than one"
|
fprintf(stderr, "%s: object file contains more than one"
|
||||||
" architecture, none of which match the current"
|
" architecture, none of which match the current"
|
||||||
" architecture; specify an architecture explicitly"
|
" architecture; specify an architecture explicitly"
|
||||||
" with '-a ARCH' to resolve the ambiguity\n",
|
" with '-a ARCH' to resolve the ambiguity\n",
|
||||||
[object_filename_ fileSystemRepresentation]);
|
[object_filename_ fileSystemRepresentation]);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -481,8 +481,8 @@ bool DumpSymbols::WriteSymbolFile(std::ostream &stream) {
|
||||||
if (!reader.Read(reinterpret_cast<const uint8_t *>([contents_ bytes])
|
if (!reader.Read(reinterpret_cast<const uint8_t *>([contents_ bytes])
|
||||||
+ selected_object_file_->offset,
|
+ selected_object_file_->offset,
|
||||||
selected_object_file_->size,
|
selected_object_file_->size,
|
||||||
selected_object_file_->cputype,
|
selected_object_file_->cputype,
|
||||||
selected_object_file_->cpusubtype))
|
selected_object_file_->cpusubtype))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Walk its load commands, and deal with whatever is there.
|
// Walk its load commands, and deal with whatever is there.
|
||||||
|
@ -490,7 +490,7 @@ bool DumpSymbols::WriteSymbolFile(std::ostream &stream) {
|
||||||
if (!reader.WalkLoadCommands(&load_command_dumper))
|
if (!reader.WalkLoadCommands(&load_command_dumper))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return module.Write(stream);
|
return module.Write(stream, cfi);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace google_breakpad
|
} // namespace google_breakpad
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright (c) 2010 Google Inc.
|
// Copyright (c) 2011 Google Inc.
|
||||||
// All rights reserved.
|
// All rights reserved.
|
||||||
//
|
//
|
||||||
// Redistribution and use in source and binary forms, with or without
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
@ -39,6 +39,7 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
namespace google_breakpad {
|
namespace google_breakpad {
|
||||||
|
|
||||||
|
@ -56,16 +57,17 @@ Module::Module(const string &name, const string &os,
|
||||||
load_address_(0) { }
|
load_address_(0) { }
|
||||||
|
|
||||||
Module::~Module() {
|
Module::~Module() {
|
||||||
for (FileByNameMap::iterator it = files_.begin(); it != files_.end(); it++)
|
for (FileByNameMap::iterator it = files_.begin(); it != files_.end(); ++it)
|
||||||
delete it->second;
|
delete it->second;
|
||||||
for (FunctionSet::iterator it = functions_.begin();
|
for (FunctionSet::iterator it = functions_.begin();
|
||||||
it != functions_.end(); it++)
|
it != functions_.end(); ++it) {
|
||||||
delete *it;
|
delete *it;
|
||||||
|
}
|
||||||
for (vector<StackFrameEntry *>::iterator it = stack_frame_entries_.begin();
|
for (vector<StackFrameEntry *>::iterator it = stack_frame_entries_.begin();
|
||||||
it != stack_frame_entries_.end(); it++)
|
it != stack_frame_entries_.end(); ++it) {
|
||||||
delete *it;
|
delete *it;
|
||||||
for (ExternSet::iterator it = externs_.begin();
|
}
|
||||||
it != externs_.end(); it++)
|
for (ExternSet::iterator it = externs_.begin(); it != externs_.end(); ++it)
|
||||||
delete *it;
|
delete *it;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,7 +89,7 @@ void Module::AddFunction(Function *function) {
|
||||||
|
|
||||||
void Module::AddFunctions(vector<Function *>::iterator begin,
|
void Module::AddFunctions(vector<Function *>::iterator begin,
|
||||||
vector<Function *>::iterator end) {
|
vector<Function *>::iterator end) {
|
||||||
for (vector<Function *>::iterator it = begin; it != end; it++)
|
for (vector<Function *>::iterator it = begin; it != end; ++it)
|
||||||
AddFunction(*it);
|
AddFunction(*it);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,7 +151,7 @@ Module::File *Module::FindExistingFile(const string &name) {
|
||||||
|
|
||||||
void Module::GetFiles(vector<File *> *vec) {
|
void Module::GetFiles(vector<File *> *vec) {
|
||||||
vec->clear();
|
vec->clear();
|
||||||
for (FileByNameMap::iterator it = files_.begin(); it != files_.end(); it++)
|
for (FileByNameMap::iterator it = files_.begin(); it != files_.end(); ++it)
|
||||||
vec->push_back(it->second);
|
vec->push_back(it->second);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,16 +162,17 @@ void Module::GetStackFrameEntries(vector<StackFrameEntry *> *vec) {
|
||||||
void Module::AssignSourceIds() {
|
void Module::AssignSourceIds() {
|
||||||
// First, give every source file an id of -1.
|
// First, give every source file an id of -1.
|
||||||
for (FileByNameMap::iterator file_it = files_.begin();
|
for (FileByNameMap::iterator file_it = files_.begin();
|
||||||
file_it != files_.end(); file_it++)
|
file_it != files_.end(); ++file_it) {
|
||||||
file_it->second->source_id = -1;
|
file_it->second->source_id = -1;
|
||||||
|
}
|
||||||
|
|
||||||
// Next, mark all files actually cited by our functions' line number
|
// Next, mark all files actually cited by our functions' line number
|
||||||
// info, by setting each one's source id to zero.
|
// info, by setting each one's source id to zero.
|
||||||
for (FunctionSet::const_iterator func_it = functions_.begin();
|
for (FunctionSet::const_iterator func_it = functions_.begin();
|
||||||
func_it != functions_.end(); func_it++) {
|
func_it != functions_.end(); ++func_it) {
|
||||||
Function *func = *func_it;
|
Function *func = *func_it;
|
||||||
for (vector<Line>::iterator line_it = func->lines.begin();
|
for (vector<Line>::iterator line_it = func->lines.begin();
|
||||||
line_it != func->lines.end(); line_it++)
|
line_it != func->lines.end(); ++line_it)
|
||||||
line_it->file->source_id = 0;
|
line_it->file->source_id = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -179,9 +182,10 @@ void Module::AssignSourceIds() {
|
||||||
// lexicographical order by name, which is neat.
|
// lexicographical order by name, which is neat.
|
||||||
int next_source_id = 0;
|
int next_source_id = 0;
|
||||||
for (FileByNameMap::iterator file_it = files_.begin();
|
for (FileByNameMap::iterator file_it = files_.begin();
|
||||||
file_it != files_.end(); file_it++)
|
file_it != files_.end(); ++file_it) {
|
||||||
if (!file_it->second->source_id)
|
if (!file_it->second->source_id)
|
||||||
file_it->second->source_id = next_source_id++;
|
file_it->second->source_id = next_source_id++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Module::ReportError() {
|
bool Module::ReportError() {
|
||||||
|
@ -192,7 +196,7 @@ bool Module::ReportError() {
|
||||||
|
|
||||||
bool Module::WriteRuleMap(const RuleMap &rule_map, std::ostream &stream) {
|
bool Module::WriteRuleMap(const RuleMap &rule_map, std::ostream &stream) {
|
||||||
for (RuleMap::const_iterator it = rule_map.begin();
|
for (RuleMap::const_iterator it = rule_map.begin();
|
||||||
it != rule_map.end(); it++) {
|
it != rule_map.end(); ++it) {
|
||||||
if (it != rule_map.begin())
|
if (it != rule_map.begin())
|
||||||
stream << ' ';
|
stream << ' ';
|
||||||
stream << it->first << ": " << it->second;
|
stream << it->first << ": " << it->second;
|
||||||
|
@ -200,7 +204,7 @@ bool Module::WriteRuleMap(const RuleMap &rule_map, std::ostream &stream) {
|
||||||
return stream.good();
|
return stream.good();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Module::Write(std::ostream &stream) {
|
bool Module::Write(std::ostream &stream, bool cfi) {
|
||||||
stream << "MODULE " << os_ << " " << architecture_ << " "
|
stream << "MODULE " << os_ << " " << architecture_ << " "
|
||||||
<< id_ << " " << name_ << endl;
|
<< id_ << " " << name_ << endl;
|
||||||
if (!stream.good())
|
if (!stream.good())
|
||||||
|
@ -210,7 +214,7 @@ bool Module::Write(std::ostream &stream) {
|
||||||
|
|
||||||
// Write out files.
|
// Write out files.
|
||||||
for (FileByNameMap::iterator file_it = files_.begin();
|
for (FileByNameMap::iterator file_it = files_.begin();
|
||||||
file_it != files_.end(); file_it++) {
|
file_it != files_.end(); ++file_it) {
|
||||||
File *file = file_it->second;
|
File *file = file_it->second;
|
||||||
if (file->source_id >= 0) {
|
if (file->source_id >= 0) {
|
||||||
stream << "FILE " << file->source_id << " " << file->name << endl;
|
stream << "FILE " << file->source_id << " " << file->name << endl;
|
||||||
|
@ -221,7 +225,7 @@ bool Module::Write(std::ostream &stream) {
|
||||||
|
|
||||||
// Write out functions and their lines.
|
// Write out functions and their lines.
|
||||||
for (FunctionSet::const_iterator func_it = functions_.begin();
|
for (FunctionSet::const_iterator func_it = functions_.begin();
|
||||||
func_it != functions_.end(); func_it++) {
|
func_it != functions_.end(); ++func_it) {
|
||||||
Function *func = *func_it;
|
Function *func = *func_it;
|
||||||
stream << "FUNC " << hex
|
stream << "FUNC " << hex
|
||||||
<< (func->address - load_address_) << " "
|
<< (func->address - load_address_) << " "
|
||||||
|
@ -232,7 +236,7 @@ bool Module::Write(std::ostream &stream) {
|
||||||
if (!stream.good())
|
if (!stream.good())
|
||||||
return ReportError();
|
return ReportError();
|
||||||
for (vector<Line>::iterator line_it = func->lines.begin();
|
for (vector<Line>::iterator line_it = func->lines.begin();
|
||||||
line_it != func->lines.end(); line_it++) {
|
line_it != func->lines.end(); ++line_it) {
|
||||||
stream << hex
|
stream << hex
|
||||||
<< (line_it->address - load_address_) << " "
|
<< (line_it->address - load_address_) << " "
|
||||||
<< line_it->size << " "
|
<< line_it->size << " "
|
||||||
|
@ -246,7 +250,7 @@ bool Module::Write(std::ostream &stream) {
|
||||||
|
|
||||||
// Write out 'PUBLIC' records.
|
// Write out 'PUBLIC' records.
|
||||||
for (ExternSet::const_iterator extern_it = externs_.begin();
|
for (ExternSet::const_iterator extern_it = externs_.begin();
|
||||||
extern_it != externs_.end(); extern_it++) {
|
extern_it != externs_.end(); ++extern_it) {
|
||||||
Extern *ext = *extern_it;
|
Extern *ext = *extern_it;
|
||||||
stream << "PUBLIC " << hex
|
stream << "PUBLIC " << hex
|
||||||
<< (ext->address - load_address_) << " 0 "
|
<< (ext->address - load_address_) << " 0 "
|
||||||
|
@ -255,34 +259,36 @@ bool Module::Write(std::ostream &stream) {
|
||||||
return ReportError();
|
return ReportError();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write out 'STACK CFI INIT' and 'STACK CFI' records.
|
if (cfi) {
|
||||||
vector<StackFrameEntry *>::const_iterator frame_it;
|
// Write out 'STACK CFI INIT' and 'STACK CFI' records.
|
||||||
for (frame_it = stack_frame_entries_.begin();
|
vector<StackFrameEntry *>::const_iterator frame_it;
|
||||||
frame_it != stack_frame_entries_.end(); frame_it++) {
|
for (frame_it = stack_frame_entries_.begin();
|
||||||
StackFrameEntry *entry = *frame_it;
|
frame_it != stack_frame_entries_.end(); ++frame_it) {
|
||||||
stream << "STACK CFI INIT " << hex
|
StackFrameEntry *entry = *frame_it;
|
||||||
<< (entry->address - load_address_) << " "
|
stream << "STACK CFI INIT " << hex
|
||||||
<< entry->size << " " << dec;
|
<< (entry->address - load_address_) << " "
|
||||||
if (!stream.good()
|
<< entry->size << " " << dec;
|
||||||
|| !WriteRuleMap(entry->initial_rules, stream))
|
|
||||||
return ReportError();
|
|
||||||
|
|
||||||
stream << endl;
|
|
||||||
|
|
||||||
// Write out this entry's delta rules as 'STACK CFI' records.
|
|
||||||
for (RuleChangeMap::const_iterator delta_it = entry->rule_changes.begin();
|
|
||||||
delta_it != entry->rule_changes.end(); delta_it++) {
|
|
||||||
stream << "STACK CFI " << hex
|
|
||||||
<< (delta_it->first - load_address_) << " " << dec;
|
|
||||||
if (!stream.good()
|
if (!stream.good()
|
||||||
|| !WriteRuleMap(delta_it->second, stream))
|
|| !WriteRuleMap(entry->initial_rules, stream))
|
||||||
return ReportError();
|
return ReportError();
|
||||||
|
|
||||||
stream << endl;
|
stream << endl;
|
||||||
|
|
||||||
|
// Write out this entry's delta rules as 'STACK CFI' records.
|
||||||
|
for (RuleChangeMap::const_iterator delta_it = entry->rule_changes.begin();
|
||||||
|
delta_it != entry->rule_changes.end(); ++delta_it) {
|
||||||
|
stream << "STACK CFI " << hex
|
||||||
|
<< (delta_it->first - load_address_) << " " << dec;
|
||||||
|
if (!stream.good()
|
||||||
|
|| !WriteRuleMap(delta_it->second, stream))
|
||||||
|
return ReportError();
|
||||||
|
|
||||||
|
stream << endl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace google_breakpad
|
} // namespace google_breakpad
|
||||||
|
|
|
@ -259,14 +259,15 @@ class Module {
|
||||||
// breakpad symbol format. Return true if all goes well, or false if
|
// breakpad symbol format. Return true if all goes well, or false if
|
||||||
// an error occurs. This method writes out:
|
// an error occurs. This method writes out:
|
||||||
// - a header based on the values given to the constructor,
|
// - a header based on the values given to the constructor,
|
||||||
// - the source files added via FindFile, and finally
|
// - the source files added via FindFile,
|
||||||
// - the functions added via AddFunctions, each with its lines.
|
// - the functions added via AddFunctions, each with its lines,
|
||||||
|
// - all public records,
|
||||||
|
// - and if CFI is true, all CFI records.
|
||||||
// Addresses in the output are all relative to the load address
|
// Addresses in the output are all relative to the load address
|
||||||
// established by SetLoadAddress.
|
// established by SetLoadAddress.
|
||||||
bool Write(std::ostream &stream);
|
bool Write(std::ostream &stream, bool cfi);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
// Report an error that has occurred writing the symbol file, using
|
// Report an error that has occurred writing the symbol file, using
|
||||||
// errno to find the appropriate cause. Return false.
|
// errno to find the appropriate cause. Return false.
|
||||||
static bool ReportError();
|
static bool ReportError();
|
||||||
|
@ -287,7 +288,7 @@ class Module {
|
||||||
// Relation for maps whose keys are strings shared with some other
|
// Relation for maps whose keys are strings shared with some other
|
||||||
// structure.
|
// structure.
|
||||||
struct CompareStringPtrs {
|
struct CompareStringPtrs {
|
||||||
bool operator()(const string *x, const string *y) { return *x < *y; };
|
bool operator()(const string *x, const string *y) { return *x < *y; }
|
||||||
};
|
};
|
||||||
|
|
||||||
// A map from filenames to File structures. The map's keys are
|
// A map from filenames to File structures. The map's keys are
|
||||||
|
@ -315,6 +316,6 @@ class Module {
|
||||||
ExternSet externs_;
|
ExternSet externs_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace google_breakpad
|
} // namespace google_breakpad
|
||||||
|
|
||||||
#endif // COMMON_LINUX_MODULE_H__
|
#endif // COMMON_LINUX_MODULE_H__
|
||||||
|
|
|
@ -70,7 +70,7 @@ static Module::Function *generate_duplicate_function(const string &name) {
|
||||||
TEST(Write, Header) {
|
TEST(Write, Header) {
|
||||||
stringstream s;
|
stringstream s;
|
||||||
Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
|
Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
|
||||||
m.Write(s);
|
m.Write(s, true);
|
||||||
string contents = s.str();
|
string contents = s.str();
|
||||||
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n",
|
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n",
|
||||||
contents.c_str());
|
contents.c_str());
|
||||||
|
@ -91,7 +91,7 @@ TEST(Write, OneLineFunc) {
|
||||||
function->lines.push_back(line);
|
function->lines.push_back(line);
|
||||||
m.AddFunction(function);
|
m.AddFunction(function);
|
||||||
|
|
||||||
m.Write(s);
|
m.Write(s, true);
|
||||||
string contents = s.str();
|
string contents = s.str();
|
||||||
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
|
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
|
||||||
"FILE 0 file_name.cc\n"
|
"FILE 0 file_name.cc\n"
|
||||||
|
@ -141,7 +141,7 @@ TEST(Write, RelativeLoadAddress) {
|
||||||
// the module must work fine.
|
// the module must work fine.
|
||||||
m.SetLoadAddress(0x2ab698b0b6407073LL);
|
m.SetLoadAddress(0x2ab698b0b6407073LL);
|
||||||
|
|
||||||
m.Write(s);
|
m.Write(s, true);
|
||||||
string contents = s.str();
|
string contents = s.str();
|
||||||
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
|
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
|
||||||
"FILE 0 filename-a.cc\n"
|
"FILE 0 filename-a.cc\n"
|
||||||
|
@ -164,7 +164,7 @@ TEST(Write, OmitUnusedFiles) {
|
||||||
|
|
||||||
// Create some source files.
|
// Create some source files.
|
||||||
Module::File *file1 = m.FindFile("filename1");
|
Module::File *file1 = m.FindFile("filename1");
|
||||||
m.FindFile("filename2"); // not used by any line
|
m.FindFile("filename2"); // not used by any line
|
||||||
Module::File *file3 = m.FindFile("filename3");
|
Module::File *file3 = m.FindFile("filename3");
|
||||||
|
|
||||||
// Create a function.
|
// Create a function.
|
||||||
|
@ -197,7 +197,7 @@ TEST(Write, OmitUnusedFiles) {
|
||||||
EXPECT_NE(-1, vec[2]->source_id);
|
EXPECT_NE(-1, vec[2]->source_id);
|
||||||
|
|
||||||
stringstream s;
|
stringstream s;
|
||||||
m.Write(s);
|
m.Write(s, true);
|
||||||
string contents = s.str();
|
string contents = s.str();
|
||||||
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
|
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
|
||||||
"FILE 0 filename1\n"
|
"FILE 0 filename1\n"
|
||||||
|
@ -209,6 +209,52 @@ TEST(Write, OmitUnusedFiles) {
|
||||||
contents.c_str());
|
contents.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(Write, NoCFI) {
|
||||||
|
stringstream s;
|
||||||
|
Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
|
||||||
|
|
||||||
|
// Some source files. We will expect to see them in lexicographic order.
|
||||||
|
Module::File *file1 = m.FindFile("filename.cc");
|
||||||
|
|
||||||
|
// A function.
|
||||||
|
Module::Function *function = new(Module::Function);
|
||||||
|
function->name = "A_FLIBBERTIJIBBET::a_will_o_the_wisp(a clown)";
|
||||||
|
function->address = 0xbec774ea5dd935f3LL;
|
||||||
|
function->size = 0x2922088f98d3f6fcLL;
|
||||||
|
function->parameter_size = 0xe5e9aa008bd5f0d0LL;
|
||||||
|
|
||||||
|
// Some source lines. The module should not sort these.
|
||||||
|
Module::Line line1 = { 0xbec774ea5dd935f3LL, 0x1c2be6d6c5af2611LL,
|
||||||
|
file1, 41676901 };
|
||||||
|
function->lines.push_back(line1);
|
||||||
|
|
||||||
|
m.AddFunction(function);
|
||||||
|
|
||||||
|
// Some stack information.
|
||||||
|
Module::StackFrameEntry *entry = new Module::StackFrameEntry();
|
||||||
|
entry->address = 0x30f9e5c83323973dULL;
|
||||||
|
entry->size = 0x49fc9ca7c7c13dc2ULL;
|
||||||
|
entry->initial_rules[".cfa"] = "he was a handsome man";
|
||||||
|
entry->initial_rules["and"] = "what i want to know is";
|
||||||
|
entry->rule_changes[0x30f9e5c83323973eULL]["how"] =
|
||||||
|
"do you like your blueeyed boy";
|
||||||
|
entry->rule_changes[0x30f9e5c83323973eULL]["Mister"] = "Death";
|
||||||
|
m.AddStackFrameEntry(entry);
|
||||||
|
|
||||||
|
// Set the load address. Doing this after adding all the data to
|
||||||
|
// the module must work fine.
|
||||||
|
m.SetLoadAddress(0x2ab698b0b6407073LL);
|
||||||
|
|
||||||
|
m.Write(s, false);
|
||||||
|
string contents = s.str();
|
||||||
|
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
|
||||||
|
"FILE 0 filename.cc\n"
|
||||||
|
"FUNC 9410dc39a798c580 2922088f98d3f6fc e5e9aa008bd5f0d0"
|
||||||
|
" A_FLIBBERTIJIBBET::a_will_o_the_wisp(a clown)\n"
|
||||||
|
"9410dc39a798c580 1c2be6d6c5af2611 41676901 0\n",
|
||||||
|
contents.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
TEST(Construct, AddFunctions) {
|
TEST(Construct, AddFunctions) {
|
||||||
stringstream s;
|
stringstream s;
|
||||||
Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
|
Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
|
||||||
|
@ -233,7 +279,7 @@ TEST(Construct, AddFunctions) {
|
||||||
|
|
||||||
m.AddFunctions(vec.begin(), vec.end());
|
m.AddFunctions(vec.begin(), vec.end());
|
||||||
|
|
||||||
m.Write(s);
|
m.Write(s, true);
|
||||||
string contents = s.str();
|
string contents = s.str();
|
||||||
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
|
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
|
||||||
"FUNC 2987743d0b35b13f b369db048deb3010 938e556cb5a79988"
|
"FUNC 2987743d0b35b13f b369db048deb3010 938e556cb5a79988"
|
||||||
|
@ -285,7 +331,7 @@ TEST(Construct, AddFrames) {
|
||||||
m.AddStackFrameEntry(entry3);
|
m.AddStackFrameEntry(entry3);
|
||||||
|
|
||||||
// Check that Write writes STACK CFI records properly.
|
// Check that Write writes STACK CFI records properly.
|
||||||
m.Write(s);
|
m.Write(s, true);
|
||||||
string contents = s.str();
|
string contents = s.str();
|
||||||
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
|
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
|
||||||
"STACK CFI INIT ddb5f41285aa7757 1486493370dc5073 \n"
|
"STACK CFI INIT ddb5f41285aa7757 1486493370dc5073 \n"
|
||||||
|
@ -361,7 +407,7 @@ TEST(Construct, DuplicateFunctions) {
|
||||||
m.AddFunction(function1);
|
m.AddFunction(function1);
|
||||||
m.AddFunction(function2);
|
m.AddFunction(function2);
|
||||||
|
|
||||||
m.Write(s);
|
m.Write(s, true);
|
||||||
string contents = s.str();
|
string contents = s.str();
|
||||||
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
|
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
|
||||||
"FUNC d35402aac7a7ad5c 200b26e605f99071 f14ac4fed48c4a99"
|
"FUNC d35402aac7a7ad5c 200b26e605f99071 f14ac4fed48c4a99"
|
||||||
|
@ -380,7 +426,7 @@ TEST(Construct, FunctionsWithSameAddress) {
|
||||||
m.AddFunction(function1);
|
m.AddFunction(function1);
|
||||||
m.AddFunction(function2);
|
m.AddFunction(function2);
|
||||||
|
|
||||||
m.Write(s);
|
m.Write(s, true);
|
||||||
string contents = s.str();
|
string contents = s.str();
|
||||||
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
|
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
|
||||||
"FUNC d35402aac7a7ad5c 200b26e605f99071 f14ac4fed48c4a99"
|
"FUNC d35402aac7a7ad5c 200b26e605f99071 f14ac4fed48c4a99"
|
||||||
|
@ -407,7 +453,7 @@ TEST(Construct, Externs) {
|
||||||
m.AddExtern(extern1);
|
m.AddExtern(extern1);
|
||||||
m.AddExtern(extern2);
|
m.AddExtern(extern2);
|
||||||
|
|
||||||
m.Write(s);
|
m.Write(s, true);
|
||||||
string contents = s.str();
|
string contents = s.str();
|
||||||
|
|
||||||
EXPECT_STREQ("MODULE " MODULE_OS " " MODULE_ARCH " "
|
EXPECT_STREQ("MODULE " MODULE_OS " " MODULE_ARCH " "
|
||||||
|
@ -434,7 +480,7 @@ TEST(Construct, DuplicateExterns) {
|
||||||
m.AddExtern(extern1);
|
m.AddExtern(extern1);
|
||||||
m.AddExtern(extern2);
|
m.AddExtern(extern2);
|
||||||
|
|
||||||
m.Write(s);
|
m.Write(s, true);
|
||||||
string contents = s.str();
|
string contents = s.str();
|
||||||
|
|
||||||
EXPECT_STREQ("MODULE " MODULE_OS " " MODULE_ARCH " "
|
EXPECT_STREQ("MODULE " MODULE_OS " " MODULE_ARCH " "
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright (c) 2010, Google Inc.
|
// Copyright (c) 2011, Google Inc.
|
||||||
// All rights reserved.
|
// All rights reserved.
|
||||||
//
|
//
|
||||||
// Redistribution and use in source and binary forms, with or without
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
@ -27,27 +27,47 @@
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <iostream>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "common/linux/dump_symbols.h"
|
#include "common/linux/dump_symbols.h"
|
||||||
|
|
||||||
using google_breakpad::WriteSymbolFile;
|
using google_breakpad::WriteSymbolFile;
|
||||||
|
|
||||||
|
int usage(const char* self) {
|
||||||
|
fprintf(stderr, "Usage: %s [OPTION] <binary-with-debugging-info> "
|
||||||
|
"[directory-for-debug-file]\n\n", self);
|
||||||
|
fprintf(stderr, "Options:\n");
|
||||||
|
fprintf(stderr, " -c Do not generate CFI section\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
if (argc < 2 || argc > 3) {
|
if (argc < 2 || argc > 4)
|
||||||
fprintf(stderr, "Usage: %s <binary-with-debugging-info> "
|
return usage(argv[0]);
|
||||||
"[directory-for-debug-file]\n", argv[0]);
|
|
||||||
return 1;
|
bool cfi = true;
|
||||||
|
if (strcmp("-c", argv[1]) == 0)
|
||||||
|
cfi = false;
|
||||||
|
if (!cfi && argc == 2)
|
||||||
|
return usage(argv[0]);
|
||||||
|
|
||||||
|
const char *binary;
|
||||||
|
std::string debug_dir;
|
||||||
|
if (cfi) {
|
||||||
|
binary = argv[1];
|
||||||
|
if (argc == 3)
|
||||||
|
debug_dir = argv[2];
|
||||||
|
} else {
|
||||||
|
binary = argv[2];
|
||||||
|
if (argc == 4)
|
||||||
|
debug_dir = argv[3];
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *binary = argv[1];
|
if (!WriteSymbolFile(binary, debug_dir, cfi, std::cout)) {
|
||||||
std::string debug_dir;
|
|
||||||
if (argc == 3)
|
|
||||||
debug_dir = argv[2];
|
|
||||||
|
|
||||||
if (!WriteSymbolFile(binary, debug_dir, std::cout)) {
|
|
||||||
fprintf(stderr, "Failed to write symbol file.\n");
|
fprintf(stderr, "Failed to write symbol file.\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// -*- mode: c++ -*-
|
// -*- mode: c++ -*-
|
||||||
|
|
||||||
// Copyright (c) 2006, Google Inc.
|
// Copyright (c) 2011, Google Inc.
|
||||||
// All rights reserved.
|
// All rights reserved.
|
||||||
//
|
//
|
||||||
// Redistribution and use in source and binary forms, with or without
|
// Redistribution and use in source and binary forms, with or without
|
||||||
|
@ -45,9 +45,10 @@ using google_breakpad::DumpSymbols;
|
||||||
using std::vector;
|
using std::vector;
|
||||||
|
|
||||||
struct Options {
|
struct Options {
|
||||||
Options() : srcPath(), arch() { }
|
Options() : srcPath(), arch(), cfi(true) { }
|
||||||
NSString *srcPath;
|
NSString *srcPath;
|
||||||
const NXArchInfo *arch;
|
const NXArchInfo *arch;
|
||||||
|
bool cfi;
|
||||||
};
|
};
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
|
@ -83,16 +84,17 @@ static bool Start(const Options &options) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return dump_symbols.WriteSymbolFile(std::cout);
|
return dump_symbols.WriteSymbolFile(std::cout, options.cfi);
|
||||||
}
|
}
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
static void Usage(int argc, const char *argv[]) {
|
static void Usage(int argc, const char *argv[]) {
|
||||||
fprintf(stderr, "Output a Breakpad symbol file from a Mach-o file.\n");
|
fprintf(stderr, "Output a Breakpad symbol file from a Mach-o file.\n");
|
||||||
fprintf(stderr, "Usage: %s [-a ARCHITECTURE] <Mach-o file>\n",
|
fprintf(stderr, "Usage: %s [-a ARCHITECTURE] [-c] <Mach-o file>\n",
|
||||||
argv[0]);
|
argv[0]);
|
||||||
fprintf(stderr, "\t-a: Architecture type [default: native, or whatever is\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 in the file, if it contains only one architecture]\n");
|
||||||
|
fprintf(stderr, "\t-c: Do not generate CFI section\n");
|
||||||
fprintf(stderr, "\t-h: Usage\n");
|
fprintf(stderr, "\t-h: Usage\n");
|
||||||
fprintf(stderr, "\t-?: Usage\n");
|
fprintf(stderr, "\t-?: Usage\n");
|
||||||
}
|
}
|
||||||
|
@ -102,7 +104,7 @@ static void SetupOptions(int argc, const char *argv[], Options *options) {
|
||||||
extern int optind;
|
extern int optind;
|
||||||
signed char ch;
|
signed char ch;
|
||||||
|
|
||||||
while ((ch = getopt(argc, (char * const *)argv, "a:h?")) != -1) {
|
while ((ch = getopt(argc, (char * const *)argv, "a:ch?")) != -1) {
|
||||||
switch (ch) {
|
switch (ch) {
|
||||||
case 'a': {
|
case 'a': {
|
||||||
const NXArchInfo *arch_info = NXGetArchInfoFromName(optarg);
|
const NXArchInfo *arch_info = NXGetArchInfoFromName(optarg);
|
||||||
|
@ -114,6 +116,9 @@ static void SetupOptions(int argc, const char *argv[], Options *options) {
|
||||||
options->arch = arch_info;
|
options->arch = arch_info;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case 'c':
|
||||||
|
options->cfi = false;
|
||||||
|
break;
|
||||||
case '?':
|
case '?':
|
||||||
case 'h':
|
case 'h':
|
||||||
Usage(argc, argv);
|
Usage(argc, argv);
|
||||||
|
|
Loading…
Reference in a new issue