From 8d54c7509234e9a4918046c12dcb138489f06990 Mon Sep 17 00:00:00 2001 From: "thestig@chromium.org" Date: Wed, 14 Sep 2011 01:02:55 +0000 Subject: [PATCH] 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 --- src/common/linux/dump_symbols.cc | 8 ++- src/common/linux/dump_symbols.h | 4 +- src/common/linux/dump_symbols_unittest.cc | 26 ++++--- src/common/mac/dump_syms.h | 24 +++---- src/common/mac/dump_syms.mm | 48 ++++++------- src/common/module.cc | 86 ++++++++++++----------- src/common/module.h | 13 ++-- src/common/module_unittest.cc | 68 +++++++++++++++--- src/tools/linux/dump_syms/dump_syms.cc | 44 ++++++++---- src/tools/mac/dump_syms/dump_syms_tool.mm | 21 +++--- 10 files changed, 214 insertions(+), 128 deletions(-) diff --git a/src/common/linux/dump_symbols.cc b/src/common/linux/dump_symbols.cc index fc312983..cd059ba8 100644 --- a/src/common/linux/dump_symbols.cc +++ b/src/common/linux/dump_symbols.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 Google Inc. +// Copyright (c) 2011 Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without @@ -728,6 +728,7 @@ namespace google_breakpad { bool WriteSymbolFileInternal(uint8_t* obj_file, const std::string &obj_filename, const std::string &debug_dir, + bool cfi, std::ostream &sym_stream) { ElfW(Ehdr) *elf_header = reinterpret_cast(obj_file); @@ -803,7 +804,7 @@ bool WriteSymbolFileInternal(uint8_t* obj_file, return false; } } - if (!module.Write(sym_stream)) + if (!module.Write(sym_stream, cfi)) return false; return true; @@ -811,6 +812,7 @@ bool WriteSymbolFileInternal(uint8_t* obj_file, bool WriteSymbolFile(const std::string &obj_file, const std::string &debug_dir, + bool cfi, std::ostream &sym_stream) { MmapWrapper map_wrapper; ElfW(Ehdr) *elf_header = NULL; @@ -818,7 +820,7 @@ bool WriteSymbolFile(const std::string &obj_file, return false; return WriteSymbolFileInternal(reinterpret_cast(elf_header), - obj_file, debug_dir, sym_stream); + obj_file, debug_dir, cfi, sym_stream); } } // namespace google_breakpad diff --git a/src/common/linux/dump_symbols.h b/src/common/linux/dump_symbols.h index 3749d1f6..9bf54d37 100644 --- a/src/common/linux/dump_symbols.h +++ b/src/common/linux/dump_symbols.h @@ -1,6 +1,6 @@ // -*- mode: c++ -*- -// Copyright (c) 2010, Google Inc. +// Copyright (c) 2011, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without @@ -45,8 +45,10 @@ namespace google_breakpad { // file format. // If OBJ_FILE has been stripped but contains a .gnu_debuglink section, // 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, const std::string &debug_dir, + bool cfi, std::ostream &sym_stream); } // namespace google_breakpad diff --git a/src/common/linux/dump_symbols_unittest.cc b/src/common/linux/dump_symbols_unittest.cc index 06263076..c6d4d2d3 100644 --- a/src/common/linux/dump_symbols_unittest.cc +++ b/src/common/linux/dump_symbols_unittest.cc @@ -47,6 +47,7 @@ namespace google_breakpad { bool WriteSymbolFileInternal(uint8_t* obj_file, const std::string &obj_filename, const std::string &debug_dir, + bool cfi, std::ostream &sym_stream); } @@ -62,7 +63,7 @@ using std::vector; using ::testing::Test; class DumpSymbols : public Test { -public: + public: void GetElfContents(ELF& elf) { string contents; ASSERT_TRUE(elf.GetContents(&contents)); @@ -84,6 +85,7 @@ TEST_F(DumpSymbols, Invalid) { EXPECT_FALSE(WriteSymbolFileInternal(reinterpret_cast(&header), "foo", "", + true, s)); } @@ -105,11 +107,11 @@ TEST_F(DumpSymbols, SimplePublic32) { SHN_UNDEF + 1); int index = elf.AddSection(".dynstr", table, SHT_STRTAB); elf.AddSection(".dynsym", syms, - SHT_DYNSYM, // type - SHF_ALLOC, // flags - 0, // addr - index, // link - sizeof(Elf32_Sym)); // entsize + SHT_DYNSYM, // type + SHF_ALLOC, // flags + 0, // addr + index, // link + sizeof(Elf32_Sym)); // entsize elf.Finish(); GetElfContents(elf); @@ -118,6 +120,7 @@ TEST_F(DumpSymbols, SimplePublic32) { ASSERT_TRUE(WriteSymbolFileInternal(elfdata, "foo", "", + true, s)); EXPECT_EQ("MODULE Linux x86 000000000000000000000000000000000 foo\n" "PUBLIC 1000 0 superfunc\n", @@ -141,11 +144,11 @@ TEST_F(DumpSymbols, SimplePublic64) { SHN_UNDEF + 1); int index = elf.AddSection(".dynstr", table, SHT_STRTAB); elf.AddSection(".dynsym", syms, - SHT_DYNSYM, // type - SHF_ALLOC, // flags - 0, // addr - index, // link - sizeof(Elf64_Sym)); // entsize + SHT_DYNSYM, // type + SHF_ALLOC, // flags + 0, // addr + index, // link + sizeof(Elf64_Sym)); // entsize elf.Finish(); GetElfContents(elf); @@ -154,6 +157,7 @@ TEST_F(DumpSymbols, SimplePublic64) { ASSERT_TRUE(WriteSymbolFileInternal(elfdata, "foo", "", + true, s)); EXPECT_EQ("MODULE Linux x86_64 000000000000000000000000000000000 foo\n" "PUBLIC 1000 0 superfunc\n", diff --git a/src/common/mac/dump_syms.h b/src/common/mac/dump_syms.h index f197ca28..0e2f464d 100644 --- a/src/common/mac/dump_syms.h +++ b/src/common/mac/dump_syms.h @@ -1,6 +1,6 @@ // -*- mode: c++ -*- -// Copyright (c) 2010, Google Inc. +// Copyright (c) 2011, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without @@ -52,9 +52,9 @@ namespace google_breakpad { class DumpSymbols { public: - DumpSymbols() + DumpSymbols() : input_pathname_(), - object_filename_(), + object_filename_(), contents_(), selected_object_file_(), selected_object_name_() { } @@ -84,9 +84,9 @@ class DumpSymbols { // 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); - - // If this dumper's file includes an object file for |arch_name|, then select - // that object file for dumping, and return true. Otherwise, return false, + + // If this dumper's file includes an object file for |arch_name|, 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 @@ -94,7 +94,7 @@ class DumpSymbols { // object file, then the dumper will dump the object file whose // 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 @@ -109,10 +109,10 @@ class DumpSymbols { return NULL; } - // 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(std::ostream &stream); + // Read the selected object file's debugging information, and write it out to + // |stream|. Write the CFI section if |cfi| is true. Return true on success; + // if an error occurs, report it and return false. + bool WriteSymbolFile(std::ostream &stream, bool cfi); private: // Used internally. @@ -158,7 +158,7 @@ class DumpSymbols { // has exactly one element. vector object_files_; - // The object file in object_files_ selected to dump, or NULL if + // 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_; diff --git a/src/common/mac/dump_syms.mm b/src/common/mac/dump_syms.mm index 5fd614f2..9783514f 100644 --- a/src/common/mac/dump_syms.mm +++ b/src/common/mac/dump_syms.mm @@ -1,6 +1,6 @@ // -*- mode: c++ -*- -// Copyright (c) 2010, Google Inc. +// Copyright (c) 2011, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without @@ -79,7 +79,7 @@ namespace google_breakpad { bool DumpSymbols::Read(NSString *filename) { if (![[NSFileManager defaultManager] fileExistsAtPath:filename]) { fprintf(stderr, "Object file does not exist: %s\n", - [filename fileSystemRepresentation]); + [filename fileSystemRepresentation]); return false; } @@ -101,15 +101,15 @@ bool DumpSymbols::Read(NSString *filename) { // pathForResource:ofType:inDirectory likes. NSString *base_name = [input_pathname_ lastPathComponent]; NSString *dwarf_resource; - + do { NSString *new_base_name = [base_name stringByDeletingPathExtension]; // If stringByDeletingPathExtension returned the name unchanged, then // there's nothing more for us to strip off --- lose. if ([new_base_name isEqualToString:base_name]) { - fprintf(stderr, "Unable to find DWARF-bearing file in bundle: %s\n", - [input_pathname_ fileSystemRepresentation]); + fprintf(stderr, "Unable to find DWARF-bearing file in bundle: %s\n", + [input_pathname_ fileSystemRepresentation]); return false; } @@ -141,12 +141,12 @@ bool DumpSymbols::Read(NSString *filename) { // file don't affect memory and vice versa). NSError *error; contents_ = [NSData dataWithContentsOfFile:object_filename_ - options:0 - error:&error]; + options:0 + error:&error]; if (!contents_) { fprintf(stderr, "Error reading object file: %s: %s\n", - [object_filename_ fileSystemRepresentation], - [[error localizedDescription] UTF8String]); + [object_filename_ fileSystemRepresentation], + [[error localizedDescription] UTF8String]); return false; } [contents_ retain]; @@ -166,7 +166,7 @@ bool DumpSymbols::Read(NSString *filename) { fat_reader.object_files(&object_files_count); if (object_files_count == 0) { fprintf(stderr, "Fat binary file contains *no* architectures: %s\n", - [object_filename_ fileSystemRepresentation]); + [object_filename_ fileSystemRepresentation]); return false; } object_files_.resize(object_files_count); @@ -197,14 +197,14 @@ bool DumpSymbols::SetArchitecture(const std::string &arch_name) { } return arch_set; } - + string DumpSymbols::Identifier() { FileID file_id([object_filename_ fileSystemRepresentation]); unsigned char identifier_bytes[16]; cpu_type_t cpu_type = selected_object_file_->cputype; if (!file_id.MachoIdentifier(cpu_type, identifier_bytes)) { fprintf(stderr, "Unable to calculate UUID of mach-o binary %s!\n", - [object_filename_ fileSystemRepresentation]); + [object_filename_ fileSystemRepresentation]); return ""; } @@ -243,7 +243,7 @@ bool DumpSymbols::ReadDwarf(google_breakpad::Module *module, const mach_o::Reader &macho_reader, const mach_o::SectionMap &dwarf_sections) const { // Build a byte reader of the appropriate endianness. - ByteReader byte_reader(macho_reader.big_endian() + ByteReader byte_reader(macho_reader.big_endian() ? dwarf2reader::ENDIANNESS_BIG : dwarf2reader::ENDIANNESS_LITTLE); @@ -265,10 +265,10 @@ bool DumpSymbols::ReadDwarf(google_breakpad::Module *module, // There had better be a __debug_info section! if (!debug_info_section.first) { 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; } - + // Build a line-to-module loader for the root handler to use. DumperLineToModule line_to_module(&byte_reader); @@ -343,7 +343,7 @@ bool DumpSymbols::ReadCFI(google_breakpad::Module *module, // investigation, Mac OS X only uses DW_EH_PE_pcrel-based pointers, so // this is the only base address the CFI parser will need. byte_reader.SetCFIDataBase(section.address, cfi); - + dwarf2reader::CallFrameInfo::Reporter dwarf_reporter(selected_object_name_, section.section_name); dwarf2reader::CallFrameInfo parser(cfi, cfi_size, @@ -421,7 +421,7 @@ bool DumpSymbols::LoadCommandDumper::SymtabCommand(const ByteBuffer &entries, 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 // explicitly. if (!selected_object_file_) { @@ -433,10 +433,10 @@ bool DumpSymbols::WriteSymbolFile(std::ostream &stream) { const NXArchInfo *local_arch = NXGetLocalArchInfo(); if (!SetArchitecture(local_arch->cputype, local_arch->cpusubtype)) { 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" - " with '-a ARCH' to resolve the ambiguity\n", - [object_filename_ fileSystemRepresentation]); + " with '-a ARCH' to resolve the ambiguity\n", + [object_filename_ fileSystemRepresentation]); return false; } } @@ -472,7 +472,7 @@ bool DumpSymbols::WriteSymbolFile(std::ostream &stream) { identifier += "0"; // Create a module to hold the debugging information. - Module module([module_name UTF8String], "mac", selected_arch_name, + Module module([module_name UTF8String], "mac", selected_arch_name, identifier); // Parse the selected object file. @@ -481,8 +481,8 @@ bool DumpSymbols::WriteSymbolFile(std::ostream &stream) { if (!reader.Read(reinterpret_cast([contents_ bytes]) + selected_object_file_->offset, selected_object_file_->size, - selected_object_file_->cputype, - selected_object_file_->cpusubtype)) + selected_object_file_->cputype, + selected_object_file_->cpusubtype)) return false; // 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)) return false; - return module.Write(stream); + return module.Write(stream, cfi); } } // namespace google_breakpad diff --git a/src/common/module.cc b/src/common/module.cc index f02b26ea..4e257d1d 100644 --- a/src/common/module.cc +++ b/src/common/module.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010 Google Inc. +// Copyright (c) 2011 Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without @@ -39,6 +39,7 @@ #include #include +#include namespace google_breakpad { @@ -56,16 +57,17 @@ Module::Module(const string &name, const string &os, load_address_(0) { } 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; for (FunctionSet::iterator it = functions_.begin(); - it != functions_.end(); it++) + it != functions_.end(); ++it) { delete *it; + } for (vector::iterator it = stack_frame_entries_.begin(); - it != stack_frame_entries_.end(); it++) + it != stack_frame_entries_.end(); ++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; } @@ -87,7 +89,7 @@ void Module::AddFunction(Function *function) { void Module::AddFunctions(vector::iterator begin, vector::iterator end) { - for (vector::iterator it = begin; it != end; it++) + for (vector::iterator it = begin; it != end; ++it) AddFunction(*it); } @@ -149,7 +151,7 @@ Module::File *Module::FindExistingFile(const string &name) { void Module::GetFiles(vector *vec) { 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); } @@ -160,16 +162,17 @@ void Module::GetStackFrameEntries(vector *vec) { void Module::AssignSourceIds() { // First, give every source file an id of -1. 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; + } // Next, mark all files actually cited by our functions' line number // info, by setting each one's source id to zero. for (FunctionSet::const_iterator func_it = functions_.begin(); - func_it != functions_.end(); func_it++) { + func_it != functions_.end(); ++func_it) { Function *func = *func_it; for (vector::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; } @@ -179,9 +182,10 @@ void Module::AssignSourceIds() { // lexicographical order by name, which is neat. int next_source_id = 0; 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) file_it->second->source_id = next_source_id++; + } } bool Module::ReportError() { @@ -192,7 +196,7 @@ bool Module::ReportError() { bool Module::WriteRuleMap(const RuleMap &rule_map, std::ostream &stream) { for (RuleMap::const_iterator it = rule_map.begin(); - it != rule_map.end(); it++) { + it != rule_map.end(); ++it) { if (it != rule_map.begin()) stream << ' '; stream << it->first << ": " << it->second; @@ -200,7 +204,7 @@ bool Module::WriteRuleMap(const RuleMap &rule_map, std::ostream &stream) { return stream.good(); } -bool Module::Write(std::ostream &stream) { +bool Module::Write(std::ostream &stream, bool cfi) { stream << "MODULE " << os_ << " " << architecture_ << " " << id_ << " " << name_ << endl; if (!stream.good()) @@ -210,7 +214,7 @@ bool Module::Write(std::ostream &stream) { // Write out files. for (FileByNameMap::iterator file_it = files_.begin(); - file_it != files_.end(); file_it++) { + file_it != files_.end(); ++file_it) { File *file = file_it->second; if (file->source_id >= 0) { stream << "FILE " << file->source_id << " " << file->name << endl; @@ -221,18 +225,18 @@ bool Module::Write(std::ostream &stream) { // Write out functions and their lines. for (FunctionSet::const_iterator func_it = functions_.begin(); - func_it != functions_.end(); func_it++) { + func_it != functions_.end(); ++func_it) { Function *func = *func_it; stream << "FUNC " << hex << (func->address - load_address_) << " " << func->size << " " << func->parameter_size << " " << func->name << dec << endl; - + if (!stream.good()) return ReportError(); for (vector::iterator line_it = func->lines.begin(); - line_it != func->lines.end(); line_it++) { + line_it != func->lines.end(); ++line_it) { stream << hex << (line_it->address - load_address_) << " " << line_it->size << " " @@ -246,7 +250,7 @@ bool Module::Write(std::ostream &stream) { // Write out 'PUBLIC' records. for (ExternSet::const_iterator extern_it = externs_.begin(); - extern_it != externs_.end(); extern_it++) { + extern_it != externs_.end(); ++extern_it) { Extern *ext = *extern_it; stream << "PUBLIC " << hex << (ext->address - load_address_) << " 0 " @@ -255,34 +259,36 @@ bool Module::Write(std::ostream &stream) { return ReportError(); } - // Write out 'STACK CFI INIT' and 'STACK CFI' records. - vector::const_iterator frame_it; - for (frame_it = stack_frame_entries_.begin(); - frame_it != stack_frame_entries_.end(); frame_it++) { - StackFrameEntry *entry = *frame_it; - stream << "STACK CFI INIT " << hex - << (entry->address - load_address_) << " " - << entry->size << " " << dec; - if (!stream.good() - || !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 (cfi) { + // Write out 'STACK CFI INIT' and 'STACK CFI' records. + vector::const_iterator frame_it; + for (frame_it = stack_frame_entries_.begin(); + frame_it != stack_frame_entries_.end(); ++frame_it) { + StackFrameEntry *entry = *frame_it; + stream << "STACK CFI INIT " << hex + << (entry->address - load_address_) << " " + << entry->size << " " << dec; if (!stream.good() - || !WriteRuleMap(delta_it->second, stream)) + || !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() + || !WriteRuleMap(delta_it->second, stream)) + return ReportError(); + + stream << endl; + } } } return true; } -} // namespace google_breakpad +} // namespace google_breakpad diff --git a/src/common/module.h b/src/common/module.h index 55f260f1..734a1afc 100644 --- a/src/common/module.h +++ b/src/common/module.h @@ -259,14 +259,15 @@ class Module { // breakpad symbol format. Return true if all goes well, or false if // an error occurs. This method writes out: // - a header based on the values given to the constructor, - // - the source files added via FindFile, and finally - // - the functions added via AddFunctions, each with its lines. + // - the source files added via FindFile, + // - 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 // established by SetLoadAddress. - bool Write(std::ostream &stream); + bool Write(std::ostream &stream, bool cfi); private: - // Report an error that has occurred writing the symbol file, using // errno to find the appropriate cause. Return false. static bool ReportError(); @@ -287,7 +288,7 @@ class Module { // Relation for maps whose keys are strings shared with some other // structure. 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 @@ -315,6 +316,6 @@ class Module { ExternSet externs_; }; -} // namespace google_breakpad +} // namespace google_breakpad #endif // COMMON_LINUX_MODULE_H__ diff --git a/src/common/module_unittest.cc b/src/common/module_unittest.cc index 4972bbe8..85c3b1c6 100644 --- a/src/common/module_unittest.cc +++ b/src/common/module_unittest.cc @@ -70,7 +70,7 @@ static Module::Function *generate_duplicate_function(const string &name) { TEST(Write, Header) { stringstream s; Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); - m.Write(s); + m.Write(s, true); string contents = s.str(); EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n", contents.c_str()); @@ -91,7 +91,7 @@ TEST(Write, OneLineFunc) { function->lines.push_back(line); m.AddFunction(function); - m.Write(s); + m.Write(s, true); string contents = s.str(); EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" "FILE 0 file_name.cc\n" @@ -141,7 +141,7 @@ TEST(Write, RelativeLoadAddress) { // the module must work fine. m.SetLoadAddress(0x2ab698b0b6407073LL); - m.Write(s); + m.Write(s, true); string contents = s.str(); EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" "FILE 0 filename-a.cc\n" @@ -164,7 +164,7 @@ TEST(Write, OmitUnusedFiles) { // Create some source files. 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"); // Create a function. @@ -197,7 +197,7 @@ TEST(Write, OmitUnusedFiles) { EXPECT_NE(-1, vec[2]->source_id); stringstream s; - m.Write(s); + m.Write(s, true); string contents = s.str(); EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" "FILE 0 filename1\n" @@ -209,6 +209,52 @@ TEST(Write, OmitUnusedFiles) { 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) { stringstream s; Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID); @@ -233,7 +279,7 @@ TEST(Construct, AddFunctions) { m.AddFunctions(vec.begin(), vec.end()); - m.Write(s); + m.Write(s, true); string contents = s.str(); EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" "FUNC 2987743d0b35b13f b369db048deb3010 938e556cb5a79988" @@ -285,7 +331,7 @@ TEST(Construct, AddFrames) { m.AddStackFrameEntry(entry3); // Check that Write writes STACK CFI records properly. - m.Write(s); + m.Write(s, true); string contents = s.str(); EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" "STACK CFI INIT ddb5f41285aa7757 1486493370dc5073 \n" @@ -361,7 +407,7 @@ TEST(Construct, DuplicateFunctions) { m.AddFunction(function1); m.AddFunction(function2); - m.Write(s); + m.Write(s, true); string contents = s.str(); EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" "FUNC d35402aac7a7ad5c 200b26e605f99071 f14ac4fed48c4a99" @@ -380,7 +426,7 @@ TEST(Construct, FunctionsWithSameAddress) { m.AddFunction(function1); m.AddFunction(function2); - m.Write(s); + m.Write(s, true); string contents = s.str(); EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n" "FUNC d35402aac7a7ad5c 200b26e605f99071 f14ac4fed48c4a99" @@ -407,7 +453,7 @@ TEST(Construct, Externs) { m.AddExtern(extern1); m.AddExtern(extern2); - m.Write(s); + m.Write(s, true); string contents = s.str(); EXPECT_STREQ("MODULE " MODULE_OS " " MODULE_ARCH " " @@ -434,7 +480,7 @@ TEST(Construct, DuplicateExterns) { m.AddExtern(extern1); m.AddExtern(extern2); - m.Write(s); + m.Write(s, true); string contents = s.str(); EXPECT_STREQ("MODULE " MODULE_OS " " MODULE_ARCH " " diff --git a/src/tools/linux/dump_syms/dump_syms.cc b/src/tools/linux/dump_syms/dump_syms.cc index f4c05cfc..adac216c 100644 --- a/src/tools/linux/dump_syms/dump_syms.cc +++ b/src/tools/linux/dump_syms/dump_syms.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2010, Google Inc. +// Copyright (c) 2011, Google Inc. // All rights reserved. // // 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 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -#include #include + +#include +#include #include #include "common/linux/dump_symbols.h" using google_breakpad::WriteSymbolFile; +int usage(const char* self) { + fprintf(stderr, "Usage: %s [OPTION] " + "[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) { - if (argc < 2 || argc > 3) { - fprintf(stderr, "Usage: %s " - "[directory-for-debug-file]\n", argv[0]); - return 1; + if (argc < 2 || argc > 4) + return usage(argv[0]); + + 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]; - std::string debug_dir; - if (argc == 3) - debug_dir = argv[2]; - - if (!WriteSymbolFile(binary, debug_dir, std::cout)) { + if (!WriteSymbolFile(binary, debug_dir, cfi, std::cout)) { fprintf(stderr, "Failed to write symbol file.\n"); return 1; } diff --git a/src/tools/mac/dump_syms/dump_syms_tool.mm b/src/tools/mac/dump_syms/dump_syms_tool.mm index 3f1f03b6..92ebf211 100644 --- a/src/tools/mac/dump_syms/dump_syms_tool.mm +++ b/src/tools/mac/dump_syms/dump_syms_tool.mm @@ -1,6 +1,6 @@ // -*- mode: c++ -*- -// Copyright (c) 2006, Google Inc. +// Copyright (c) 2011, Google Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without @@ -45,9 +45,10 @@ using google_breakpad::DumpSymbols; using std::vector; struct Options { - Options() : srcPath(), arch() { } + Options() : srcPath(), arch(), cfi(true) { } NSString *srcPath; const NXArchInfo *arch; + bool cfi; }; //============================================================================= @@ -82,17 +83,18 @@ static bool Start(const Options &options) { return false; } } - - return dump_symbols.WriteSymbolFile(std::cout); + + return dump_symbols.WriteSymbolFile(std::cout, options.cfi); } //============================================================================= 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] \n", + fprintf(stderr, "Usage: %s [-a ARCHITECTURE] [-c] \n", argv[0]); 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-c: Do not generate CFI section\n"); fprintf(stderr, "\t-h: Usage\n"); fprintf(stderr, "\t-?: Usage\n"); } @@ -102,7 +104,7 @@ static void SetupOptions(int argc, const char *argv[], Options *options) { extern int optind; 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) { case 'a': { const NXArchInfo *arch_info = NXGetArchInfoFromName(optarg); @@ -114,6 +116,9 @@ static void SetupOptions(int argc, const char *argv[], Options *options) { options->arch = arch_info; break; } + case 'c': + options->cfi = false; + break; case '?': case 'h': Usage(argc, argv); @@ -121,7 +126,7 @@ static void SetupOptions(int argc, const char *argv[], Options *options) { break; } } - + if ((argc - optind) != 1) { fprintf(stderr, "Must specify Mach-o file\n"); Usage(argc, argv); @@ -137,7 +142,7 @@ static void SetupOptions(int argc, const char *argv[], Options *options) { int main (int argc, const char * argv[]) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; Options options; - bool result; + bool result; SetupOptions(argc, argv, &options); result = Start(options);