bug 839126 - Update Breakpad to SVN r1112. r=upstream. Also fix a local patch that hadn't applied properly.

--HG--
rename : toolkit/crashreporter/breakpad-patches/06-readsymboldata-mac => toolkit/crashreporter/breakpad-patches/06-readsymboldata-mac.patch
extra : rebase_source : dcd743469929ecc3fa83ddd11663840628841900
This commit is contained in:
Ted Mielczarek 2013-02-07 12:56:27 -05:00
parent 283e84505d
commit 98609c8753
38 changed files with 1850 additions and 4988 deletions

View File

@ -1,20 +1,15 @@
# HG changeset patch
# User Ted Mielczarek <ted@mielczarek.org>
# Date 1352220493 18000
# Node ID af59ab8ee1ff8efa2a5e9d53fa494bb17ebad582
# Parent 1b7cd930bef43cf597e66fefba27218affa724d6
# Node ID a38d670da97e338234375756313b2f47650e01fb
# Parent 201b7c6793586b6b7cfcaa02f4e29700c4c12ef1
Add APIs for querying Module data
R=glandium at https://breakpad.appspot.com/511003/
diff --git a/src/common/module.cc b/src/common/module.cc
--- a/src/common/module.cc
+++ b/src/common/module.cc
@@ -58,17 +58,17 @@
Module::~Module() {
for (FileByNameMap::iterator it = files_.begin(); it != files_.end(); ++it)
delete it->second;
for (FunctionSet::iterator it = functions_.begin();
@@ -63,7 +63,7 @@
it != functions_.end(); ++it) {
delete *it;
}
@ -23,17 +18,7 @@ diff --git a/src/common/module.cc b/src/common/module.cc
it != stack_frame_entries_.end(); ++it) {
delete *it;
}
for (ExternSet::iterator it = externs_.begin(); it != externs_.end(); ++it)
delete *it;
}
void Module::SetLoadAddress(Address address) {
@@ -88,39 +88,84 @@
}
void Module::AddFunctions(vector<Function *>::iterator begin,
vector<Function *>::iterator end) {
for (vector<Function *>::iterator it = begin; it != end; ++it)
@@ -93,8 +93,14 @@
AddFunction(*it);
}
@ -50,16 +35,7 @@ diff --git a/src/common/module.cc b/src/common/module.cc
}
void Module::AddExtern(Extern *ext) {
std::pair<ExternSet::iterator,bool> ret = externs_.insert(ext);
if (!ret.second) {
// Free the duplicate that was not inserted because this Module
// now owns it.
delete ext;
}
}
void Module::GetFunctions(vector<Function *> *vec,
vector<Function *>::iterator i) {
@@ -111,11 +117,50 @@
vec->insert(i, functions_.begin(), functions_.end());
}
@ -110,17 +86,7 @@ diff --git a/src/common/module.cc b/src/common/module.cc
Module::File *Module::FindFile(const string &name) {
// A tricky bit here. The key of each map entry needs to be a
// pointer to the entry's File's name string. This means that we
// can't do the initial lookup with any operation that would create
// an empty entry for us if the name isn't found (like, say,
// operator[] or insert do), because such a created entry's key will
// be a pointer the string passed as our argument. Since the key of
// a map's value type is const, we can't fix it up once we've
@@ -150,18 +195,35 @@
}
void Module::GetFiles(vector<File *> *vec) {
vec->clear();
for (FileByNameMap::iterator it = files_.begin(); it != files_.end(); ++it)
@@ -155,8 +200,25 @@
vec->push_back(it->second);
}
@ -148,17 +114,7 @@ diff --git a/src/common/module.cc b/src/common/module.cc
}
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->second->source_id = -1;
}
@@ -256,17 +318,17 @@
<< (ext->address - load_address_) << " 0 "
<< ext->name << dec << endl;
if (!stream.good())
return ReportError();
}
@@ -261,7 +323,7 @@
if (cfi) {
// Write out 'STACK CFI INIT' and 'STACK CFI' records.
@ -167,20 +123,10 @@ diff --git a/src/common/module.cc b/src/common/module.cc
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))
diff --git a/src/common/module.h b/src/common/module.h
--- a/src/common/module.h
+++ b/src/common/module.h
@@ -163,16 +163,23 @@
struct ExternCompare {
bool operator() (const Extern *lhs,
const Extern *rhs) const {
return lhs->address < rhs->address;
@@ -168,6 +168,13 @@
}
};
@ -194,17 +140,7 @@ diff --git a/src/common/module.h b/src/common/module.h
// Create a new module with the given name, operating system,
// architecture, and ID string.
Module(const string &name, const string &os, const string &architecture,
const string &id);
~Module();
// Set the module's load address to LOAD_ADDRESS; addresses given
// for functions and lines will be written to the Breakpad symbol
@@ -222,37 +229,49 @@
// Insert pointers to the functions added to this module at I in
// VEC. The pointed-to Functions are still owned by this module.
// (Since this is effectively a copy of the function list, this is
// mostly useful for testing; other uses should probably get a more
@@ -227,6 +234,10 @@
// appropriate interface.)
void GetFunctions(vector<Function *> *vec, vector<Function *>::iterator i);
@ -215,7 +151,7 @@ diff --git a/src/common/module.h b/src/common/module.h
// Insert pointers to the externs added to this module at I in
// VEC. The pointed-to Externs are still owned by this module.
// (Since this is effectively a copy of the extern list, this is
// mostly useful for testing; other uses should probably get a more
@@ -234,6 +245,10 @@
// appropriate interface.)
void GetExterns(vector<Extern *> *vec, vector<Extern *>::iterator i);
@ -226,14 +162,7 @@ diff --git a/src/common/module.h b/src/common/module.h
// Clear VEC and fill it with pointers to the Files added to this
// module, sorted by name. The pointed-to Files are still owned by
// this module. (Since this is effectively a copy of the file list,
// this is mostly useful for testing; other uses should probably get
// a more appropriate interface.)
void GetFiles(vector<File *> *vec);
// Clear VEC and fill it with pointers to the StackFrameEntry
// objects that have been added to this module. (Since this is
// effectively a copy of the stack frame entry list, this is mostly
// useful for testing; other uses should probably get
@@ -248,6 +263,10 @@
// a more appropriate interface.)
void GetStackFrameEntries(vector<StackFrameEntry *> *vec);
@ -244,17 +173,7 @@ diff --git a/src/common/module.h b/src/common/module.h
// Find those files in this module that are actually referred to by
// functions' line number data, and assign them source id numbers.
// Set the source id numbers for all other files --- unused by the
// source line data --- to -1. We do this before writing out the
// symbol file, at which point we omit any unused files.
void AssignSourceIds();
// Call AssignSourceIds, and write this module to STREAM in the
@@ -296,25 +315,28 @@
typedef map<const string *, File *, CompareStringPtrs> FileByNameMap;
// A set containing Function structures, sorted by address.
typedef set<Function *, FunctionCompare> FunctionSet;
@@ -301,6 +320,9 @@
// A set containing Extern structures, sorted by address.
typedef set<Extern *, ExternCompare> ExternSet;
@ -264,8 +183,7 @@ diff --git a/src/common/module.h b/src/common/module.h
// The module owns all the files and functions that have been added
// to it; destroying the module frees the Files and Functions these
// point to.
FileByNameMap files_; // This module's source files.
FunctionSet functions_; // This module's functions.
@@ -309,7 +331,7 @@
// The module owns all the call frame info entries that have been
// added to it.
@ -274,20 +192,10 @@ diff --git a/src/common/module.h b/src/common/module.h
// The module owns all the externs that have been added to it;
// destroying the module frees the Externs these point to.
ExternSet externs_;
};
} // namespace google_breakpad
diff --git a/src/common/module_unittest.cc b/src/common/module_unittest.cc
--- a/src/common/module_unittest.cc
+++ b/src/common/module_unittest.cc
@@ -329,63 +329,63 @@
entry3->rule_changes[0x36682fad3763ffffULL][".cfa"] =
"I think I know";
m.AddStackFrameEntry(entry3);
// Check that Write writes STACK CFI records properly.
@@ -334,11 +334,6 @@
m.Write(s, true);
string contents = s.str();
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
@ -299,7 +207,7 @@ diff --git a/src/common/module_unittest.cc b/src/common/module_unittest.cc
"STACK CFI INIT 5e8d0db0a7075c6c 1c7edb12a7aea229"
" .cfa: Whose woods are these\n"
"STACK CFI 36682fad3763ffff"
" .cfa: I think I know"
@@ -346,7 +341,12 @@
" stromboli: his house is in\n"
"STACK CFI 47ceb0f63c269d7f"
" calzone: the village though"
@ -313,7 +221,7 @@ diff --git a/src/common/module_unittest.cc b/src/common/module_unittest.cc
contents.c_str());
// Check that GetStackFrameEntries works.
vector<Module::StackFrameEntry *> entries;
@@ -354,10 +354,18 @@
m.GetStackFrameEntries(&entries);
ASSERT_EQ(3U, entries.size());
// Check first entry.
@ -336,11 +244,7 @@ diff --git a/src/common/module_unittest.cc b/src/common/module_unittest.cc
// Check second entry.
EXPECT_EQ(0x8064f3af5e067e38ULL, entries[1]->address);
EXPECT_EQ(0x0de2a5ee55509407ULL, entries[1]->size);
ASSERT_EQ(3U, entries[1]->initial_rules.size());
Module::RuleMap entry2_initial;
entry2_initial[".cfa"] = "I think that I shall never see";
entry2_initial["stromboli"] = "a poem lovely as a tree";
entry2_initial["cannoli"] = "a tree whose hungry mouth is prest";
@@ -369,18 +377,10 @@
EXPECT_THAT(entries[1]->initial_rules, ContainerEq(entry2_initial));
ASSERT_EQ(0U, entries[1]->rule_changes.size());
// Check third entry.
@ -363,17 +267,7 @@ diff --git a/src/common/module_unittest.cc b/src/common/module_unittest.cc
}
TEST(Construct, UniqueFiles) {
Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
Module::File *file1 = m.FindFile("foo");
Module::File *file2 = m.FindFile(string("bar"));
Module::File *file3 = m.FindFile(string("foo"));
Module::File *file4 = m.FindFile("bar");
@@ -483,8 +483,155 @@
m.Write(s, true);
string contents = s.str();
EXPECT_STREQ("MODULE " MODULE_OS " " MODULE_ARCH " "
MODULE_ID " " MODULE_NAME "\n"
@@ -488,3 +488,150 @@
"PUBLIC ffff 0 _xyz\n",
contents.c_str());
}

View File

@ -1,20 +1,15 @@
# HG changeset patch
# User Ted Mielczarek <ted@mielczarek.org>
# Date 1352220493 18000
# Node ID 0f7f04d2a249b9a9bbc61eb350f177054ab11601
# Parent 96b3a2bb799eb401c8a80ed6c134289f91eb7436
# Node ID e57a7855d118e645730887e2b921dc83f89a25e7
# Parent a38d670da97e338234375756313b2f47650e01fb
Allow reading just CFI data when reading symbols
R=thestig at https://breakpad.appspot.com/517002/
diff --git a/src/common/linux/dump_symbols.cc b/src/common/linux/dump_symbols.cc
--- a/src/common/linux/dump_symbols.cc
+++ b/src/common/linux/dump_symbols.cc
@@ -505,16 +505,17 @@
};
template<typename ElfClass>
bool LoadSymbols(const string& obj_file,
const bool big_endian,
@@ -510,6 +510,7 @@
const typename ElfClass::Ehdr* elf_header,
const bool read_gnu_debug_link,
LoadSymbolsInfo<ElfClass>* info,
@ -22,17 +17,7 @@ diff --git a/src/common/linux/dump_symbols.cc b/src/common/linux/dump_symbols.cc
Module* module) {
typedef typename ElfClass::Addr Addr;
typedef typename ElfClass::Phdr Phdr;
typedef typename ElfClass::Shdr Shdr;
Addr loading_addr = GetLoadingAddress<ElfClass>(
GetOffset<ElfClass, Phdr>(elf_header, elf_header->e_phoff),
elf_header->e_phnum);
@@ -525,91 +526,95 @@
GetOffset<ElfClass, Shdr>(elf_header, elf_header->e_shoff);
const Shdr* section_names = sections + elf_header->e_shstrndx;
const char* names =
GetOffset<ElfClass, char>(elf_header, section_names->sh_offset);
const char *names_end = names + section_names->sh_size;
@@ -530,81 +531,85 @@
bool found_debug_info_section = false;
bool found_usable_info = false;
@ -181,17 +166,7 @@ diff --git a/src/common/linux/dump_symbols.cc b/src/common/linux/dump_symbols.cc
}
if (!found_debug_info_section) {
fprintf(stderr, "%s: file contains no debugging information"
" (no \".stab\" or \".debug_info\" sections)\n",
obj_file.c_str());
// Failed, but maybe there's a .gnu_debuglink section?
@@ -631,17 +636,17 @@
} else {
fprintf(stderr, ".gnu_debuglink section found in '%s', "
"but no debug path specified.\n", obj_file.c_str());
}
} else {
@@ -636,7 +641,7 @@
fprintf(stderr, "%s does not contain a .gnu_debuglink section.\n",
obj_file.c_str());
}
@ -200,17 +175,7 @@ diff --git a/src/common/linux/dump_symbols.cc b/src/common/linux/dump_symbols.cc
// The caller doesn't want to consult .gnu_debuglink.
// See if there are export symbols available.
const Shdr* dynsym_section =
FindElfSectionByName<ElfClass>(".dynsym", SHT_DYNSYM,
sections, names, names_end,
elf_header->e_shnum);
const Shdr* dynstr_section =
FindElfSectionByName<ElfClass>(".dynstr", SHT_STRTAB,
@@ -726,17 +731,17 @@
free(c_filename);
return base;
}
template<typename ElfClass>
@@ -731,7 +736,7 @@
bool ReadSymbolDataElfClass(const typename ElfClass::Ehdr* elf_header,
const string& obj_filename,
const std::vector<string>& debug_dirs,
@ -219,17 +184,7 @@ diff --git a/src/common/linux/dump_symbols.cc b/src/common/linux/dump_symbols.cc
Module** out_module) {
typedef typename ElfClass::Ehdr Ehdr;
typedef typename ElfClass::Shdr Shdr;
*out_module = NULL;
unsigned char identifier[16];
if (!google_breakpad::FileID::ElfFileIdentifierFromMappedFile(elf_header,
@@ -760,17 +765,18 @@
string name = BaseFileName(obj_filename);
string os = "Linux";
string id = FormatIdentifier(identifier);
@@ -765,7 +770,8 @@
LoadSymbolsInfo<ElfClass> info(debug_dirs);
scoped_ptr<Module> module(new Module(name, os, architecture, id));
if (!LoadSymbols<ElfClass>(obj_filename, big_endian, elf_header,
@ -239,17 +194,7 @@ diff --git a/src/common/linux/dump_symbols.cc b/src/common/linux/dump_symbols.cc
const string debuglink_file = info.debuglink_file();
if (debuglink_file.empty())
return false;
// Load debuglink ELF file.
fprintf(stderr, "Found debugging info in %s\n", debuglink_file.c_str());
MmapWrapper debug_map_wrapper;
Ehdr* debug_elf_header = NULL;
@@ -798,75 +804,76 @@
return false;
if (debug_big_endian != big_endian) {
fprintf(stderr, "%s and %s does not match in endianness\n",
obj_filename.c_str(), debuglink_file.c_str());
return false;
@@ -803,7 +809,8 @@
}
if (!LoadSymbols<ElfClass>(debuglink_file, debug_big_endian,
@ -259,16 +204,7 @@ diff --git a/src/common/linux/dump_symbols.cc b/src/common/linux/dump_symbols.cc
return false;
}
}
*out_module = module.release();
return true;
}
} // namespace
namespace google_breakpad {
// Not explicitly exported, but not static so it can be used in unit tests.
@@ -820,7 +827,7 @@
bool ReadSymbolDataInternal(const uint8_t* obj_file,
const string& obj_filename,
const std::vector<string>& debug_dirs,
@ -277,11 +213,7 @@ diff --git a/src/common/linux/dump_symbols.cc b/src/common/linux/dump_symbols.cc
Module** module) {
if (!IsValidElf(obj_file)) {
fprintf(stderr, "Not a valid ELF file: %s\n", obj_filename.c_str());
return false;
}
int elfclass = ElfClass(obj_file);
@@ -832,12 +839,12 @@
if (elfclass == ELFCLASS32) {
return ReadSymbolDataElfClass<ElfClass32>(
reinterpret_cast<const Elf32_Ehdr*>(obj_file), obj_filename, debug_dirs,
@ -296,7 +228,7 @@ diff --git a/src/common/linux/dump_symbols.cc b/src/common/linux/dump_symbols.cc
}
return false;
}
@@ -845,20 +852,20 @@
bool WriteSymbolFile(const string &obj_file,
const std::vector<string>& debug_dirs,
@ -321,7 +253,7 @@ diff --git a/src/common/linux/dump_symbols.cc b/src/common/linux/dump_symbols.cc
Module** module) {
MmapWrapper map_wrapper;
void* elf_header = NULL;
if (!LoadELF(obj_file, &map_wrapper, &elf_header))
@@ -866,7 +873,7 @@
return false;
return ReadSymbolDataInternal(reinterpret_cast<uint8_t*>(elf_header),
@ -333,12 +265,7 @@ diff --git a/src/common/linux/dump_symbols.cc b/src/common/linux/dump_symbols.cc
diff --git a/src/common/linux/dump_symbols.h b/src/common/linux/dump_symbols.h
--- a/src/common/linux/dump_symbols.h
+++ b/src/common/linux/dump_symbols.h
@@ -34,36 +34,37 @@
#ifndef COMMON_LINUX_DUMP_SYMBOLS_H__
#define COMMON_LINUX_DUMP_SYMBOLS_H__
#include <iostream>
@@ -39,6 +39,7 @@
#include <string>
#include <vector>
@ -346,11 +273,7 @@ diff --git a/src/common/linux/dump_symbols.h b/src/common/linux/dump_symbols.h
#include "common/using_std_string.h"
namespace google_breakpad {
class Module;
// Find all the debugging information in OBJ_FILE, an ELF executable
// or shared library, and write it to SYM_STREAM in the Breakpad symbol
@@ -50,10 +51,10 @@
// file format.
// If OBJ_FILE has been stripped but contains a .gnu_debuglink section,
// then look for the debug file in DEBUG_DIRS.
@ -363,7 +286,7 @@ diff --git a/src/common/linux/dump_symbols.h b/src/common/linux/dump_symbols.h
std::ostream &sym_stream);
// As above, but simply return the debugging information in MODULE
// instead of writing it to a stream. The caller owns the resulting
@@ -61,7 +62,7 @@
// Module object and must delete it when finished.
bool ReadSymbolData(const string& obj_file,
const std::vector<string>& debug_dirs,
@ -372,17 +295,10 @@ diff --git a/src/common/linux/dump_symbols.h b/src/common/linux/dump_symbols.h
Module** module);
} // namespace google_breakpad
#endif // COMMON_LINUX_DUMP_SYMBOLS_H__
diff --git a/src/common/linux/dump_symbols_unittest.cc b/src/common/linux/dump_symbols_unittest.cc
--- a/src/common/linux/dump_symbols_unittest.cc
+++ b/src/common/linux/dump_symbols_unittest.cc
@@ -43,17 +43,17 @@
#include "common/linux/synth_elf.h"
#include "common/module.h"
#include "common/using_std_string.h"
namespace google_breakpad {
@@ -48,7 +48,7 @@
bool ReadSymbolDataInternal(const uint8_t* obj_file,
const string& obj_filename,
const std::vector<string>& debug_dir,
@ -391,17 +307,7 @@ diff --git a/src/common/linux/dump_symbols_unittest.cc b/src/common/linux/dump_s
Module** module);
}
using google_breakpad::synth_elf::ELF;
using google_breakpad::synth_elf::StringTable;
using google_breakpad::synth_elf::SymbolTable;
using google_breakpad::test_assembler::kLittleEndian;
using google_breakpad::test_assembler::Section;
@@ -81,17 +81,17 @@
TEST_F(DumpSymbols, Invalid) {
Elf32_Ehdr header;
memset(&header, 0, sizeof(header));
Module* module;
@@ -86,7 +86,7 @@
EXPECT_FALSE(ReadSymbolDataInternal(reinterpret_cast<uint8_t*>(&header),
"foo",
vector<string>(),
@ -410,17 +316,7 @@ diff --git a/src/common/linux/dump_symbols_unittest.cc b/src/common/linux/dump_s
&module));
}
TEST_F(DumpSymbols, SimplePublic32) {
ELF elf(EM_386, ELFCLASS32, kLittleEndian);
// Zero out text section for simplicity.
Section text(kLittleEndian);
text.Append(4096, 0);
@@ -113,21 +113,21 @@
elf.Finish();
GetElfContents(elf);
Module* module;
@@ -118,11 +118,11 @@
EXPECT_TRUE(ReadSymbolDataInternal(elfdata,
"foo",
vector<string>(),
@ -434,17 +330,7 @@ diff --git a/src/common/linux/dump_symbols_unittest.cc b/src/common/linux/dump_s
EXPECT_EQ("MODULE Linux x86 000000000000000000000000000000000 foo\n"
"PUBLIC 1000 0 superfunc\n",
s.str());
delete module;
}
TEST_F(DumpSymbols, SimplePublic64) {
ELF elf(EM_X86_64, ELFCLASS64, kLittleEndian);
@@ -152,17 +152,17 @@
elf.Finish();
GetElfContents(elf);
Module* module;
@@ -157,11 +157,11 @@
EXPECT_TRUE(ReadSymbolDataInternal(elfdata,
"foo",
vector<string>(),
@ -458,16 +344,10 @@ diff --git a/src/common/linux/dump_symbols_unittest.cc b/src/common/linux/dump_s
EXPECT_EQ("MODULE Linux x86_64 000000000000000000000000000000000 foo\n"
"PUBLIC 1000 0 superfunc\n",
s.str());
}
diff --git a/src/common/mac/dump_syms.h b/src/common/mac/dump_syms.h
--- a/src/common/mac/dump_syms.h
+++ b/src/common/mac/dump_syms.h
@@ -42,23 +42,25 @@
#include <ostream>
#include <string>
#include <vector>
@@ -47,13 +47,15 @@
#include "common/byte_cursor.h"
#include "common/mac/macho_reader.h"
#include "common/module.h"
@ -485,17 +365,7 @@ diff --git a/src/common/mac/dump_syms.h b/src/common/mac/dump_syms.h
object_filename_(),
contents_(),
selected_object_file_(),
selected_object_name_() { }
~DumpSymbols() {
[input_pathname_ release];
[object_filename_ release];
[contents_ release];
@@ -105,19 +107,19 @@
const struct fat_arch *AvailableArchitectures(size_t *count) {
*count = object_files_.size();
if (object_files_.size() > 0)
return &object_files_[0];
return NULL;
@@ -110,9 +112,9 @@
}
// Read the selected object file's debugging information, and write it out to
@ -508,17 +378,7 @@ diff --git a/src/common/mac/dump_syms.h b/src/common/mac/dump_syms.h
private:
// Used internally.
class DumperLineToModule;
class LoadCommandDumper;
// Return an identifier string for the file this DumpSymbols is dumping.
std::string Identifier();
@@ -134,16 +136,19 @@
// 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,
@@ -139,6 +141,9 @@
const mach_o::Section &section,
bool eh_frame) const;
@ -528,20 +388,10 @@ diff --git a/src/common/mac/dump_syms.h b/src/common/mac/dump_syms.h
// 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.
diff --git a/src/common/mac/dump_syms.mm b/src/common/mac/dump_syms.mm
--- a/src/common/mac/dump_syms.mm
+++ b/src/common/mac/dump_syms.mm
@@ -50,16 +50,17 @@
#include "common/dwarf_cu_to_module.h"
#include "common/dwarf_line_to_module.h"
#include "common/mac/file_id.h"
#include "common/mac/arch_utilities.h"
#include "common/mac/macho_reader.h"
@@ -55,6 +55,7 @@
#include "common/module.h"
#include "common/stabs_reader.h"
#include "common/stabs_to_module.h"
@ -549,17 +399,7 @@ diff --git a/src/common/mac/dump_syms.mm b/src/common/mac/dump_syms.mm
#ifndef CPU_TYPE_ARM
#define CPU_TYPE_ARM (static_cast<cpu_type_t>(12))
#endif // CPU_TYPE_ARM
using dwarf2reader::ByteReader;
using google_breakpad::DwarfCUToModule;
using google_breakpad::DwarfLineToModule;
@@ -365,52 +366,61 @@
// Module.
class DumpSymbols::LoadCommandDumper:
public mach_o::Reader::LoadCommandHandler {
public:
// Create a load command dumper handling load commands from READER's
@@ -370,8 +371,12 @@
// file, and adding data to MODULE.
LoadCommandDumper(const DumpSymbols &dumper,
google_breakpad::Module *module,
@ -574,8 +414,7 @@ diff --git a/src/common/mac/dump_syms.mm b/src/common/mac/dump_syms.mm
bool SegmentCommand(const mach_o::Segment &segment);
bool SymtabCommand(const ByteBuffer &entries, const ByteBuffer &strings);
private:
@@ -380,6 +385,7 @@
const DumpSymbols &dumper_;
google_breakpad::Module *module_; // WEAK
const mach_o::Reader &reader_;
@ -583,7 +422,7 @@ diff --git a/src/common/mac/dump_syms.mm b/src/common/mac/dump_syms.mm
};
bool DumpSymbols::LoadCommandDumper::SegmentCommand(const Segment &segment) {
mach_o::SectionMap section_map;
@@ -387,7 +393,7 @@
if (!reader_.MapSegmentSections(segment, &section_map))
return false;
@ -592,11 +431,7 @@ diff --git a/src/common/mac/dump_syms.mm b/src/common/mac/dump_syms.mm
module_->SetLoadAddress(segment.vmaddr);
mach_o::SectionMap::const_iterator eh_frame =
section_map.find("__eh_frame");
if (eh_frame != section_map.end()) {
// If there is a problem reading this, don't treat it as a fatal error.
dumper_.ReadCFI(module_, reader_, eh_frame->second, true);
}
return true;
@@ -399,13 +405,17 @@
}
if (segment.name == "__DWARF") {
@ -621,17 +456,7 @@ diff --git a/src/common/mac/dump_syms.mm b/src/common/mac/dump_syms.mm
}
}
return true;
}
bool DumpSymbols::LoadCommandDumper::SymtabCommand(const ByteBuffer &entries,
const ByteBuffer &strings) {
@@ -424,17 +434,17 @@
true,
&stabs_to_module);
if (!stabs_reader.Process())
return false;
stabs_to_module.Finalize();
@@ -429,7 +439,7 @@
return true;
}
@ -640,17 +465,7 @@ diff --git a/src/common/mac/dump_syms.mm b/src/common/mac/dump_syms.mm
// Select an object file, if SetArchitecture hasn't been called to set one
// explicitly.
if (!selected_object_file_) {
// If there's only one architecture, that's the one.
if (object_files_.size() == 1)
selected_object_file_ = &object_files_[0];
else {
// Look for an object file whose architecture matches our own.
@@ -489,16 +499,16 @@
if (!reader.Read(reinterpret_cast<const uint8_t *>([contents_ bytes])
+ selected_object_file_->offset,
selected_object_file_->size,
selected_object_file_->cputype,
selected_object_file_->cpusubtype))
@@ -494,11 +504,11 @@
return false;
// Walk its load commands, and deal with whatever is there.
@ -667,12 +482,7 @@ diff --git a/src/common/mac/dump_syms.mm b/src/common/mac/dump_syms.mm
diff --git a/src/common/module.cc b/src/common/module.cc
--- a/src/common/module.cc
+++ b/src/common/module.cc
@@ -256,72 +256,74 @@
it != rule_map.end(); ++it) {
if (it != rule_map.begin())
stream << ' ';
stream << it->first << ": " << it->second;
}
@@ -266,62 +266,64 @@
return stream.good();
}
@ -782,20 +592,10 @@ diff --git a/src/common/module.cc b/src/common/module.cc
// Write out 'STACK CFI INIT' and 'STACK CFI' records.
StackFrameEntrySet::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;
diff --git a/src/common/module.h b/src/common/module.h
--- a/src/common/module.h
+++ b/src/common/module.h
@@ -39,16 +39,17 @@
#define COMMON_LINUX_MODULE_H__
#include <iostream>
#include <map>
#include <set>
@@ -44,6 +44,7 @@
#include <string>
#include <vector>
@ -803,17 +603,7 @@ diff --git a/src/common/module.h b/src/common/module.h
#include "common/using_std_string.h"
#include "google_breakpad/common/breakpad_types.h"
namespace google_breakpad {
using std::set;
using std::vector;
using std::map;
@@ -273,23 +274,25 @@
// source line data --- to -1. We do this before writing out the
// symbol file, at which point we omit any unused files.
void AssignSourceIds();
// Call AssignSourceIds, and write this module to STREAM in the
@@ -278,13 +279,15 @@
// 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,
@ -831,20 +621,10 @@ diff --git a/src/common/module.h b/src/common/module.h
private:
// Report an error that has occurred writing the symbol file, using
// errno to find the appropriate cause. Return false.
static bool ReportError();
// Write RULE_MAP to STREAM, in the form appropriate for 'STACK CFI'
// records, without a final newline. Return true if all goes well;
diff --git a/src/common/module_unittest.cc b/src/common/module_unittest.cc
--- a/src/common/module_unittest.cc
+++ b/src/common/module_unittest.cc
@@ -65,17 +65,17 @@
#define MODULE_NAME "name with spaces"
#define MODULE_OS "os-name"
#define MODULE_ARCH "architecture"
#define MODULE_ID "id-string"
@@ -70,7 +70,7 @@
TEST(Write, Header) {
stringstream s;
Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
@ -853,17 +633,7 @@ diff --git a/src/common/module_unittest.cc b/src/common/module_unittest.cc
string contents = s.str();
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n",
contents.c_str());
}
TEST(Write, OneLineFunc) {
stringstream s;
Module m(MODULE_NAME, MODULE_OS, MODULE_ARCH, MODULE_ID);
@@ -86,17 +86,17 @@
function->address = 0xe165bf8023b9d9abLL;
function->size = 0x1e4bb0eb1cbf5b09LL;
function->parameter_size = 0x772beee89114358aLL;
Module::Line line = { 0xe165bf8023b9d9abLL, 0x1e4bb0eb1cbf5b09LL,
file, 67519080 };
@@ -91,7 +91,7 @@
function->lines.push_back(line);
m.AddFunction(function);
@ -872,17 +642,7 @@ diff --git a/src/common/module_unittest.cc b/src/common/module_unittest.cc
string contents = s.str();
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
"FILE 0 file_name.cc\n"
"FUNC e165bf8023b9d9ab 1e4bb0eb1cbf5b09 772beee89114358a"
" function_name\n"
"e165bf8023b9d9ab 1e4bb0eb1cbf5b09 67519080 0\n",
contents.c_str());
}
@@ -136,17 +136,17 @@
"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
@@ -141,7 +141,7 @@
// the module must work fine.
m.SetLoadAddress(0x2ab698b0b6407073LL);
@ -891,17 +651,7 @@ diff --git a/src/common/module_unittest.cc b/src/common/module_unittest.cc
string contents = s.str();
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
"FILE 0 filename-a.cc\n"
"FILE 1 filename-b.cc\n"
"FUNC 9410dc39a798c580 2922088f98d3f6fc e5e9aa008bd5f0d0"
" A_FLIBBERTIJIBBET::a_will_o_the_wisp(a clown)\n"
"b03cc3106d47eb91 cf621b8d324d0eb 67519080 0\n"
"9410dc39a798c580 1c2be6d6c5af2611 41676901 1\n"
@@ -192,17 +192,17 @@
EXPECT_NE(-1, vec[0]->source_id);
// Expect filename2 not to be used.
EXPECT_STREQ("filename2", vec[1]->name.c_str());
EXPECT_EQ(-1, vec[1]->source_id);
EXPECT_STREQ("filename3", vec[2]->name.c_str());
@@ -197,7 +197,7 @@
EXPECT_NE(-1, vec[2]->source_id);
stringstream s;
@ -910,17 +660,7 @@ diff --git a/src/common/module_unittest.cc b/src/common/module_unittest.cc
string contents = s.str();
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
"FILE 0 filename1\n"
"FILE 1 filename3\n"
"FUNC 9b926d464f0b9384 4f524a4ba795e6a6 bbe8133a6641c9b7"
" function_name\n"
"595fa44ebacc1086 1e1e0191b066c5b3 137850127 0\n"
"401ce8c8a12d25e3 895751c41b8d2ce2 28113549 1\n",
@@ -240,17 +240,17 @@
"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
@@ -245,7 +245,7 @@
// the module must work fine.
m.SetLoadAddress(0x2ab698b0b6407073LL);
@ -929,17 +669,7 @@ diff --git a/src/common/module_unittest.cc b/src/common/module_unittest.cc
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());
}
@@ -274,17 +274,17 @@
// Put them in a vector.
vector<Module::Function *> vec;
vec.push_back(function1);
vec.push_back(function2);
@@ -279,7 +279,7 @@
m.AddFunctions(vec.begin(), vec.end());
@ -948,17 +678,7 @@ diff --git a/src/common/module_unittest.cc b/src/common/module_unittest.cc
string contents = s.str();
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
"FUNC 2987743d0b35b13f b369db048deb3010 938e556cb5a79988"
" _and_void\n"
"FUNC d35024aa7ca7da5c 200b26e605f99071 f14ac4fed48c4a99"
" _without_form\n",
contents.c_str());
@@ -326,17 +326,17 @@
"he will not see me stopping here";
entry3->rule_changes[0x36682fad3763ffffULL]["stromboli"] =
"his house is in";
entry3->rule_changes[0x36682fad3763ffffULL][".cfa"] =
"I think I know";
@@ -331,7 +331,7 @@
m.AddStackFrameEntry(entry3);
// Check that Write writes STACK CFI records properly.
@ -967,17 +687,7 @@ diff --git a/src/common/module_unittest.cc b/src/common/module_unittest.cc
string contents = s.str();
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
"STACK CFI INIT 5e8d0db0a7075c6c 1c7edb12a7aea229"
" .cfa: Whose woods are these\n"
"STACK CFI 36682fad3763ffff"
" .cfa: I think I know"
" stromboli: his house is in\n"
"STACK CFI 47ceb0f63c269d7f"
@@ -402,17 +402,17 @@
// Two functions.
Module::Function *function1 = generate_duplicate_function("_without_form");
Module::Function *function2 = generate_duplicate_function("_without_form");
@@ -407,7 +407,7 @@
m.AddFunction(function1);
m.AddFunction(function2);
@ -986,17 +696,7 @@ diff --git a/src/common/module_unittest.cc b/src/common/module_unittest.cc
string contents = s.str();
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
"FUNC d35402aac7a7ad5c 200b26e605f99071 f14ac4fed48c4a99"
" _without_form\n",
contents.c_str());
}
TEST(Construct, FunctionsWithSameAddress) {
@@ -421,17 +421,17 @@
// Two functions.
Module::Function *function1 = generate_duplicate_function("_without_form");
Module::Function *function2 = generate_duplicate_function("_and_void");
@@ -426,7 +426,7 @@
m.AddFunction(function1);
m.AddFunction(function2);
@ -1005,17 +705,7 @@ diff --git a/src/common/module_unittest.cc b/src/common/module_unittest.cc
string contents = s.str();
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
"FUNC d35402aac7a7ad5c 200b26e605f99071 f14ac4fed48c4a99"
" _and_void\n"
"FUNC d35402aac7a7ad5c 200b26e605f99071 f14ac4fed48c4a99"
" _without_form\n",
contents.c_str());
}
@@ -448,17 +448,17 @@
extern1->name = "_abc";
Module::Extern *extern2 = new(Module::Extern);
extern2->address = 0xaaaa;
extern2->name = "_xyz";
@@ -453,7 +453,7 @@
m.AddExtern(extern1);
m.AddExtern(extern2);
@ -1024,17 +714,7 @@ diff --git a/src/common/module_unittest.cc b/src/common/module_unittest.cc
string contents = s.str();
EXPECT_STREQ("MODULE " MODULE_OS " " MODULE_ARCH " "
MODULE_ID " " MODULE_NAME "\n"
"PUBLIC aaaa 0 _xyz\n"
"PUBLIC ffff 0 _abc\n",
contents.c_str());
}
@@ -475,17 +475,17 @@
extern1->name = "_xyz";
Module::Extern *extern2 = new(Module::Extern);
extern2->address = 0xffff;
extern2->name = "_abc";
@@ -480,7 +480,7 @@
m.AddExtern(extern1);
m.AddExtern(extern2);
@ -1043,11 +723,6 @@ diff --git a/src/common/module_unittest.cc b/src/common/module_unittest.cc
string contents = s.str();
EXPECT_STREQ("MODULE " MODULE_OS " " MODULE_ARCH " "
MODULE_ID " " MODULE_NAME "\n"
"PUBLIC ffff 0 _xyz\n",
contents.c_str());
}
diff --git a/src/common/symbol_data.h b/src/common/symbol_data.h
new file mode 100644
--- /dev/null
@ -1098,12 +773,7 @@ new file mode 100644
diff --git a/src/tools/linux/dump_syms/dump_syms.cc b/src/tools/linux/dump_syms/dump_syms.cc
--- a/src/tools/linux/dump_syms/dump_syms.cc
+++ b/src/tools/linux/dump_syms/dump_syms.cc
@@ -63,15 +63,16 @@
std::vector<string> debug_dirs;
binary = argv[binary_index];
for (int debug_dir_index = binary_index + 1;
debug_dir_index < argc;
++debug_dir_index) {
@@ -68,7 +68,8 @@
debug_dirs.push_back(argv[debug_dir_index]);
}
@ -1113,18 +783,10 @@ diff --git a/src/tools/linux/dump_syms/dump_syms.cc b/src/tools/linux/dump_syms/
fprintf(stderr, "Failed to write symbol file.\n");
return 1;
}
return 0;
}
diff --git a/src/tools/mac/dump_syms/dump_syms_tool.mm b/src/tools/mac/dump_syms/dump_syms_tool.mm
--- a/src/tools/mac/dump_syms/dump_syms_tool.mm
+++ b/src/tools/mac/dump_syms/dump_syms_tool.mm
@@ -49,17 +49,17 @@
Options() : srcPath(), arch(), cfi(true) { }
NSString *srcPath;
const NXArchInfo *arch;
bool cfi;
};
@@ -54,7 +54,7 @@
//=============================================================================
static bool Start(const Options &options) {
@ -1133,17 +795,7 @@ diff --git a/src/tools/mac/dump_syms/dump_syms_tool.mm b/src/tools/mac/dump_syms
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",
@@ -81,17 +81,17 @@
else
fprintf(stderr, "unrecognized cpu type 0x%x, subtype 0x%x\n",
arch->cputype, arch->cpusubtype);
}
return false;
@@ -86,7 +86,7 @@
}
}
@ -1152,8 +804,3 @@ diff --git a/src/tools/mac/dump_syms/dump_syms_tool.mm b/src/tools/mac/dump_syms
}
//=============================================================================
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] [-c] <Mach-o file>\n",
argv[0]);
fprintf(stderr, "\t-a: Architecture type [default: native, or whatever is\n");

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,59 +1,37 @@
# HG changeset patch
# Parent 4851b0fa0c4c0983670d137ea960977f627db88c
# User Ted Mielczarek <ted.mielczarek@gmail.com>
# Date 1360255134 18000
# Node ID 74d4bb64dc84b4bc73939af06d804b71425e51d4
# Parent 97572beba4ad7fa4f76c3d1871d2001839a65b32
Minor Android fixup for symbol dumping code
R=ted
diff --git a/src/common/dwarf_cu_to_module.cc b/src/common/dwarf_cu_to_module.cc
--- a/src/common/dwarf_cu_to_module.cc
+++ b/src/common/dwarf_cu_to_module.cc
@@ -34,17 +34,19 @@
// For <inttypes.h> PRI* macros, before anything else might #include it.
#ifndef __STDC_FORMAT_MACROS
#define __STDC_FORMAT_MACROS
#endif /* __STDC_FORMAT_MACROS */
@@ -39,7 +39,9 @@
#include "common/dwarf_cu_to_module.h"
#include <assert.h>
-#include <cxxabi.h>
+#if !defined(ANDROID)
+# include <cxxabi.h>
+#if !defined(__ANDROID__)
#include <cxxabi.h>
+#endif
#include <inttypes.h>
#include <stdio.h>
#include <algorithm>
#include <set>
#include <utility>
#include "common/dwarf_line_to_module.h"
@@ -308,17 +310,20 @@
enum DwarfAttribute attr,
enum DwarfForm form,
const string &data) {
switch (attr) {
case dwarf2reader::DW_AT_name:
@@ -313,7 +315,10 @@
name_attribute_ = AddStringToPool(data);
break;
case dwarf2reader::DW_AT_MIPS_linkage_name: {
- char* demangled = abi::__cxa_demangle(data.c_str(), NULL, NULL, NULL);
+ char* demangled = NULL;
+# if !defined(ANDROID)
+#if !defined(__ANDROID__)
+ demangled = abi::__cxa_demangle(data.c_str(), NULL, NULL, NULL);
+# endif
+#endif
if (demangled) {
demangled_name_ = AddStringToPool(demangled);
free(reinterpret_cast<void*>(demangled));
}
break;
}
default: break;
}
@@ -778,19 +783,19 @@
// DWARF spec certainly makes no such promises.
//
// So treat the functions and lines as peers, and take the trouble
// to compute their ranges' intersections precisely. In any case,
// the hair here is a constant factor for performance; the
@@ -783,9 +788,9 @@
// complexity from here on out is linear.
// Put both our functions and lines in order by address.
@ -66,31 +44,3 @@ diff --git a/src/common/dwarf_cu_to_module.cc b/src/common/dwarf_cu_to_module.cc
// The last line that we used any piece of. We use this only for
// generating warnings.
const Module::Line *last_line_used = NULL;
// The last function and line we warned about --- so we can avoid
// doing so more than once.
const Module::Function *last_function_cited = NULL;
diff --git a/src/common/linux/dump_symbols.cc b/src/common/linux/dump_symbols.cc
--- a/src/common/linux/dump_symbols.cc
+++ b/src/common/linux/dump_symbols.cc
@@ -112,18 +112,17 @@
// MmapWrapper
//
// Wrapper class to make sure mapped regions are unmapped.
//
class MmapWrapper {
public:
MmapWrapper() : is_set_(false) {}
~MmapWrapper() {
- if (base_ != NULL) {
- assert(size_ > 0);
+ if (is_set_ && base_ != NULL && size_ > 0) {
munmap(base_, size_);
}
}
void set(void *mapped_address, size_t mapped_size) {
is_set_ = true;
base_ = mapped_address;
size_ = mapped_size;
}

View File

@ -1,160 +0,0 @@
# HG changeset patch
# Parent 5f4e1d84f6c317595060aa200adb5aef7e53079d
Provide a ReadSymbolData API for Mac dump_syms
diff --git a/src/common/mac/dump_syms.h b/src/common/mac/dump_syms.h
--- a/src/common/mac/dump_syms.h
+++ b/src/common/mac/dump_syms.h
@@ -111,16 +111,21 @@
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);
+ // As above, but simply return the debugging information in module
+ // instead of writing it to a stream. The caller owns the resulting
+ // module object and must delete it when finished.
+ bool ReadSymbolData(Module** module);
+
private:
// Used internally.
class DumperLineToModule;
class LoadCommandDumper;
// Return an identifier string for the file this DumpSymbols is dumping.
std::string Identifier();
diff --git a/src/common/mac/dump_syms.mm b/src/common/mac/dump_syms.mm
--- a/src/common/mac/dump_syms.mm
+++ b/src/common/mac/dump_syms.mm
@@ -48,34 +48,37 @@
#include "common/dwarf/dwarf2reader.h"
#include "common/dwarf_cfi_to_module.h"
#include "common/dwarf_cu_to_module.h"
#include "common/dwarf_line_to_module.h"
#include "common/mac/file_id.h"
#include "common/mac/arch_utilities.h"
#include "common/mac/macho_reader.h"
#include "common/module.h"
+#include "common/scoped_ptr.h"
#include "common/stabs_reader.h"
#include "common/stabs_to_module.h"
#include "common/symbol_data.h"
+#include "common/unique_string.h"
#ifndef CPU_TYPE_ARM
#define CPU_TYPE_ARM (static_cast<cpu_type_t>(12))
#endif // CPU_TYPE_ARM
using dwarf2reader::ByteReader;
using google_breakpad::DwarfCUToModule;
using google_breakpad::DwarfLineToModule;
using google_breakpad::FileID;
using google_breakpad::mach_o::FatReader;
using google_breakpad::mach_o::Section;
using google_breakpad::mach_o::Segment;
using google_breakpad::Module;
using google_breakpad::StabsReader;
using google_breakpad::StabsToModule;
+using google_breakpad::scoped_ptr;
using std::make_pair;
using std::pair;
using std::string;
using std::vector;
namespace google_breakpad {
bool DumpSymbols::Read(NSString *filename) {
@@ -305,17 +308,17 @@
}
bool DumpSymbols::ReadCFI(google_breakpad::Module *module,
const mach_o::Reader &macho_reader,
const mach_o::Section &section,
bool eh_frame) const {
// Find the appropriate set of register names for this file's
// architecture.
- vector<string> register_names;
+ vector<const UniqueString*> register_names;
switch (macho_reader.cpu_type()) {
case CPU_TYPE_X86:
register_names = DwarfCFIToModule::RegisterNames::I386();
break;
case CPU_TYPE_X86_64:
register_names = DwarfCFIToModule::RegisterNames::X86_64();
break;
case CPU_TYPE_ARM:
@@ -434,17 +437,17 @@
true,
&stabs_to_module);
if (!stabs_reader.Process())
return false;
stabs_to_module.Finalize();
return true;
}
-bool DumpSymbols::WriteSymbolFile(std::ostream &stream) {
+bool DumpSymbols::ReadSymbolData(Module** out_module) {
// Select an object file, if SetArchitecture hasn't been called to set one
// explicitly.
if (!selected_object_file_) {
// If there's only one architecture, that's the one.
if (object_files_.size() == 1)
selected_object_file_ = &object_files_[0];
else {
// Look for an object file whose architecture matches our own.
@@ -485,30 +488,47 @@
// Choose an identifier string, to appear in the MODULE record.
string identifier = Identifier();
if (identifier.empty())
return false;
identifier += "0";
// Create a module to hold the debugging information.
- Module module([module_name UTF8String], "mac", selected_arch_name,
- identifier);
+ scoped_ptr<Module> module = new Module([module_name UTF8String],
+ "mac",
+ selected_arch_name,
+ identifier);
// Parse the selected object file.
mach_o::Reader::Reporter reporter(selected_object_name_);
mach_o::Reader reader(&reporter);
if (!reader.Read(reinterpret_cast<const uint8_t *>([contents_ bytes])
+ selected_object_file_->offset,
selected_object_file_->size,
selected_object_file_->cputype,
selected_object_file_->cpusubtype))
return false;
// Walk its load commands, and deal with whatever is there.
- LoadCommandDumper load_command_dumper(*this, &module, reader, symbol_data_);
+ LoadCommandDumper load_command_dumper(*this, module.get(), reader,
+ symbol_data_);
if (!reader.WalkLoadCommands(&load_command_dumper))
return false;
- return module.Write(stream, symbol_data_);
+ *out_module = module.release();
+
+ return true;
+}
+
+bool DumpSymbols::WriteSymbolFile(std::ostream &stream, bool cfi) {
+ Module* module = NULL;
+
+ if (ReadSymbolData(&module) && module) {
+ bool res = module->Write(stream, cfi);
+ delete module;
+ return res;
+ }
+
+ return false;
}
} // namespace google_breakpad

View File

@ -0,0 +1,97 @@
# HG changeset patch
# User Ted Mielczarek <ted.mielczarek@gmail.com>
# Date 1360255134 18000
# Node ID 47146439a92d83b7add8af766ec53eaf41c10ec2
# Parent 74d4bb64dc84b4bc73939af06d804b71425e51d4
Provide a ReadSymbolData API for Mac dump_syms
R=mark at https://breakpad.appspot.com/522002/
diff --git a/src/common/mac/dump_syms.h b/src/common/mac/dump_syms.h
--- a/src/common/mac/dump_syms.h
+++ b/src/common/mac/dump_syms.h
@@ -116,6 +116,11 @@
// return false.
bool WriteSymbolFile(std::ostream &stream);
+ // As above, but simply return the debugging information in module
+ // instead of writing it to a stream. The caller owns the resulting
+ // module object and must delete it when finished.
+ bool ReadSymbolData(Module** module);
+
private:
// Used internally.
class DumperLineToModule;
diff --git a/src/common/mac/dump_syms.mm b/src/common/mac/dump_syms.mm
--- a/src/common/mac/dump_syms.mm
+++ b/src/common/mac/dump_syms.mm
@@ -53,9 +53,11 @@
#include "common/mac/arch_utilities.h"
#include "common/mac/macho_reader.h"
#include "common/module.h"
+#include "common/scoped_ptr.h"
#include "common/stabs_reader.h"
#include "common/stabs_to_module.h"
#include "common/symbol_data.h"
+#include "common/unique_string.h"
#ifndef CPU_TYPE_ARM
#define CPU_TYPE_ARM (static_cast<cpu_type_t>(12))
@@ -71,6 +73,7 @@
using google_breakpad::Module;
using google_breakpad::StabsReader;
using google_breakpad::StabsToModule;
+using google_breakpad::scoped_ptr;
using std::make_pair;
using std::pair;
using std::string;
@@ -439,7 +442,7 @@
return true;
}
-bool DumpSymbols::WriteSymbolFile(std::ostream &stream) {
+bool DumpSymbols::ReadSymbolData(Module** out_module) {
// Select an object file, if SetArchitecture hasn't been called to set one
// explicitly.
if (!selected_object_file_) {
@@ -490,8 +493,10 @@
identifier += "0";
// Create a module to hold the debugging information.
- Module module([module_name UTF8String], "mac", selected_arch_name,
- identifier);
+ scoped_ptr<Module> module(new Module([module_name UTF8String],
+ "mac",
+ selected_arch_name,
+ identifier));
// Parse the selected object file.
mach_o::Reader::Reporter reporter(selected_object_name_);
@@ -504,11 +509,26 @@
return false;
// Walk its load commands, and deal with whatever is there.
- LoadCommandDumper load_command_dumper(*this, &module, reader, symbol_data_);
+ LoadCommandDumper load_command_dumper(*this, module.get(), reader,
+ symbol_data_);
if (!reader.WalkLoadCommands(&load_command_dumper))
return false;
- return module.Write(stream, symbol_data_);
+ *out_module = module.release();
+
+ return true;
+}
+
+bool DumpSymbols::WriteSymbolFile(std::ostream &stream) {
+ Module* module = NULL;
+
+ if (ReadSymbolData(&module) && module) {
+ bool res = module->Write(stream, symbol_data_);
+ delete module;
+ return res;
+ }
+
+ return false;
}
} // namespace google_breakpad

View File

@ -2,10 +2,10 @@ Path: ../google-breakpad-svn
URL: https://google-breakpad.googlecode.com/svn/trunk
Repository Root: https://google-breakpad.googlecode.com/svn
Repository UUID: 4c0a9323-5329-0410-9bdc-e9ce6186880e
Revision: 1106
Revision: 1112
Node Kind: directory
Schedule: normal
Last Changed Author: ted.mielczarek@gmail.com
Last Changed Rev: 1106
Last Changed Date: 2013-01-23 13:01:28 -0500 (Wed, 23 Jan 2013)
Last Changed Rev: 1110
Last Changed Date: 2013-02-01 14:20:34 -0500 (Fri, 01 Feb 2013)

View File

@ -105,6 +105,9 @@
// BreakpadController.
- (void)setUploadingEnabled:(BOOL)enabled;
// Check if there is currently a crash report to upload.
- (void)hasReportToUpload:(void(^)(BOOL))callback;
@end
#endif // CLIENT_IOS_HANDLER_IOS_BREAKPAD_CONTROLLER_H_

View File

@ -228,6 +228,13 @@ NSString* GetPlatform() {
});
}
- (void)hasReportToUpload:(void(^)(BOOL))callback {
NSAssert(started_, @"The controller must be started before "
"hasReportToUpload is called");
dispatch_async(queue_, ^{
callback(breakpadRef_ && BreakpadHasCrashReportToUpload(breakpadRef_));
});
}
#pragma mark -

View File

@ -889,7 +889,7 @@ TEST(ExceptionHandlerTest, ExternalDumper) {
const ssize_t n = HANDLE_EINTR(recvmsg(fds[0], &msg, 0));
ASSERT_EQ(static_cast<ssize_t>(kCrashContextSize), n);
ASSERT_EQ(kControlMsgSize, msg.msg_controllen);
ASSERT_EQ(0, msg.msg_flags);
ASSERT_EQ(static_cast<typeof(msg.msg_flags)>(0), msg.msg_flags);
ASSERT_EQ(0, close(fds[0]));
pid_t crashing_pid = -1;

View File

@ -1144,11 +1144,10 @@ class MinidumpWriter {
debug.get()->ldbase = (void*)debug_entry.r_ldbase;
debug.get()->dynamic = dynamic;
char* dso_debug_data = new char[dynamic_length];
dumper_->CopyFromProcess(dso_debug_data, GetCrashThread(), dynamic,
wasteful_vector<char> dso_debug_data(dumper_->allocator(), dynamic_length);
dumper_->CopyFromProcess(&dso_debug_data[0], GetCrashThread(), dynamic,
dynamic_length);
debug.CopyIndexAfterObject(0, dso_debug_data, dynamic_length);
delete[] dso_debug_data;
debug.CopyIndexAfterObject(0, &dso_debug_data[0], dynamic_length);
return true;
}

View File

@ -36,11 +36,13 @@ TEST(AndroidUContext, GRegsOffset) {
#ifdef __arm__
// There is no gregs[] array on ARM, so compare to the offset of
// first register fields, since they're stored in order.
ASSERT_EQ(MCONTEXT_GREGS_OFFSET, offsetof(ucontext_t,uc_mcontext.arm_r0));
ASSERT_EQ(static_cast<size_t>(MCONTEXT_GREGS_OFFSET),
offsetof(ucontext_t,uc_mcontext.arm_r0));
#elif defined(__i386__)
ASSERT_EQ(MCONTEXT_GREGS_OFFSET, offsetof(ucontext_t,uc_mcontext.gregs));
ASSERT_EQ(static_cast<size_t>(MCONTEXT_GREGS_OFFSET),
offsetof(ucontext_t,uc_mcontext.gregs));
#define CHECK_REG(x) \
ASSERT_EQ(MCONTEXT_##x##_OFFSET, \
ASSERT_EQ(static_cast<size_t>(MCONTEXT_##x##_OFFSET), \
offsetof(ucontext_t,uc_mcontext.gregs[REG_##x]))
CHECK_REG(GS);
CHECK_REG(FS);
@ -62,15 +64,18 @@ TEST(AndroidUContext, GRegsOffset) {
CHECK_REG(UESP);
CHECK_REG(SS);
ASSERT_EQ(UCONTEXT_FPREGS_OFFSET, offsetof(ucontext_t,uc_mcontext.fpregs));
ASSERT_EQ(static_cast<size_t>(UCONTEXT_FPREGS_OFFSET),
offsetof(ucontext_t,uc_mcontext.fpregs));
ASSERT_EQ(UCONTEXT_FPREGS_MEM_OFFSET,
ASSERT_EQ(static_cast<size_t>(UCONTEXT_FPREGS_MEM_OFFSET),
offsetof(ucontext_t,__fpregs_mem));
#else
ASSERT_EQ(MCONTEXT_GREGS_OFFSET, offsetof(ucontext_t,uc_mcontext.gregs));
ASSERT_EQ(static_cast<size_t>(MCONTEXT_GREGS_OFFSET),
offsetof(ucontext_t,uc_mcontext.gregs));
#endif
}
TEST(AndroidUContext, SigmakOffset) {
ASSERT_EQ(UCONTEXT_SIGMASK_OFFSET, offsetof(ucontext_t,uc_sigmask));
ASSERT_EQ(static_cast<size_t>(UCONTEXT_SIGMASK_OFFSET),
offsetof(ucontext_t,uc_sigmask));
}

View File

@ -57,7 +57,7 @@ char* mkdtemp(char* path) {
const size_t kSuffixLen = strlen(kSuffix);
char* path_end = path + strlen(path);
if (path_end - path < kSuffixLen ||
if (static_cast<size_t>(path_end - path) < kSuffixLen ||
memcmp(path_end - kSuffixLen, kSuffix, kSuffixLen) != 0) {
errno = EINVAL;
return NULL;

View File

@ -43,11 +43,11 @@ namespace google_breakpad {
using std::ostringstream;
vector<const UniqueString*> DwarfCFIToModule::RegisterNames::MakeVector(
const char * const *strings,
const char* const* strings,
size_t size) {
vector<const UniqueString*> names(size, NULL);
for (size_t i = 0; i < size; i++) {
names[i] = toUniqueString(strings[i]);
for (size_t i = 0; i < size; ++i) {
names[i] = ToUniqueString(strings[i]);
}
return names;
@ -154,7 +154,7 @@ const UniqueString* DwarfCFIToModule::RegisterName(int i) {
reporter_->UnnamedRegister(entry_offset_, reg);
char buf[30];
sprintf(buf, "unnamed_register%u", reg);
return toUniqueString(buf);
return ToUniqueString(buf);
}
void DwarfCFIToModule::Record(Module::Address address, int reg,
@ -244,7 +244,7 @@ void DwarfCFIToModule::Reporter::UndefinedNotSupported(
"the call frame entry at offset 0x%zx sets the rule for "
"register '%s' to 'undefined', but the Breakpad symbol file format"
" cannot express this\n",
file_.c_str(), section_.c_str(), offset, fromUniqueString(reg));
file_.c_str(), section_.c_str(), offset, FromUniqueString(reg));
}
void DwarfCFIToModule::Reporter::ExpressionsNotSupported(
@ -255,7 +255,7 @@ void DwarfCFIToModule::Reporter::ExpressionsNotSupported(
" describe how to recover register '%s', "
" but this translator cannot yet translate DWARF expressions to"
" Breakpad postfix expressions\n",
file_.c_str(), section_.c_str(), offset, fromUniqueString(reg));
file_.c_str(), section_.c_str(), offset, FromUniqueString(reg));
}
} // namespace google_breakpad

View File

@ -42,6 +42,11 @@ using std::vector;
using google_breakpad::Module;
using google_breakpad::DwarfCFIToModule;
using google_breakpad::ToUniqueString;
using google_breakpad::UniqueString;
using google_breakpad::ustr__ZDcfa;
using google_breakpad::ustr__ZDra;
using google_breakpad::ustr__empty;
using testing::ContainerEq;
using testing::Test;
using testing::_;
@ -61,16 +66,16 @@ struct DwarfCFIToModuleFixture {
: module("module name", "module os", "module arch", "module id"),
reporter("reporter file", "reporter section"),
handler(&module, register_names, &reporter) {
register_names.push_back(toUniqueString("reg0"));
register_names.push_back(toUniqueString("reg1"));
register_names.push_back(toUniqueString("reg2"));
register_names.push_back(toUniqueString("reg3"));
register_names.push_back(toUniqueString("reg4"));
register_names.push_back(toUniqueString("reg5"));
register_names.push_back(toUniqueString("reg6"));
register_names.push_back(toUniqueString("reg7"));
register_names.push_back(toUniqueString("sp"));
register_names.push_back(toUniqueString("pc"));
register_names.push_back(ToUniqueString("reg0"));
register_names.push_back(ToUniqueString("reg1"));
register_names.push_back(ToUniqueString("reg2"));
register_names.push_back(ToUniqueString("reg3"));
register_names.push_back(ToUniqueString("reg4"));
register_names.push_back(ToUniqueString("reg5"));
register_names.push_back(ToUniqueString("reg6"));
register_names.push_back(ToUniqueString("reg7"));
register_names.push_back(ToUniqueString("sp"));
register_names.push_back(ToUniqueString("pc"));
register_names.push_back(ustr__empty());
EXPECT_CALL(reporter, UnnamedRegister(_, _)).Times(0);
@ -134,7 +139,7 @@ struct RuleFixture: public DwarfCFIToModuleFixture {
class Rule: public RuleFixture, public Test { };
TEST_F(Rule, UndefinedRule) {
EXPECT_CALL(reporter, UndefinedNotSupported(_, toUniqueString("reg7")));
EXPECT_CALL(reporter, UndefinedNotSupported(_, ToUniqueString("reg7")));
StartEntry();
ASSERT_TRUE(handler.UndefinedRule(entry_address, 7));
ASSERT_TRUE(handler.End());
@ -146,7 +151,7 @@ TEST_F(Rule, UndefinedRule) {
TEST_F(Rule, RegisterWithEmptyName) {
EXPECT_CALL(reporter, UnnamedRegister(_, 10));
EXPECT_CALL(reporter,
UndefinedNotSupported(_, toUniqueString("unnamed_register10")));
UndefinedNotSupported(_, ToUniqueString("unnamed_register10")));
StartEntry();
ASSERT_TRUE(handler.UndefinedRule(entry_address, 10));
ASSERT_TRUE(handler.End());
@ -161,7 +166,7 @@ TEST_F(Rule, SameValueRule) {
ASSERT_TRUE(handler.End());
CheckEntry();
Module::RuleMap expected_initial;
const UniqueString* reg6 = toUniqueString("reg6");
const UniqueString* reg6 = ToUniqueString("reg6");
expected_initial[reg6] = Module::Expr(reg6, 0, false);
EXPECT_THAT(entries[0]->initial_rules, ContainerEq(expected_initial));
EXPECT_EQ(0U, entries[0]->rule_changes.size());
@ -190,7 +195,7 @@ TEST_F(Rule, OffsetRuleNegative) {
EXPECT_EQ(0U, entries[0]->initial_rules.size());
Module::RuleChangeMap expected_changes;
expected_changes[entry_address + 1][ustr__ZDcfa()] =
Module::Expr(toUniqueString("reg4"), -34530721, true);
Module::Expr(ToUniqueString("reg4"), -34530721, true);
EXPECT_THAT(entries[0]->rule_changes, ContainerEq(expected_changes));
}
@ -206,7 +211,7 @@ TEST_F(Rule, ValOffsetRule) {
EXPECT_EQ(0U, entries[0]->initial_rules.size());
Module::RuleChangeMap expected_changes;
expected_changes[entry_address + 0x5ab7][ustr__ZDcfa()] =
Module::Expr(toUniqueString("unnamed_register11"), 61812979, false);
Module::Expr(ToUniqueString("unnamed_register11"), 61812979, false);
EXPECT_THAT(entries[0]->rule_changes, ContainerEq(expected_changes));
}
@ -217,13 +222,13 @@ TEST_F(Rule, RegisterRule) {
CheckEntry();
Module::RuleMap expected_initial;
expected_initial[ustr__ZDra()] =
Module::Expr(toUniqueString("reg3"), 0, false);
Module::Expr(ToUniqueString("reg3"), 0, false);
EXPECT_THAT(entries[0]->initial_rules, ContainerEq(expected_initial));
EXPECT_EQ(0U, entries[0]->rule_changes.size());
}
TEST_F(Rule, ExpressionRule) {
EXPECT_CALL(reporter, ExpressionsNotSupported(_, toUniqueString("reg2")));
EXPECT_CALL(reporter, ExpressionsNotSupported(_, ToUniqueString("reg2")));
StartEntry();
ASSERT_TRUE(handler.ExpressionRule(entry_address + 0xf326, 2,
"it takes two to tango"));
@ -234,7 +239,7 @@ TEST_F(Rule, ExpressionRule) {
}
TEST_F(Rule, ValExpressionRule) {
EXPECT_CALL(reporter, ExpressionsNotSupported(_, toUniqueString("reg0")));
EXPECT_CALL(reporter, ExpressionsNotSupported(_, ToUniqueString("reg0")));
StartEntry();
ASSERT_TRUE(handler.ValExpressionRule(entry_address + 0x6367, 0,
"bit off more than he could chew"));
@ -252,9 +257,9 @@ TEST_F(Rule, DefaultReturnAddressRule) {
CheckEntry();
Module::RuleMap expected_initial;
expected_initial[ustr__ZDra()] =
Module::Expr(toUniqueString("reg2"), 0, false);
expected_initial[toUniqueString("reg0")] =
Module::Expr(toUniqueString("reg1"), 0, false);
Module::Expr(ToUniqueString("reg2"), 0, false);
expected_initial[ToUniqueString("reg0")] =
Module::Expr(ToUniqueString("reg1"), 0, false);
EXPECT_THAT(entries[0]->initial_rules, ContainerEq(expected_initial));
EXPECT_EQ(0U, entries[0]->rule_changes.size());
}
@ -267,7 +272,7 @@ TEST_F(Rule, DefaultReturnAddressRuleOverride) {
CheckEntry();
Module::RuleMap expected_initial;
expected_initial[ustr__ZDra()] =
Module::Expr(toUniqueString("reg1"), 0, false);
Module::Expr(ToUniqueString("reg1"), 0, false);
EXPECT_THAT(entries[0]->initial_rules, ContainerEq(expected_initial));
EXPECT_EQ(0U, entries[0]->rule_changes.size());
}
@ -280,39 +285,39 @@ TEST_F(Rule, DefaultReturnAddressRuleLater) {
CheckEntry();
Module::RuleMap expected_initial;
expected_initial[ustr__ZDra()] =
Module::Expr(toUniqueString("reg2"), 0, false);
Module::Expr(ToUniqueString("reg2"), 0, false);
EXPECT_THAT(entries[0]->initial_rules, ContainerEq(expected_initial));
Module::RuleChangeMap expected_changes;
expected_changes[entry_address + 1][ustr__ZDra()] =
Module::Expr(toUniqueString("reg1"), 0, false);
Module::Expr(ToUniqueString("reg1"), 0, false);
EXPECT_THAT(entries[0]->rule_changes, ContainerEq(expected_changes));
}
TEST(RegisterNames, I386) {
vector<const UniqueString*> names = DwarfCFIToModule::RegisterNames::I386();
EXPECT_EQ(toUniqueString("$eax"), names[0]);
EXPECT_EQ(toUniqueString("$ecx"), names[1]);
EXPECT_EQ(toUniqueString("$esp"), names[4]);
EXPECT_EQ(toUniqueString("$eip"), names[8]);
EXPECT_EQ(ToUniqueString("$eax"), names[0]);
EXPECT_EQ(ToUniqueString("$ecx"), names[1]);
EXPECT_EQ(ToUniqueString("$esp"), names[4]);
EXPECT_EQ(ToUniqueString("$eip"), names[8]);
}
TEST(RegisterNames, ARM) {
vector<const UniqueString*> names = DwarfCFIToModule::RegisterNames::ARM();
EXPECT_EQ(toUniqueString("r0"), names[0]);
EXPECT_EQ(toUniqueString("r10"), names[10]);
EXPECT_EQ(toUniqueString("sp"), names[13]);
EXPECT_EQ(toUniqueString("lr"), names[14]);
EXPECT_EQ(toUniqueString("pc"), names[15]);
EXPECT_EQ(ToUniqueString("r0"), names[0]);
EXPECT_EQ(ToUniqueString("r10"), names[10]);
EXPECT_EQ(ToUniqueString("sp"), names[13]);
EXPECT_EQ(ToUniqueString("lr"), names[14]);
EXPECT_EQ(ToUniqueString("pc"), names[15]);
}
TEST(RegisterNames, X86_64) {
vector<const UniqueString*> names = DwarfCFIToModule::RegisterNames::X86_64();
EXPECT_EQ(toUniqueString("$rax"), names[0]);
EXPECT_EQ(toUniqueString("$rdx"), names[1]);
EXPECT_EQ(toUniqueString("$rbp"), names[6]);
EXPECT_EQ(toUniqueString("$rsp"), names[7]);
EXPECT_EQ(toUniqueString("$rip"), names[16]);
EXPECT_EQ(ToUniqueString("$rax"), names[0]);
EXPECT_EQ(ToUniqueString("$rdx"), names[1]);
EXPECT_EQ(ToUniqueString("$rbp"), names[6]);
EXPECT_EQ(ToUniqueString("$rsp"), names[7]);
EXPECT_EQ(ToUniqueString("$rip"), names[16]);
}

View File

@ -39,8 +39,8 @@
#include "common/dwarf_cu_to_module.h"
#include <assert.h>
#if !defined(ANDROID)
# include <cxxabi.h>
#if !defined(__ANDROID__)
#include <cxxabi.h>
#endif
#include <inttypes.h>
#include <stdio.h>
@ -316,9 +316,9 @@ void DwarfCUToModule::GenericDIEHandler::ProcessAttributeString(
break;
case dwarf2reader::DW_AT_MIPS_linkage_name: {
char* demangled = NULL;
# if !defined(ANDROID)
#if !defined(__ANDROID__)
demangled = abi::__cxa_demangle(data.c_str(), NULL, NULL, NULL);
# endif
#endif
if (demangled) {
demangled_name_ = AddStringToPool(demangled);
free(reinterpret_cast<void*>(demangled));

View File

@ -81,6 +81,7 @@ using google_breakpad::GetOffset;
using google_breakpad::IsValidElf;
using google_breakpad::Module;
using google_breakpad::StabsToModule;
using google_breakpad::UniqueString;
using google_breakpad::scoped_ptr;
//
@ -117,7 +118,8 @@ class MmapWrapper {
public:
MmapWrapper() : is_set_(false) {}
~MmapWrapper() {
if (is_set_ && base_ != NULL && size_ > 0) {
if (base_ != NULL) {
assert(size_ > 0);
munmap(base_, size_);
}
}

View File

@ -116,6 +116,11 @@ class DumpSymbols {
// return false.
bool WriteSymbolFile(std::ostream &stream);
// As above, but simply return the debugging information in module
// instead of writing it to a stream. The caller owns the resulting
// module object and must delete it when finished.
bool ReadSymbolData(Module** module);
private:
// Used internally.
class DumperLineToModule;

View File

@ -53,9 +53,11 @@
#include "common/mac/arch_utilities.h"
#include "common/mac/macho_reader.h"
#include "common/module.h"
#include "common/scoped_ptr.h"
#include "common/stabs_reader.h"
#include "common/stabs_to_module.h"
#include "common/symbol_data.h"
#include "common/unique_string.h"
#ifndef CPU_TYPE_ARM
#define CPU_TYPE_ARM (static_cast<cpu_type_t>(12))
@ -71,6 +73,7 @@ using google_breakpad::mach_o::Segment;
using google_breakpad::Module;
using google_breakpad::StabsReader;
using google_breakpad::StabsToModule;
using google_breakpad::scoped_ptr;
using std::make_pair;
using std::pair;
using std::string;
@ -439,7 +442,7 @@ bool DumpSymbols::LoadCommandDumper::SymtabCommand(const ByteBuffer &entries,
return true;
}
bool DumpSymbols::WriteSymbolFile(std::ostream &stream) {
bool DumpSymbols::ReadSymbolData(Module** out_module) {
// Select an object file, if SetArchitecture hasn't been called to set one
// explicitly.
if (!selected_object_file_) {
@ -490,8 +493,10 @@ 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,
identifier);
scoped_ptr<Module> module(new Module([module_name UTF8String],
"mac",
selected_arch_name,
identifier));
// Parse the selected object file.
mach_o::Reader::Reporter reporter(selected_object_name_);
@ -504,11 +509,26 @@ bool DumpSymbols::WriteSymbolFile(std::ostream &stream) {
return false;
// Walk its load commands, and deal with whatever is there.
LoadCommandDumper load_command_dumper(*this, &module, reader, symbol_data_);
LoadCommandDumper load_command_dumper(*this, module.get(), reader,
symbol_data_);
if (!reader.WalkLoadCommands(&load_command_dumper))
return false;
return module.Write(stream, symbol_data_);
*out_module = module.release();
return true;
}
bool DumpSymbols::WriteSymbolFile(std::ostream &stream) {
Module* module = NULL;
if (ReadSymbolData(&module) && module) {
bool res = module->Write(stream, symbol_data_);
delete module;
return res;
}
return false;
}
} // namespace google_breakpad

View File

@ -38,6 +38,7 @@
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <iostream>
#include <utility>
@ -275,11 +276,25 @@ std::ostream& operator<<(std::ostream& stream, const Module::Expr& expr) {
}
bool Module::WriteRuleMap(const RuleMap &rule_map, std::ostream &stream) {
// Visit the register rules in alphabetical order. Because
// rule_map has the elements in some arbitrary order,
// get the names out into a vector, sort them, and visit in
// sorted order.
std::vector<const UniqueString*> rr_names;
for (RuleMap::const_iterator it = rule_map.begin();
it != rule_map.end(); ++it) {
if (it != rule_map.begin())
stream << ' ';
stream << it->first << ": " << it->second;
rr_names.push_back(it->first);
}
std::sort(rr_names.begin(), rr_names.end(), LessThan_UniqueString);
// Now visit the register rules in alphabetical order.
for (std::vector<const UniqueString*>::const_iterator name = rr_names.begin();
name != rr_names.end();
++name) {
if (name != rr_names.begin())
stream << " ";
stream << FromUniqueString(*name) << ": " << rule_map.find(*name)->second;
}
return stream.good();
}

View File

@ -1,358 +0,0 @@
// Copyright (c) 2011 Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Original author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
// module.cc: Implement google_breakpad::Module. See module.h.
#include "common/module.h"
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <utility>
namespace google_breakpad {
using std::dec;
using std::endl;
using std::hex;
Module::Module(const string &name, const string &os,
const string &architecture, const string &id) :
name_(name),
os_(os),
architecture_(architecture),
id_(id),
load_address_(0) { }
Module::~Module() {
for (FileByNameMap::iterator it = files_.begin(); it != files_.end(); ++it)
delete it->second;
for (FunctionSet::iterator it = functions_.begin();
it != functions_.end(); ++it) {
delete *it;
}
for (StackFrameEntrySet::iterator it = stack_frame_entries_.begin();
it != stack_frame_entries_.end(); ++it) {
delete *it;
}
for (ExternSet::iterator it = externs_.begin(); it != externs_.end(); ++it)
delete *it;
}
void Module::SetLoadAddress(Address address) {
load_address_ = address;
}
void Module::AddFunction(Function *function) {
// FUNC lines must not hold an empty name, so catch the problem early if
// callers try to add one.
assert(!function->name.empty());
std::pair<FunctionSet::iterator,bool> ret = functions_.insert(function);
if (!ret.second) {
// Free the duplicate that was not inserted because this Module
// now owns it.
delete function;
}
}
void Module::AddFunctions(vector<Function *>::iterator begin,
vector<Function *>::iterator end) {
for (vector<Function *>::iterator it = begin; it != end; ++it)
AddFunction(*it);
}
void Module::AddStackFrameEntry(StackFrameEntry* stack_frame_entry) {
std::pair<StackFrameEntrySet::iterator,bool> ret =
stack_frame_entries_.insert(stack_frame_entry);
if (!ret.second) {
// Free the duplicate that was not inserted because this Module
// now owns it.
delete stack_frame_entry;
}
}
void Module::AddExtern(Extern *ext) {
std::pair<ExternSet::iterator,bool> ret = externs_.insert(ext);
if (!ret.second) {
// Free the duplicate that was not inserted because this Module
// now owns it.
delete ext;
}
}
void Module::GetFunctions(vector<Function *> *vec,
vector<Function *>::iterator i) {
vec->insert(i, functions_.begin(), functions_.end());
}
template<typename T>
bool EntryContainsAddress(T entry, Module::Address address) {
return entry->address <= address && address < entry->address + entry->size;
}
Module::Function* Module::FindFunctionByAddress(Address address) {
Function search;
search.address = address;
// Ensure that name always sorts higher than the function name,
// so that upper_bound always returns the function just after
// the function containing this address.
search.name = "\xFF";
FunctionSet::iterator it = functions_.upper_bound(&search);
if (it == functions_.begin())
return NULL;
it--;
if (EntryContainsAddress(*it, address))
return *it;
return NULL;
}
void Module::GetExterns(vector<Extern *> *vec,
vector<Extern *>::iterator i) {
vec->insert(i, externs_.begin(), externs_.end());
}
Module::Extern* Module::FindExternByAddress(Address address) {
Extern search;
search.address = address;
ExternSet::iterator it = externs_.upper_bound(&search);
if (it == externs_.begin())
return NULL;
it--;
if ((*it)->address > address)
return NULL;
return *it;
}
Module::File *Module::FindFile(const string &name) {
// A tricky bit here. The key of each map entry needs to be a
// pointer to the entry's File's name string. This means that we
// can't do the initial lookup with any operation that would create
// an empty entry for us if the name isn't found (like, say,
// operator[] or insert do), because such a created entry's key will
// be a pointer the string passed as our argument. Since the key of
// a map's value type is const, we can't fix it up once we've
// created our file. lower_bound does the lookup without doing an
// insertion, and returns a good hint iterator to pass to insert.
// Our "destiny" is where we belong, whether we're there or not now.
FileByNameMap::iterator destiny = files_.lower_bound(&name);
if (destiny == files_.end()
|| *destiny->first != name) { // Repeated string comparison, boo hoo.
File *file = new File;
file->name = name;
file->source_id = -1;
destiny = files_.insert(destiny,
FileByNameMap::value_type(&file->name, file));
}
return destiny->second;
}
Module::File *Module::FindFile(const char *name) {
string name_string = name;
return FindFile(name_string);
}
Module::File *Module::FindExistingFile(const string &name) {
FileByNameMap::iterator it = files_.find(&name);
return (it == files_.end()) ? NULL : it->second;
}
void Module::GetFiles(vector<File *> *vec) {
vec->clear();
for (FileByNameMap::iterator it = files_.begin(); it != files_.end(); ++it)
vec->push_back(it->second);
}
void Module::GetStackFrameEntries(vector<StackFrameEntry *>* vec) {
vec->clear();
vec->insert(vec->begin(), stack_frame_entries_.begin(),
stack_frame_entries_.end());
}
Module::StackFrameEntry* Module::FindStackFrameEntryByAddress(Address address) {
StackFrameEntry search;
search.address = address;
StackFrameEntrySet::iterator it = stack_frame_entries_.upper_bound(&search);
if (it == stack_frame_entries_.begin())
return NULL;
it--;
if (EntryContainsAddress(*it, address))
return *it;
return NULL;
}
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->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) {
Function *func = *func_it;
for (vector<Line>::iterator line_it = func->lines.begin();
line_it != func->lines.end(); ++line_it)
line_it->file->source_id = 0;
}
// Finally, assign source ids to those files that have been marked.
// We could have just assigned source id numbers while traversing
// the line numbers, but doing it this way numbers the files in
// 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) {
if (!file_it->second->source_id)
file_it->second->source_id = next_source_id++;
}
}
bool Module::ReportError() {
fprintf(stderr, "error writing symbol file: %s\n",
strerror(errno));
return false;
}
bool Module::WriteRuleMap(const RuleMap &rule_map, std::ostream &stream) {
for (RuleMap::const_iterator it = rule_map.begin();
it != rule_map.end(); ++it) {
if (it != rule_map.begin())
stream << ' ';
stream << it->first << ": " << it->second;
}
return stream.good();
}
bool Module::Write(std::ostream &stream, SymbolData symbol_data) {
stream << "MODULE " << os_ << " " << architecture_ << " "
<< id_ << " " << name_ << endl;
if (!stream.good())
return ReportError();
if (symbol_data != ONLY_CFI) {
AssignSourceIds();
// Write out files.
for (FileByNameMap::iterator file_it = files_.begin();
file_it != files_.end(); ++file_it) {
File *file = file_it->second;
if (file->source_id >= 0) {
stream << "FILE " << file->source_id << " " << file->name << endl;
if (!stream.good())
return ReportError();
}
}
// Write out functions and their lines.
for (FunctionSet::const_iterator func_it = functions_.begin();
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<Line>::iterator line_it = func->lines.begin();
line_it != func->lines.end(); ++line_it) {
stream << hex
<< (line_it->address - load_address_) << " "
<< line_it->size << " "
<< dec
<< line_it->number << " "
<< line_it->file->source_id << endl;
if (!stream.good())
return ReportError();
}
}
// Write out 'PUBLIC' records.
for (ExternSet::const_iterator extern_it = externs_.begin();
extern_it != externs_.end(); ++extern_it) {
Extern *ext = *extern_it;
stream << "PUBLIC " << hex
<< (ext->address - load_address_) << " 0 "
<< ext->name << dec << endl;
if (!stream.good())
return ReportError();
}
}
if (symbol_data != NO_CFI) {
// Write out 'STACK CFI INIT' and 'STACK CFI' records.
StackFrameEntrySet::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 (!stream.good()
|| !WriteRuleMap(delta_it->second, stream))
return ReportError();
stream << endl;
}
}
}
return true;
}
} // namespace google_breakpad

View File

@ -45,6 +45,8 @@
#include "common/using_std_string.h"
using google_breakpad::Module;
using google_breakpad::ToUniqueString;
using google_breakpad::ustr__ZDcfa;
using std::stringstream;
using std::vector;
using testing::ContainerEq;
@ -131,11 +133,11 @@ TEST(Write, RelativeLoadAddress) {
entry->address = 0x30f9e5c83323973dULL;
entry->size = 0x49fc9ca7c7c13dc2ULL;
entry->initial_rules[ustr__ZDcfa()] = Module::Expr("he was a handsome man");
entry->initial_rules[toUniqueString("and")] =
entry->initial_rules[ToUniqueString("and")] =
Module::Expr("what i want to know is");
entry->rule_changes[0x30f9e5c83323973eULL][toUniqueString("how")] =
entry->rule_changes[0x30f9e5c83323973eULL][ToUniqueString("how")] =
Module::Expr("do you like your blueeyed boy");
entry->rule_changes[0x30f9e5c83323973eULL][toUniqueString("Mister")] =
entry->rule_changes[0x30f9e5c83323973eULL][ToUniqueString("Mister")] =
Module::Expr("Death");
m.AddStackFrameEntry(entry);
@ -143,7 +145,6 @@ TEST(Write, RelativeLoadAddress) {
// the module must work fine.
m.SetLoadAddress(0x2ab698b0b6407073LL);
/*TODO: fix this test. registers are not serialized alphabetically.
m.Write(s, ALL_SYMBOL_DATA);
string contents = s.str();
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
@ -160,7 +161,6 @@ TEST(Write, RelativeLoadAddress) {
" Mister: Death"
" how: do you like your blueeyed boy\n",
contents.c_str());
*/
}
TEST(Write, OmitUnusedFiles) {
@ -239,11 +239,11 @@ TEST(Write, NoCFI) {
entry->address = 0x30f9e5c83323973dULL;
entry->size = 0x49fc9ca7c7c13dc2ULL;
entry->initial_rules[ustr__ZDcfa()] = Module::Expr("he was a handsome man");
entry->initial_rules[toUniqueString("and")] =
entry->initial_rules[ToUniqueString("and")] =
Module::Expr("what i want to know is");
entry->rule_changes[0x30f9e5c83323973eULL][toUniqueString("how")] =
entry->rule_changes[0x30f9e5c83323973eULL][ToUniqueString("how")] =
Module::Expr("do you like your blueeyed boy");
entry->rule_changes[0x30f9e5c83323973eULL][toUniqueString("Mister")] =
entry->rule_changes[0x30f9e5c83323973eULL][ToUniqueString("Mister")] =
Module::Expr("Death");
m.AddStackFrameEntry(entry);
@ -318,9 +318,9 @@ TEST(Construct, AddFrames) {
entry2->size = 0x0de2a5ee55509407ULL;
entry2->initial_rules[ustr__ZDcfa()] =
Module::Expr("I think that I shall never see");
entry2->initial_rules[toUniqueString("stromboli")] =
entry2->initial_rules[ToUniqueString("stromboli")] =
Module::Expr("a poem lovely as a tree");
entry2->initial_rules[toUniqueString("cannoli")] =
entry2->initial_rules[ToUniqueString("cannoli")] =
Module::Expr("a tree whose hungry mouth is prest");
m.AddStackFrameEntry(entry2);
@ -329,18 +329,17 @@ TEST(Construct, AddFrames) {
entry3->address = 0x5e8d0db0a7075c6cULL;
entry3->size = 0x1c7edb12a7aea229ULL;
entry3->initial_rules[ustr__ZDcfa()] = Module::Expr("Whose woods are these");
entry3->rule_changes[0x47ceb0f63c269d7fULL][toUniqueString("calzone")] =
entry3->rule_changes[0x47ceb0f63c269d7fULL][ToUniqueString("calzone")] =
Module::Expr("the village though");
entry3->rule_changes[0x47ceb0f63c269d7fULL][toUniqueString("cannoli")] =
entry3->rule_changes[0x47ceb0f63c269d7fULL][ToUniqueString("cannoli")] =
Module::Expr("he will not see me stopping here");
entry3->rule_changes[0x36682fad3763ffffULL][toUniqueString("stromboli")] =
entry3->rule_changes[0x36682fad3763ffffULL][ToUniqueString("stromboli")] =
Module::Expr("his house is in");
entry3->rule_changes[0x36682fad3763ffffULL][ustr__ZDcfa()] =
Module::Expr("I think I know");
m.AddStackFrameEntry(entry3);
// Check that Write writes STACK CFI records properly.
/*TODO: fix this test
m.Write(s, ALL_SYMBOL_DATA);
string contents = s.str();
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
@ -358,7 +357,6 @@ TEST(Construct, AddFrames) {
" stromboli: a poem lovely as a tree\n"
"STACK CFI INIT ddb5f41285aa7757 1486493370dc5073 \n",
contents.c_str());
*/
// Check that GetStackFrameEntries works.
vector<Module::StackFrameEntry *> entries;
@ -373,11 +371,11 @@ TEST(Construct, AddFrames) {
Module::RuleChangeMap entry1_changes;
entry1_changes[0x36682fad3763ffffULL][ustr__ZDcfa()] =
Module::Expr("I think I know");
entry1_changes[0x36682fad3763ffffULL][toUniqueString("stromboli")] =
entry1_changes[0x36682fad3763ffffULL][ToUniqueString("stromboli")] =
Module::Expr("his house is in");
entry1_changes[0x47ceb0f63c269d7fULL][toUniqueString("calzone")] =
entry1_changes[0x47ceb0f63c269d7fULL][ToUniqueString("calzone")] =
Module::Expr("the village though");
entry1_changes[0x47ceb0f63c269d7fULL][toUniqueString("cannoli")] =
entry1_changes[0x47ceb0f63c269d7fULL][ToUniqueString("cannoli")] =
Module::Expr("he will not see me stopping here");
EXPECT_THAT(entries[0]->rule_changes, ContainerEq(entry1_changes));
// Check second entry.
@ -387,9 +385,9 @@ TEST(Construct, AddFrames) {
Module::RuleMap entry2_initial;
entry2_initial[ustr__ZDcfa()] =
Module::Expr("I think that I shall never see");
entry2_initial[toUniqueString("stromboli")] =
entry2_initial[ToUniqueString("stromboli")] =
Module::Expr("a poem lovely as a tree");
entry2_initial[toUniqueString("cannoli")] =
entry2_initial[ToUniqueString("cannoli")] =
Module::Expr("a tree whose hungry mouth is prest");
EXPECT_THAT(entries[1]->initial_rules, ContainerEq(entry2_initial));
ASSERT_EQ(0U, entries[1]->rule_changes.size());
@ -609,9 +607,9 @@ TEST(Lookup, StackFrameEntries) {
entry2->size = 0x900;
entry2->initial_rules[ustr__ZDcfa()] =
Module::Expr("I think that I shall never see");
entry2->initial_rules[toUniqueString("stromboli")] =
entry2->initial_rules[ToUniqueString("stromboli")] =
Module::Expr("a poem lovely as a tree");
entry2->initial_rules[toUniqueString("cannoli")] =
entry2->initial_rules[ToUniqueString("cannoli")] =
Module::Expr("a tree whose hungry mouth is prest");
m.AddStackFrameEntry(entry2);
@ -620,11 +618,11 @@ TEST(Lookup, StackFrameEntries) {
entry3->address = 0x1000;
entry3->size = 0x900;
entry3->initial_rules[ustr__ZDcfa()] = Module::Expr("Whose woods are these");
entry3->rule_changes[0x47ceb0f63c269d7fULL][toUniqueString("calzone")] =
entry3->rule_changes[0x47ceb0f63c269d7fULL][ToUniqueString("calzone")] =
Module::Expr("the village though");
entry3->rule_changes[0x47ceb0f63c269d7fULL][toUniqueString("cannoli")] =
entry3->rule_changes[0x47ceb0f63c269d7fULL][ToUniqueString("cannoli")] =
Module::Expr("he will not see me stopping here");
entry3->rule_changes[0x36682fad3763ffffULL][toUniqueString("stromboli")] =
entry3->rule_changes[0x36682fad3763ffffULL][ToUniqueString("stromboli")] =
Module::Expr("his house is in");
entry3->rule_changes[0x36682fad3763ffffULL][ustr__ZDcfa()] =
Module::Expr("I think I know");

View File

@ -1,34 +1,60 @@
#include <stdlib.h>
#include <string.h>
#include <stdio.h> // for debugging only
// Copyright (c) 2013 Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <string>
#include <map>
#include <stdlib.h>
#include <string.h>
#include "common/unique_string.h"
namespace google_breakpad {
///////////////////////////////////////////////////////////////////
// UniqueString
//
class UniqueString {
public:
UniqueString(string str) { str_ = strdup(str.c_str()); }
~UniqueString() { free((void*)str_); }
~UniqueString() { free(reinterpret_cast<void*>(const_cast<char*>(str_))); }
const char* str_;
};
class UniqueStringUniverse {
public:
UniqueStringUniverse() {};
const UniqueString* findOrCopy(string str)
{
std::map<string, UniqueString*>::iterator it;
it = map_.find(str);
const UniqueString* FindOrCopy(string str) {
std::map<string, UniqueString*>::iterator it = map_.find(str);
if (it == map_.end()) {
UniqueString* ustr = new UniqueString(str);
map_[str] = ustr;
fprintf(stderr, "UniqueString %d = \"%s\"\n",
(int)map_.size(), str.c_str());
return ustr;
} else {
return it->second;
@ -37,6 +63,7 @@ class UniqueStringUniverse {
private:
std::map<string, UniqueString*> map_;
};
//
///////////////////////////////////////////////////////////////////
@ -45,31 +72,39 @@ static UniqueStringUniverse* sUSU = NULL;
// This isn't threadsafe.
const UniqueString* toUniqueString(string str)
{
const UniqueString* ToUniqueString(string str) {
if (!sUSU) {
sUSU = new UniqueStringUniverse();
}
return sUSU->findOrCopy(str);
return sUSU->FindOrCopy(str);
}
// This isn't threadsafe.
const UniqueString* toUniqueString_n(char* str, size_t n)
{
const UniqueString* ToUniqueString_n(const char* str, size_t n) {
if (!sUSU) {
sUSU = new UniqueStringUniverse();
}
string key(str);
key.resize(n);
return sUSU->findOrCopy(key);
string key(str, n);
return sUSU->FindOrCopy(key);
}
const char index(const UniqueString* us, int ix)
const char Index(const UniqueString* us, int ix)
{
return us->str_[ix];
}
const char* const fromUniqueString(const UniqueString* ustr)
const char* const FromUniqueString(const UniqueString* ustr)
{
return ustr->str_;
}
int StrcmpUniqueString(const UniqueString* us1, const UniqueString* us2) {
return strcmp(us1->str_, us2->str_);
}
bool LessThan_UniqueString(const UniqueString* us1, const UniqueString* us2) {
int r = StrcmpUniqueString(us1, us2);
return r < 0;
}
} // namespace google_breakpad

View File

@ -1,30 +1,61 @@
// Copyright (c) 2013 Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#ifndef COMMON_UNIQUE_STRING_H
#define COMMON_UNIQUE_STRING_H
#ifndef COMMON_UNIQUE_STRING_H_
#define COMMON_UNIQUE_STRING_H_
#include <string>
#include <map>
#include <string>
#include "common/using_std_string.h"
// FIXME-remove, is debugging hack
#include <stdio.h>
#include <assert.h>
namespace google_breakpad {
// Abstract type
class UniqueString;
// Unique-ify a string. |toUniqueString| can never return NULL.
const UniqueString* toUniqueString(string);
// Unique-ify a string. |ToUniqueString| can never return NULL.
const UniqueString* ToUniqueString(string);
// ditto, starting instead from the first n characters of a C string
const UniqueString* toUniqueString_n(char* str, size_t n);
const UniqueString* ToUniqueString_n(const char* str, size_t n);
// Pull chars out of the string. No range checking.
const char index(const UniqueString*, int);
const char Index(const UniqueString*, int);
// Get the contained C string (debugging only)
const char* const fromUniqueString(const UniqueString*);
const char* const FromUniqueString(const UniqueString*);
// Do a strcmp-style comparison on the contained C string
int StrcmpUniqueString(const UniqueString*, const UniqueString*);
// Less-than comparison of two UniqueStrings, usable for std::sort.
bool LessThan_UniqueString(const UniqueString*, const UniqueString*);
// Some handy pre-uniqified strings. Z is an escape character:
// ZS '$'
@ -46,161 +77,161 @@ const char* const fromUniqueString(const UniqueString*);
// ""
inline static const UniqueString* ustr__empty() {
static const UniqueString* us = NULL;
if (!us) us = toUniqueString("");
if (!us) us = ToUniqueString("");
return us;
}
// "$eip"
inline static const UniqueString* ustr__ZSeip() {
static const UniqueString* us = NULL;
if (!us) us = toUniqueString("$eip");
if (!us) us = ToUniqueString("$eip");
return us;
}
// "$ebp"
inline static const UniqueString* ustr__ZSebp() {
static const UniqueString* us = NULL;
if (!us) us = toUniqueString("$ebp");
if (!us) us = ToUniqueString("$ebp");
return us;
}
// "$esp"
inline static const UniqueString* ustr__ZSesp() {
static const UniqueString* us = NULL;
if (!us) us = toUniqueString("$esp");
if (!us) us = ToUniqueString("$esp");
return us;
}
// "$ebx"
inline static const UniqueString* ustr__ZSebx() {
static const UniqueString* us = NULL;
if (!us) us = toUniqueString("$ebx");
if (!us) us = ToUniqueString("$ebx");
return us;
}
// "$esi"
inline static const UniqueString* ustr__ZSesi() {
static const UniqueString* us = NULL;
if (!us) us = toUniqueString("$esi");
if (!us) us = ToUniqueString("$esi");
return us;
}
// "$edi"
inline static const UniqueString* ustr__ZSedi() {
static const UniqueString* us = NULL;
if (!us) us = toUniqueString("$edi");
if (!us) us = ToUniqueString("$edi");
return us;
}
// ".cbCalleeParams"
inline static const UniqueString* ustr__ZDcbCalleeParams() {
static const UniqueString* us = NULL;
if (!us) us = toUniqueString(".cbCalleeParams");
if (!us) us = ToUniqueString(".cbCalleeParams");
return us;
}
// ".cbSavedRegs"
inline static const UniqueString* ustr__ZDcbSavedRegs() {
static const UniqueString* us = NULL;
if (!us) us = toUniqueString(".cbSavedRegs");
if (!us) us = ToUniqueString(".cbSavedRegs");
return us;
}
// ".cbLocals"
inline static const UniqueString* ustr__ZDcbLocals() {
static const UniqueString* us = NULL;
if (!us) us = toUniqueString(".cbLocals");
if (!us) us = ToUniqueString(".cbLocals");
return us;
}
// ".raSearchStart"
inline static const UniqueString* ustr__ZDraSearchStart() {
static const UniqueString* us = NULL;
if (!us) us = toUniqueString(".raSearchStart");
if (!us) us = ToUniqueString(".raSearchStart");
return us;
}
// ".raSearch"
inline static const UniqueString* ustr__ZDraSearch() {
static const UniqueString* us = NULL;
if (!us) us = toUniqueString(".raSearch");
if (!us) us = ToUniqueString(".raSearch");
return us;
}
// ".cbParams"
inline static const UniqueString* ustr__ZDcbParams() {
static const UniqueString* us = NULL;
if (!us) us = toUniqueString(".cbParams");
if (!us) us = ToUniqueString(".cbParams");
return us;
}
// "+"
inline static const UniqueString* ustr__Zplus() {
static const UniqueString* us = NULL;
if (!us) us = toUniqueString("+");
if (!us) us = ToUniqueString("+");
return us;
}
// "-"
inline static const UniqueString* ustr__Zminus() {
static const UniqueString* us = NULL;
if (!us) us = toUniqueString("-");
if (!us) us = ToUniqueString("-");
return us;
}
// "*"
inline static const UniqueString* ustr__Zstar() {
static const UniqueString* us = NULL;
if (!us) us = toUniqueString("*");
if (!us) us = ToUniqueString("*");
return us;
}
// "/"
inline static const UniqueString* ustr__Zslash() {
static const UniqueString* us = NULL;
if (!us) us = toUniqueString("/");
if (!us) us = ToUniqueString("/");
return us;
}
// "%"
inline static const UniqueString* ustr__Zpercent() {
static const UniqueString* us = NULL;
if (!us) us = toUniqueString("%");
if (!us) us = ToUniqueString("%");
return us;
}
// "@"
inline static const UniqueString* ustr__Zat() {
static const UniqueString* us = NULL;
if (!us) us = toUniqueString("@");
if (!us) us = ToUniqueString("@");
return us;
}
// "^"
inline static const UniqueString* ustr__Zcaret() {
static const UniqueString* us = NULL;
if (!us) us = toUniqueString("^");
if (!us) us = ToUniqueString("^");
return us;
}
// "="
inline static const UniqueString* ustr__Zeq() {
static const UniqueString* us = NULL;
if (!us) us = toUniqueString("=");
if (!us) us = ToUniqueString("=");
return us;
}
// ".cfa"
inline static const UniqueString* ustr__ZDcfa() {
static const UniqueString* us = NULL;
if (!us) us = toUniqueString(".cfa");
if (!us) us = ToUniqueString(".cfa");
return us;
}
// ".ra"
inline static const UniqueString* ustr__ZDra() {
static const UniqueString* us = NULL;
if (!us) us = toUniqueString(".ra");
if (!us) us = ToUniqueString(".ra");
return us;
}
@ -211,35 +242,21 @@ class UniqueStringMap
static const int N_FIXED = 10;
public:
/* __attribute__((noinline)) */ UniqueStringMap()
: n_fixed_(0), n_sets_(0), n_gets_(0), n_clears_(0)
{
};
/* __attribute__((noinline)) */ ~UniqueStringMap()
{
if (0)
fprintf(stderr,
"~UniqueStringMap: size %2d, sets %2d, gets %2d, clears %2d\n",
n_fixed_ + (int)map_.size(),
n_sets_, n_gets_, n_clears_);
};
UniqueStringMap() : n_fixed_(0), n_sets_(0), n_gets_(0), n_clears_(0) {};
~UniqueStringMap() {};
// Empty out the map.
/* __attribute__((noinline)) */ void clear()
{
n_clears_++;
void clear() {
++n_clears_;
map_.clear();
n_fixed_ = 0;
}
// Do "map[ix] = v".
/* __attribute__((noinline)) */ void set(const UniqueString* ix,
ValueType v)
{
n_sets_++;
void set(const UniqueString* ix, ValueType v) {
++n_sets_;
int i;
for (i = 0; i < n_fixed_; i++) {
for (i = 0; i < n_fixed_; ++i) {
if (fixed_keys_[i] == ix) {
fixed_vals_[i] = v;
return;
@ -249,26 +266,24 @@ class UniqueStringMap
i = n_fixed_;
fixed_keys_[i] = ix;
fixed_vals_[i] = v;
n_fixed_++;
++n_fixed_;
} else {
map_[ix] = v;
}
}
// Lookup 'ix' in the map, and also return a success/fail boolean.
/* __attribute__((noinline)) */ ValueType get(/*OUT*/bool* have,
const UniqueString* ix) const
{
n_gets_++;
ValueType get(/*OUT*/bool* have, const UniqueString* ix) const {
++n_gets_;
int i;
for (i = 0; i < n_fixed_; i++) {
for (i = 0; i < n_fixed_; ++i) {
if (fixed_keys_[i] == ix) {
*have = true;
return fixed_vals_[i];
}
}
typename std::map<const UniqueString*, ValueType>::const_iterator it
= map_.find(ix);
= map_.find(ix);
if (it == map_.end()) {
*have = false;
return ValueType();
@ -279,37 +294,48 @@ class UniqueStringMap
};
// Lookup 'ix' in the map, and return zero if it is not present.
/* __attribute__((noinline)) */ ValueType get(const UniqueString* ix)
{
n_gets_++;
ValueType get(const UniqueString* ix) const {
++n_gets_;
bool found;
ValueType v = get(&found, ix);
return found ? v : ValueType();
}
// Find out whether 'ix' is in the map.
/* __attribute__((noinline)) */ bool have(const UniqueString* ix) const
{
n_gets_++;
bool have(const UniqueString* ix) const {
++n_gets_;
bool found;
(void)get(&found, ix);
return found;
}
// Copy the contents to a std::map, generally for testing.
void copy_to_map(std::map<const UniqueString*, ValueType>* m) const {
m->clear();
int i;
for (i = 0; i < n_fixed_; ++i) {
(*m)[fixed_keys_[i]] = fixed_vals_[i];
}
m->insert(map_.begin(), map_.end());
}
// Note that users of this class rely on having also a sane
// assignment operator. The default one is OK, though.
// AFAICT there are no uses of the copy constructor, but if
// there were, the default one would also suffice.
private:
// Quick (we hope) cache
// Quick (hopefully) cache
const UniqueString* fixed_keys_[N_FIXED];
ValueType fixed_vals_[N_FIXED];
int n_fixed_; /* 0 .. N_FIXED inclusive */
int n_fixed_; // 0 .. N_FIXED inclusive
// Fallback storage when the cache is filled
std::map<const UniqueString*, ValueType> map_;
// For tracking usage stats.
mutable int n_sets_, n_gets_, n_clears_;
};
#endif /* ndef COMMON_UNIQUE_STRING_H */
} // namespace google_breakpad
#endif // COMMON_UNIQUE_STRING_H_

View File

@ -29,6 +29,7 @@
#include <stdio.h>
#include <map>
#include <string>
#include "breakpad_googletest_includes.h"
@ -48,11 +49,21 @@ namespace {
using google_breakpad::BasicSourceLineResolver;
using google_breakpad::CFIFrameInfo;
using google_breakpad::CodeModule;
using google_breakpad::FromUniqueString;
using google_breakpad::MemoryRegion;
using google_breakpad::StackFrame;
using google_breakpad::ToUniqueString;
using google_breakpad::UniqueString;
using google_breakpad::WindowsFrameInfo;
using google_breakpad::linked_ptr;
using google_breakpad::scoped_ptr;
using google_breakpad::ustr__ZDcfa;
using google_breakpad::ustr__ZDra;
using google_breakpad::ustr__ZSebx;
using google_breakpad::ustr__ZSebp;
using google_breakpad::ustr__ZSedi;
using google_breakpad::ustr__ZSesi;
using google_breakpad::ustr__ZSesp;
class TestCodeModule : public CodeModule {
public:
@ -109,32 +120,36 @@ class MockMemoryRegion: public MemoryRegion {
// ".cfa".
static bool VerifyRegisters(
const char *file, int line,
const CFIFrameInfo::RegisterValueMap<u_int32_t> &expected,
const CFIFrameInfo::RegisterValueMap<u_int32_t> &actual) {
if (!actual.have(ustr__ZDcfa()))
const std::map<const UniqueString*, u_int32_t> &expected,
const CFIFrameInfo::RegisterValueMap<u_int32_t> &actual_regmap) {
std::map<const UniqueString*, u_int32_t> actual;
actual_regmap.copy_to_map(&actual);
std::map<const UniqueString*, u_int32_t>::const_iterator a;
a = actual.find(ustr__ZDcfa());
if (a == actual.end())
return false;
if (!actual.have(ustr__ZDra()))
a = actual.find(ustr__ZDra());
if (a == actual.end())
return false;
/*TODO: fix
for (a = actual.begin(); a != actual.end(); a++) {
CFIFrameInfo::RegisterValueMap<u_int32_t>::const_iterator e =
std::map<const UniqueString*, u_int32_t>::const_iterator e =
expected.find(a->first);
if (e == expected.end()) {
fprintf(stderr, "%s:%d: unexpected register '%s' recovered, value 0x%x\n",
file, line, fromUniqueString(a->first), a->second);
file, line, FromUniqueString(a->first), a->second);
return false;
}
if (e->second != a->second) {
fprintf(stderr,
"%s:%d: register '%s' recovered value was 0x%x, expected 0x%x\n",
file, line, fromUniqueString(a->first), a->second, e->second);
file, line, FromUniqueString(a->first), a->second, e->second);
return false;
}
// Don't complain if this doesn't recover all registers. Although
// the DWARF spec says that unmentioned registers are undefined,
// GCC uses omission to mean that they are unchanged.
}
*/
return true;
}
@ -253,17 +268,17 @@ TEST_F(TestBasicSourceLineResolver, TestLoadAndResolve)
CFIFrameInfo::RegisterValueMap<u_int32_t> current_registers;
CFIFrameInfo::RegisterValueMap<u_int32_t> caller_registers;
CFIFrameInfo::RegisterValueMap<u_int32_t> expected_caller_registers;
std::map<const UniqueString*, u_int32_t> expected_caller_registers;
MockMemoryRegion memory;
// Regardless of which instruction evaluation takes place at, it
// should produce the same values for the caller's registers.
expected_caller_registers.set(ustr__ZDcfa(), 0x1001c);
expected_caller_registers.set(ustr__ZDra(), 0xf6438648);
expected_caller_registers.set(ustr__ZSebp(), 0x10038);
expected_caller_registers.set(ustr__ZSebx(), 0x98ecadc3);
expected_caller_registers.set(ustr__ZSesi(), 0x878f7524);
expected_caller_registers.set(ustr__ZSedi(), 0x6312f9a5);
expected_caller_registers[ustr__ZDcfa()] = 0x1001c;
expected_caller_registers[ustr__ZDra()] = 0xf6438648;
expected_caller_registers[ustr__ZSebp()] = 0x10038;
expected_caller_registers[ustr__ZSebx()] = 0x98ecadc3;
expected_caller_registers[ustr__ZSesi()] = 0x878f7524;
expected_caller_registers[ustr__ZSedi()] = 0x6312f9a5;
frame.instruction = 0x3d40;
frame.module = &module1;

View File

@ -36,6 +36,7 @@
#include <string.h>
#include <algorithm>
#include <sstream>
#include "common/scoped_ptr.h"
@ -108,12 +109,29 @@ string CFIFrameInfo::Serialize() const {
stream << " ";
stream << ".ra: " << ra_rule_;
}
// Visit the register rules in alphabetical order. Because
// register_rules_ has the elements in some arbitrary order,
// get the names out into a vector, sort them, and visit in
// sorted order.
std::vector<const UniqueString*> rr_names;
for (RuleMap::const_iterator iter = register_rules_.begin();
iter != register_rules_.end();
++iter) {
rr_names.push_back(iter->first);
}
std::sort(rr_names.begin(), rr_names.end(), LessThan_UniqueString);
// Now visit the register rules in alphabetical order.
for (std::vector<const UniqueString*>::const_iterator name = rr_names.begin();
name != rr_names.end();
++name) {
const UniqueString* nm = *name;
Module::Expr rule = register_rules_.at(nm);
if (static_cast<std::streamoff>(stream.tellp()) != 0)
stream << " ";
stream << fromUniqueString(iter->first) << ": " << iter->second;
stream << FromUniqueString(nm) << ": " << rule;
}
return stream.str();
@ -145,7 +163,7 @@ bool CFIRuleParser::Parse(const string &rule_set) {
if (name_ != ustr__empty() || !expression_.empty()) {
if (!Report()) return false;
}
name_ = toUniqueString_n(token, token_len - 1);
name_ = ToUniqueString_n(token, token_len - 1);
expression_.clear();
} else {
// Another expression component.

View File

@ -43,9 +43,14 @@
using google_breakpad::CFIFrameInfo;
using google_breakpad::CFIFrameInfoParseHandler;
using google_breakpad::CFIRuleParser;
using google_breakpad::FromUniqueString;
using google_breakpad::MemoryRegion;
using google_breakpad::Module;
using google_breakpad::SimpleCFIWalker;
using google_breakpad::ToUniqueString;
using google_breakpad::UniqueString;
using google_breakpad::ustr__ZDcfa;
using google_breakpad::ustr__ZDra;
using testing::_;
using testing::A;
using testing::AtMost;
@ -124,10 +129,10 @@ TEST_F(Simple, SetManyRules) {
cfi.SetCFARule(Module::Expr("$temp1 68737028 = $temp2 61072337 = $temp1 $temp2 -"));
cfi.SetRARule(Module::Expr(".cfa 99804755 +"));
const UniqueString* reg1 = toUniqueString("register1");
const UniqueString* reg2 = toUniqueString("vodkathumbscrewingly");
const UniqueString* reg3 = toUniqueString("pubvexingfjordschmaltzy");
const UniqueString* reg4 = toUniqueString("uncopyrightables");
const UniqueString* reg1 = ToUniqueString("register1");
const UniqueString* reg2 = ToUniqueString("vodkathumbscrewingly");
const UniqueString* reg3 = ToUniqueString("pubvexingfjordschmaltzy");
const UniqueString* reg4 = ToUniqueString("uncopyrightables");
cfi.SetRegisterRule(reg1, Module::Expr(".cfa 54370437 *"));
cfi.SetRegisterRule(reg2, Module::Expr("24076308 .cfa +"));
@ -141,7 +146,6 @@ TEST_F(Simple, SetManyRules) {
ASSERT_EQ(31740999U, caller_registers.get(reg2));
ASSERT_EQ(-22136316ULL, caller_registers.get(reg3));
ASSERT_EQ(12U, caller_registers.get(reg4));
/*TODO: fix this test, Serialize no longer serializes alphabetically
ASSERT_EQ(".cfa: $temp1 68737028 = $temp2 61072337 = $temp1 $temp2 - "
".ra: .cfa 99804755 + "
"pubvexingfjordschmaltzy: .cfa 29801007 - "
@ -149,7 +153,6 @@ TEST_F(Simple, SetManyRules) {
"uncopyrightables: 92642917 .cfa / "
"vodkathumbscrewingly: 24076308 .cfa +",
cfi.Serialize());
*/
}
TEST_F(Simple, RulesOverride) {
@ -193,8 +196,8 @@ TEST_F(Scope, CFALacksRA) {
TEST_F(Scope, CFASeesCurrentRegs) {
ExpectNoMemoryReferences();
const UniqueString* reg1 = toUniqueString(".baraminology");
const UniqueString* reg2 = toUniqueString(".ornithorhynchus");
const UniqueString* reg1 = ToUniqueString(".baraminology");
const UniqueString* reg2 = ToUniqueString(".ornithorhynchus");
registers.set(reg1, 0x06a7bc63e4f13893ULL);
registers.set(reg2, 0x5e0bf850bafce9d2ULL);
cfi.SetCFARule(Module::Expr(".baraminology .ornithorhynchus +"));
@ -232,7 +235,7 @@ TEST_F(Scope, RASeesCurrentRegs) {
ExpectNoMemoryReferences();
cfi.SetCFARule(Module::Expr("10359370"));
const UniqueString* reg1 = toUniqueString("noachian");
const UniqueString* reg1 = ToUniqueString("noachian");
registers.set(reg1, 0x54dc4a5d8e5eb503ULL);
cfi.SetRARule(Module::Expr(reg1, 0, false));
ASSERT_TRUE(cfi.FindCallerRegs<u_int64_t>(registers, memory,
@ -246,7 +249,7 @@ TEST_F(Scope, RegistersSeeCFA) {
cfi.SetCFARule(Module::Expr("6515179"));
cfi.SetRARule(Module::Expr(".cfa"));
const UniqueString* reg1 = toUniqueString("rogerian");
const UniqueString* reg1 = ToUniqueString("rogerian");
cfi.SetRegisterRule(reg1, Module::Expr(".cfa"));
ASSERT_TRUE(cfi.FindCallerRegs<u_int64_t>(registers, memory,
&caller_registers));
@ -259,7 +262,7 @@ TEST_F(Scope, RegsLackRA) {
cfi.SetCFARule(Module::Expr("42740329"));
cfi.SetRARule(Module::Expr("27045204"));
const UniqueString* reg1 = toUniqueString("$r1");
const UniqueString* reg1 = ToUniqueString("$r1");
cfi.SetRegisterRule(reg1, Module::Expr(".ra"));
ASSERT_FALSE(cfi.FindCallerRegs<u_int64_t>(registers, memory,
&caller_registers));
@ -269,8 +272,8 @@ TEST_F(Scope, RegsLackRA) {
TEST_F(Scope, RegsSeeRegs) {
ExpectNoMemoryReferences();
const UniqueString* reg1 = toUniqueString("$r1");
const UniqueString* reg2 = toUniqueString("$r2");
const UniqueString* reg1 = ToUniqueString("$r1");
const UniqueString* reg2 = ToUniqueString("$r2");
registers.set(reg1, 0x6ed3582c4bedb9adULL);
registers.set(reg2, 0xd27d9e742b8df6d0ULL);
cfi.SetCFARule(Module::Expr("88239303"));
@ -373,7 +376,7 @@ TEST_F(Parser, RA) {
}
TEST_F(Parser, Reg) {
EXPECT_CALL(mock_handler, RegisterRule(toUniqueString("nemo"), "mellifluous"))
EXPECT_CALL(mock_handler, RegisterRule(ToUniqueString("nemo"), "mellifluous"))
.WillOnce(Return());
EXPECT_TRUE(parser.Parse("nemo: mellifluous"));
}
@ -381,18 +384,18 @@ TEST_F(Parser, Reg) {
TEST_F(Parser, CFARARegs) {
EXPECT_CALL(mock_handler, CFARule("cfa expression")).WillOnce(Return());
EXPECT_CALL(mock_handler, RARule("ra expression")).WillOnce(Return());
EXPECT_CALL(mock_handler, RegisterRule(toUniqueString("galba"), "praetorian"))
EXPECT_CALL(mock_handler, RegisterRule(ToUniqueString("galba"), "praetorian"))
.WillOnce(Return());
EXPECT_CALL(mock_handler, RegisterRule(toUniqueString("otho"), "vitellius"))
EXPECT_CALL(mock_handler, RegisterRule(ToUniqueString("otho"), "vitellius"))
.WillOnce(Return());
EXPECT_TRUE(parser.Parse(".cfa: cfa expression .ra: ra expression "
"galba: praetorian otho: vitellius"));
}
TEST_F(Parser, Whitespace) {
EXPECT_CALL(mock_handler, RegisterRule(toUniqueString("r1"), "r1 expression"))
EXPECT_CALL(mock_handler, RegisterRule(ToUniqueString("r1"), "r1 expression"))
.WillOnce(Return());
EXPECT_CALL(mock_handler, RegisterRule(toUniqueString("r2"), "r2 expression"))
EXPECT_CALL(mock_handler, RegisterRule(ToUniqueString("r2"), "r2 expression"))
.WillOnce(Return());
EXPECT_TRUE(parser.Parse(" r1:\tr1\nexpression \tr2:\t\rr2\r\n "
"expression \n"));
@ -403,21 +406,21 @@ TEST_F(Parser, WhitespaceLoneColon) {
}
TEST_F(Parser, EmptyName) {
EXPECT_CALL(mock_handler, RegisterRule(toUniqueString("reg"), _))
EXPECT_CALL(mock_handler, RegisterRule(ToUniqueString("reg"), _))
.Times(AtMost(1))
.WillRepeatedly(Return());
EXPECT_FALSE(parser.Parse("reg: expr1 : expr2"));
}
TEST_F(Parser, RuleLoneColon) {
EXPECT_CALL(mock_handler, RegisterRule(toUniqueString("r1"), "expr"))
EXPECT_CALL(mock_handler, RegisterRule(ToUniqueString("r1"), "expr"))
.Times(AtMost(1))
.WillRepeatedly(Return());
EXPECT_FALSE(parser.Parse(" r1: expr :"));
}
TEST_F(Parser, RegNoExprRule) {
EXPECT_CALL(mock_handler, RegisterRule(toUniqueString("r1"), "expr"))
EXPECT_CALL(mock_handler, RegisterRule(ToUniqueString("r1"), "expr"))
.Times(AtMost(1))
.WillRepeatedly(Return());
EXPECT_FALSE(parser.Parse("r0: r1: expr"));
@ -434,8 +437,8 @@ class ParseHandler: public ParseHandlerFixture, public Test { };
TEST_F(ParseHandler, CFARARule) {
handler.CFARule("reg-for-cfa");
handler.RARule("reg-for-ra");
registers.set(toUniqueString("reg-for-cfa"), 0x268a9a4a3821a797ULL);
registers.set(toUniqueString("reg-for-ra"), 0x6301b475b8b91c02ULL);
registers.set(ToUniqueString("reg-for-cfa"), 0x268a9a4a3821a797ULL);
registers.set(ToUniqueString("reg-for-ra"), 0x6301b475b8b91c02ULL);
ASSERT_TRUE(cfi.FindCallerRegs<u_int64_t>(registers, memory,
&caller_registers));
ASSERT_EQ(0x268a9a4a3821a797ULL, caller_registers.get(ustr__ZDcfa()));
@ -445,18 +448,18 @@ TEST_F(ParseHandler, CFARARule) {
TEST_F(ParseHandler, RegisterRules) {
handler.CFARule("reg-for-cfa");
handler.RARule("reg-for-ra");
handler.RegisterRule(toUniqueString("reg1"), "reg-for-reg1");
handler.RegisterRule(toUniqueString("reg2"), "reg-for-reg2");
registers.set(toUniqueString("reg-for-cfa"), 0x268a9a4a3821a797ULL);
registers.set(toUniqueString("reg-for-ra"), 0x6301b475b8b91c02ULL);
registers.set(toUniqueString("reg-for-reg1"), 0x06cde8e2ff062481ULL);
registers.set(toUniqueString("reg-for-reg2"), 0xff0c4f76403173e2ULL);
handler.RegisterRule(ToUniqueString("reg1"), "reg-for-reg1");
handler.RegisterRule(ToUniqueString("reg2"), "reg-for-reg2");
registers.set(ToUniqueString("reg-for-cfa"), 0x268a9a4a3821a797ULL);
registers.set(ToUniqueString("reg-for-ra"), 0x6301b475b8b91c02ULL);
registers.set(ToUniqueString("reg-for-reg1"), 0x06cde8e2ff062481ULL);
registers.set(ToUniqueString("reg-for-reg2"), 0xff0c4f76403173e2ULL);
ASSERT_TRUE(cfi.FindCallerRegs<u_int64_t>(registers, memory,
&caller_registers));
ASSERT_EQ(0x268a9a4a3821a797ULL, caller_registers.get(ustr__ZDcfa()));
ASSERT_EQ(0x6301b475b8b91c02ULL, caller_registers.get(ustr__ZDra()));
ASSERT_EQ(0x06cde8e2ff062481ULL, caller_registers.get(toUniqueString("reg1")));
ASSERT_EQ(0xff0c4f76403173e2ULL, caller_registers.get(toUniqueString("reg2")));
ASSERT_EQ(0x06cde8e2ff062481ULL, caller_registers.get(ToUniqueString("reg1")));
ASSERT_EQ(0xff0c4f76403173e2ULL, caller_registers.get(ToUniqueString("reg2")));
}
struct SimpleCFIWalkerFixture {
@ -487,13 +490,13 @@ struct SimpleCFIWalkerFixture {
SimpleCFIWalkerFixture::CFIWalker::RegisterSet
SimpleCFIWalkerFixture::register_map[7] = {
{ toUniqueString("r0"), NULL, true, R0_VALID, &RawContext::r0 },
{ toUniqueString("r1"), NULL, true, R1_VALID, &RawContext::r1 },
{ toUniqueString("r2"), NULL, false, R2_VALID, &RawContext::r2 },
{ toUniqueString("r3"), NULL, false, R3_VALID, &RawContext::r3 },
{ toUniqueString("r4"), NULL, true, R4_VALID, &RawContext::r4 },
{ toUniqueString("sp"), ustr__ZDcfa(), true, SP_VALID, &RawContext::sp },
{ toUniqueString("pc"), ustr__ZDra(), true, PC_VALID, &RawContext::pc },
{ ToUniqueString("r0"), NULL, true, R0_VALID, &RawContext::r0 },
{ ToUniqueString("r1"), NULL, true, R1_VALID, &RawContext::r1 },
{ ToUniqueString("r2"), NULL, false, R2_VALID, &RawContext::r2 },
{ ToUniqueString("r3"), NULL, false, R3_VALID, &RawContext::r3 },
{ ToUniqueString("r4"), NULL, true, R4_VALID, &RawContext::r4 },
{ ToUniqueString("sp"), ustr__ZDcfa(), true, SP_VALID, &RawContext::sp },
{ ToUniqueString("pc"), ustr__ZDra(), true, PC_VALID, &RawContext::pc },
};
class SimpleWalker: public SimpleCFIWalkerFixture, public Test { };
@ -528,9 +531,9 @@ TEST_F(SimpleWalker, Walk) {
call_frame_info.SetCFARule(Module::Expr("sp 24 +"));
call_frame_info.SetRARule(Module::Expr(".cfa 8 - ^"));
call_frame_info.SetRegisterRule(toUniqueString("r0"),
call_frame_info.SetRegisterRule(ToUniqueString("r0"),
Module::Expr(".cfa 24 - ^"));
call_frame_info.SetRegisterRule(toUniqueString("r1"),
call_frame_info.SetRegisterRule(ToUniqueString("r1"),
Module::Expr("r2"));
callee_context.r0 = 0x94e030ca79edd119ULL;

View File

@ -56,15 +56,25 @@ namespace {
using google_breakpad::SourceLineResolverBase;
using google_breakpad::BasicSourceLineResolver;
using google_breakpad::FastSourceLineResolver;
using google_breakpad::FromUniqueString;
using google_breakpad::ModuleSerializer;
using google_breakpad::ModuleComparer;
using google_breakpad::CFIFrameInfo;
using google_breakpad::CodeModule;
using google_breakpad::MemoryRegion;
using google_breakpad::StackFrame;
using google_breakpad::ToUniqueString;
using google_breakpad::UniqueString;
using google_breakpad::WindowsFrameInfo;
using google_breakpad::linked_ptr;
using google_breakpad::scoped_ptr;
using google_breakpad::ustr__ZDcfa;
using google_breakpad::ustr__ZDra;
using google_breakpad::ustr__ZSebx;
using google_breakpad::ustr__ZSebp;
using google_breakpad::ustr__ZSedi;
using google_breakpad::ustr__ZSesi;
using google_breakpad::ustr__ZSesp;
class TestCodeModule : public CodeModule {
public:
@ -121,32 +131,36 @@ class MockMemoryRegion: public MemoryRegion {
// ".cfa".
static bool VerifyRegisters(
const char *file, int line,
const CFIFrameInfo::RegisterValueMap<u_int32_t> &expected,
const CFIFrameInfo::RegisterValueMap<u_int32_t> &actual) {
if (!actual.have(ustr__ZDcfa()))
const std::map<const UniqueString*, u_int32_t> &expected,
const CFIFrameInfo::RegisterValueMap<u_int32_t> &actual_regmap) {
std::map<const UniqueString*, u_int32_t> actual;
actual_regmap.copy_to_map(&actual);
std::map<const UniqueString*, u_int32_t>::const_iterator a;
a = actual.find(ustr__ZDcfa());
if (a == actual.end())
return false;
if (!actual.have(ustr__ZDra()))
a = actual.find(ustr__ZDra());
if (a == actual.end())
return false;
/*TODO: fixme
for (a = actual.begin(); a != actual.end(); a++) {
CFIFrameInfo::RegisterValueMap<u_int32_t>::const_iterator e =
std::map<const UniqueString*, u_int32_t>::const_iterator e =
expected.find(a->first);
if (e == expected.end()) {
fprintf(stderr, "%s:%d: unexpected register '%s' recovered, value 0x%x\n",
file, line, fromUniqueString(a->first), a->second);
file, line, FromUniqueString(a->first), a->second);
return false;
}
if (e->second != a->second) {
fprintf(stderr,
"%s:%d: register '%s' recovered value was 0x%x, expected 0x%x\n",
file, line, fromUniqueString(a->first), a->second, e->second);
file, line, FromUniqueString(a->first), a->second, e->second);
return false;
}
// Don't complain if this doesn't recover all registers. Although
// the DWARF spec says that unmentioned registers are undefined,
// GCC uses omission to mean that they are unchanged.
}
*/
return true;
}
@ -281,17 +295,18 @@ TEST_F(TestFastSourceLineResolver, TestLoadAndResolve) {
CFIFrameInfo::RegisterValueMap<u_int32_t> current_registers;
CFIFrameInfo::RegisterValueMap<u_int32_t> caller_registers;
CFIFrameInfo::RegisterValueMap<u_int32_t> expected_caller_registers;
std::map<const UniqueString*, u_int32_t> expected_caller_registers;
MockMemoryRegion memory;
// Regardless of which instruction evaluation takes place at, it
// should produce the same values for the caller's registers.
expected_caller_registers.set(ustr__ZDcfa(), 0x1001c);
expected_caller_registers.set(ustr__ZDra(), 0xf6438648);
expected_caller_registers.set(ustr__ZSebp(), 0x10038);
expected_caller_registers.set(ustr__ZSebx(), 0x98ecadc3);
expected_caller_registers.set(ustr__ZSesi(), 0x878f7524);
expected_caller_registers.set(ustr__ZSedi(), 0x6312f9a5);
// should produce the same values for the caller's registers.
expected_caller_registers[ustr__ZDcfa()] = 0x1001c;
expected_caller_registers[ustr__ZDra()] = 0xf6438648;
expected_caller_registers[ustr__ZSebp()] = 0x10038;
expected_caller_registers[ustr__ZSebx()] = 0x98ecadc3;
expected_caller_registers[ustr__ZSesi()] = 0x878f7524;
expected_caller_registers[ustr__ZSedi()] = 0x6312f9a5;
frame.instruction = 0x3d40;
frame.module = &module1;

View File

@ -233,6 +233,17 @@ static void PrintStack(const CallStack *stack, const string &cpu) {
const StackFrameARM *frame_arm =
reinterpret_cast<const StackFrameARM*>(frame);
// Argument registers (caller-saves), which will likely only be valid
// for the youngest frame.
if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R0)
sequence = PrintRegister("r0", frame_arm->context.iregs[0], sequence);
if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R1)
sequence = PrintRegister("r1", frame_arm->context.iregs[1], sequence);
if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R2)
sequence = PrintRegister("r2", frame_arm->context.iregs[2], sequence);
if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R3)
sequence = PrintRegister("r3", frame_arm->context.iregs[3], sequence);
// General-purpose callee-saves registers.
if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R4)
sequence = PrintRegister("r4", frame_arm->context.iregs[4], sequence);

View File

@ -184,7 +184,7 @@ bool PostfixEvaluator<ValueType>::EvaluateToken(
HexString(value) << ": " << expression;
return false;
}
if (identifier == ustr__empty() || index(identifier,0) != '$') {
if (identifier == ustr__empty() || Index(identifier,0) != '$') {
BPLOG(ERROR) << "Can't assign " << HexString(value) << " to " <<
identifier << ": " << expression;
return false;
@ -194,7 +194,7 @@ bool PostfixEvaluator<ValueType>::EvaluateToken(
if (assigned)
assigned->set(identifier, true);
} else {
// Push it onto the stack as-is, but first convert it either to a
// Push it onto the stack as-is, but first convert it either to a
// ValueType (if a literal) or to a UniqueString* (if an identifier).
//
// First, try to treat the value as a literal. Literals may have leading
@ -216,7 +216,7 @@ bool PostfixEvaluator<ValueType>::EvaluateToken(
if (token_stream >> literal && token_stream.peek() == EOF) {
PushValue(negative ? (-literal) : literal);
} else {
PushIdentifier(toUniqueString(token));
PushIdentifier(ToUniqueString(token));
}
}
return true;
@ -310,7 +310,7 @@ bool PostfixEvaluator<ValueType>::EvaluateForValue(const Module::Expr& expr,
if (!found) {
// The identifier wasn't found in the dictionary. Don't imply any
// default value, just fail.
BPLOG(INFO) << "Identifier " << fromUniqueString(expr.ident_)
BPLOG(INFO) << "Identifier " << FromUniqueString(expr.ident_)
<< " not in dictionary (kExprSimple{Mem})";
return false;
}
@ -378,7 +378,7 @@ bool PostfixEvaluator<ValueType>::PopValue(ValueType *value) {
if (!found) {
// The identifier wasn't found in the dictionary. Don't imply any
// default value, just fail.
BPLOG(INFO) << "Identifier " << fromUniqueString(token)
BPLOG(INFO) << "Identifier " << FromUniqueString(token)
<< " not in dictionary";
return false;
}

View File

@ -48,8 +48,22 @@ namespace {
using std::map;
using google_breakpad::FromUniqueString;
using google_breakpad::MemoryRegion;
using google_breakpad::PostfixEvaluator;
using google_breakpad::ToUniqueString;
using google_breakpad::UniqueString;
using google_breakpad::ustr__ZDcbParams;
using google_breakpad::ustr__ZDcbSavedRegs;
using google_breakpad::ustr__ZDcfa;
using google_breakpad::ustr__ZDra;
using google_breakpad::ustr__ZDraSearchStart;
using google_breakpad::ustr__ZSebx;
using google_breakpad::ustr__ZSebp;
using google_breakpad::ustr__ZSedi;
using google_breakpad::ustr__ZSeip;
using google_breakpad::ustr__ZSesi;
using google_breakpad::ustr__ZSesp;
// FakeMemoryRegion is used to test PostfixEvaluator's dereference (^)
@ -153,16 +167,16 @@ static bool RunTests() {
{ "$rAdd3 2 2 + =$rMul2 9 6 * =", true } // smashed-equals tokenization
};
map<const UniqueString*, unsigned int> validate_data_0;
validate_data_0[toUniqueString("$rAdd")] = 8;
validate_data_0[toUniqueString("$rAdd2")] = 4;
validate_data_0[toUniqueString("$rSub")] = 3;
validate_data_0[toUniqueString("$rMul")] = 54;
validate_data_0[toUniqueString("$rDivQ")] = 1;
validate_data_0[toUniqueString("$rDivM")] = 3;
validate_data_0[toUniqueString("$rDeref")] = 10;
validate_data_0[toUniqueString("$rAlign")] = 32;
validate_data_0[toUniqueString("$rAdd3")] = 4;
validate_data_0[toUniqueString("$rMul2")] = 54;
validate_data_0[ToUniqueString("$rAdd")] = 8;
validate_data_0[ToUniqueString("$rAdd2")] = 4;
validate_data_0[ToUniqueString("$rSub")] = 3;
validate_data_0[ToUniqueString("$rMul")] = 54;
validate_data_0[ToUniqueString("$rDivQ")] = 1;
validate_data_0[ToUniqueString("$rDivM")] = 3;
validate_data_0[ToUniqueString("$rDeref")] = 10;
validate_data_0[ToUniqueString("$rAlign")] = 32;
validate_data_0[ToUniqueString("$rAdd3")] = 4;
validate_data_0[ToUniqueString("$rMul2")] = 54;
// The second test set simulates a couple of MSVC program strings.
// The data is fudged a little bit because the tests use FakeMemoryRegion
@ -194,14 +208,14 @@ static bool RunTests() {
true }
};
map<const UniqueString*, unsigned int> validate_data_1;
validate_data_1[toUniqueString("$T0")] = 0xbfff0012;
validate_data_1[toUniqueString("$T1")] = 0xbfff0020;
validate_data_1[toUniqueString("$T2")] = 0xbfff0019;
validate_data_1[ToUniqueString("$T0")] = 0xbfff0012;
validate_data_1[ToUniqueString("$T1")] = 0xbfff0020;
validate_data_1[ToUniqueString("$T2")] = 0xbfff0019;
validate_data_1[ustr__ZSeip()] = 0xbfff0021;
validate_data_1[ustr__ZSebp()] = 0xbfff0012;
validate_data_1[ustr__ZSesp()] = 0xbfff0024;
validate_data_1[toUniqueString("$L")] = 0xbfff000e;
validate_data_1[toUniqueString("$P")] = 0xbfff0028;
validate_data_1[ToUniqueString("$L")] = 0xbfff000e;
validate_data_1[ToUniqueString("$P")] = 0xbfff0028;
validate_data_1[ustr__ZSebx()] = 0xbffefff7;
validate_data_1[ustr__ZDcbSavedRegs()] = 4;
validate_data_1[ustr__ZDcbParams()] = 4;
@ -270,7 +284,7 @@ static bool RunTests() {
"validate identifier \"%s\", "
"expected %d, observed not found\n",
evaluate_test_set_index, evaluate_test_set_count,
fromUniqueString(identifier), expected_value);
FromUniqueString(identifier), expected_value);
return false;
}
@ -282,13 +296,13 @@ static bool RunTests() {
"validate identifier \"%s\", "
"expected %d, observed %d\n",
evaluate_test_set_index, evaluate_test_set_count,
fromUniqueString(identifier), expected_value, observed_value);
FromUniqueString(identifier), expected_value, observed_value);
return false;
}
// The value must be set in the "assigned" dictionary if it was a
// variable. It must not have been assigned if it was a constant.
bool expected_assigned = fromUniqueString(identifier)[0] == '$';
bool expected_assigned = FromUniqueString(identifier)[0] == '$';
bool observed_assigned = false;
if (assigned.have(identifier)) {
observed_assigned = assigned.get(identifier);
@ -298,7 +312,7 @@ static bool RunTests() {
"validate assignment of \"%s\", "
"expected %d, observed %d\n",
evaluate_test_set_index, evaluate_test_set_count,
fromUniqueString(identifier), expected_assigned,
FromUniqueString(identifier), expected_assigned,
observed_assigned);
return false;
}
@ -331,7 +345,7 @@ static bool RunTests() {
validate_data_2[ustr__ZSeip()] = 0x10000000;
validate_data_2[ustr__ZSebp()] = 0xbfff000c;
validate_data_2[ustr__ZSesp()] = 0xbfff0000;
validate_data_2[toUniqueString("$new")] = 0x10000000;
validate_data_2[ToUniqueString("$new")] = 0x10000000;
validate_data_2[ustr__ZDcbSavedRegs()] = 4;
validate_data_2[ustr__ZDcbParams()] = 4;
validate_data_2[ustr__ZDraSearchStart()] = 0xbfff0020;
@ -356,37 +370,37 @@ static bool RunTests() {
}
}
map<const UniqueString*, unsigned int> dictionary_2_map;
dictionary_2.copy_to_map(&dictionary_2_map);
for (map<const UniqueString*, unsigned int>::iterator v =
validate_data_2.begin();
v != validate_data_2.end(); v++) {
if (!dictionary_2.have(v->first)) {
map<const UniqueString*, unsigned int>::iterator a =
dictionary_2_map.find(v->first);
if (a == dictionary_2_map.end()) {
fprintf(stderr, "FAIL: evaluate for value dictionary check: "
"expected dict[\"%s\"] to be 0x%x, but it was unset\n",
fromUniqueString(v->first), v->second);
FromUniqueString(v->first), v->second);
return false;
} else if (dictionary_2.get(v->first) != v->second) {
} else if (a->second != v->second) {
fprintf(stderr, "FAIL: evaluate for value dictionary check: "
"expected dict[\"%s\"] to be 0x%x, but it was 0x%x\n",
fromUniqueString(v->first), v->second,
dictionary_2.get(v->first));
FromUniqueString(v->first), v->second, a->second);
return false;
}
//TODO: fixme
//dictionary_2.erase(a);
dictionary_2_map.erase(a);
}
/*TODO: fixme
map<const UniqueString*, unsigned int>::iterator remaining =
dictionary_2.begin();
if (remaining != dictionary_2.end()) {
dictionary_2_map.begin();
if (remaining != dictionary_2_map.end()) {
fprintf(stderr, "FAIL: evaluation of test expressions put unexpected "
"values in dictionary:\n");
for (; remaining != dictionary_2.end(); remaining++)
for (; remaining != dictionary_2_map.end(); remaining++)
fprintf(stderr, " dict[\"%s\"] == 0x%x\n",
fromUniqueString(remaining->first), remaining->second);
FromUniqueString(remaining->first), remaining->second);
return false;
}
*/
return true;
}

View File

@ -54,39 +54,39 @@ StackwalkerAMD64::cfi_register_map_[] = {
// flags here really means that the walker should assume they're
// unchanged if the CFI doesn't mention them --- clearly wrong for $rip
// and $rsp.
{ toUniqueString("$rax"), NULL, false,
{ ToUniqueString("$rax"), NULL, false,
StackFrameAMD64::CONTEXT_VALID_RAX, &MDRawContextAMD64::rax },
{ toUniqueString("$rdx"), NULL, false,
{ ToUniqueString("$rdx"), NULL, false,
StackFrameAMD64::CONTEXT_VALID_RDX, &MDRawContextAMD64::rdx },
{ toUniqueString("$rcx"), NULL, false,
{ ToUniqueString("$rcx"), NULL, false,
StackFrameAMD64::CONTEXT_VALID_RCX, &MDRawContextAMD64::rcx },
{ toUniqueString("$rbx"), NULL, true,
{ ToUniqueString("$rbx"), NULL, true,
StackFrameAMD64::CONTEXT_VALID_RBX, &MDRawContextAMD64::rbx },
{ toUniqueString("$rsi"), NULL, false,
{ ToUniqueString("$rsi"), NULL, false,
StackFrameAMD64::CONTEXT_VALID_RSI, &MDRawContextAMD64::rsi },
{ toUniqueString("$rdi"), NULL, false,
{ ToUniqueString("$rdi"), NULL, false,
StackFrameAMD64::CONTEXT_VALID_RDI, &MDRawContextAMD64::rdi },
{ toUniqueString("$rbp"), NULL, true,
{ ToUniqueString("$rbp"), NULL, true,
StackFrameAMD64::CONTEXT_VALID_RBP, &MDRawContextAMD64::rbp },
{ toUniqueString("$rsp"), toUniqueString(".cfa"), false,
{ ToUniqueString("$rsp"), ToUniqueString(".cfa"), false,
StackFrameAMD64::CONTEXT_VALID_RSP, &MDRawContextAMD64::rsp },
{ toUniqueString("$r8"), NULL, false,
{ ToUniqueString("$r8"), NULL, false,
StackFrameAMD64::CONTEXT_VALID_R8, &MDRawContextAMD64::r8 },
{ toUniqueString("$r9"), NULL, false,
{ ToUniqueString("$r9"), NULL, false,
StackFrameAMD64::CONTEXT_VALID_R9, &MDRawContextAMD64::r9 },
{ toUniqueString("$r10"), NULL, false,
{ ToUniqueString("$r10"), NULL, false,
StackFrameAMD64::CONTEXT_VALID_R10, &MDRawContextAMD64::r10 },
{ toUniqueString("$r11"), NULL, false,
{ ToUniqueString("$r11"), NULL, false,
StackFrameAMD64::CONTEXT_VALID_R11, &MDRawContextAMD64::r11 },
{ toUniqueString("$r12"), NULL, true,
{ ToUniqueString("$r12"), NULL, true,
StackFrameAMD64::CONTEXT_VALID_R12, &MDRawContextAMD64::r12 },
{ toUniqueString("$r13"), NULL, true,
{ ToUniqueString("$r13"), NULL, true,
StackFrameAMD64::CONTEXT_VALID_R13, &MDRawContextAMD64::r13 },
{ toUniqueString("$r14"), NULL, true,
{ ToUniqueString("$r14"), NULL, true,
StackFrameAMD64::CONTEXT_VALID_R14, &MDRawContextAMD64::r14 },
{ toUniqueString("$r15"), NULL, true,
{ ToUniqueString("$r15"), NULL, true,
StackFrameAMD64::CONTEXT_VALID_R15, &MDRawContextAMD64::r15 },
{ toUniqueString("$rip"), toUniqueString(".ra"), false,
{ ToUniqueString("$rip"), ToUniqueString(".ra"), false,
StackFrameAMD64::CONTEXT_VALID_RIP, &MDRawContextAMD64::rip },
};

View File

@ -9,7 +9,7 @@
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with tohe
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
@ -82,19 +82,19 @@ StackFrameARM* StackwalkerARM::GetCallerByCFIFrameInfo(
StackFrameARM* last_frame = static_cast<StackFrameARM*>(frames.back());
static const UniqueString *register_names[] = {
toUniqueString("r0"), toUniqueString("r1"),
toUniqueString("r2"), toUniqueString("r3"),
toUniqueString("r4"), toUniqueString("r5"),
toUniqueString("r6"), toUniqueString("r7"),
toUniqueString("r8"), toUniqueString("r9"),
toUniqueString("r10"), toUniqueString("r11"),
toUniqueString("r12"), toUniqueString("sp"),
toUniqueString("lr"), toUniqueString("pc"),
toUniqueString("f0"), toUniqueString("f1"),
toUniqueString("f2"), toUniqueString("f3"),
toUniqueString("f4"), toUniqueString("f5"),
toUniqueString("f6"), toUniqueString("f7"),
toUniqueString("fps"), toUniqueString("cpsr"),
ToUniqueString("r0"), ToUniqueString("r1"),
ToUniqueString("r2"), ToUniqueString("r3"),
ToUniqueString("r4"), ToUniqueString("r5"),
ToUniqueString("r6"), ToUniqueString("r7"),
ToUniqueString("r8"), ToUniqueString("r9"),
ToUniqueString("r10"), ToUniqueString("r11"),
ToUniqueString("r12"), ToUniqueString("sp"),
ToUniqueString("lr"), ToUniqueString("pc"),
ToUniqueString("f0"), ToUniqueString("f1"),
ToUniqueString("f2"), ToUniqueString("f3"),
ToUniqueString("f4"), ToUniqueString("f5"),
ToUniqueString("f6"), ToUniqueString("f7"),
ToUniqueString("fps"), ToUniqueString("cpsr"),
NULL
};

View File

@ -58,23 +58,23 @@ StackwalkerX86::cfi_register_map_[] = {
// restored upon return. But the callee_saves flags here really means
// that the walker should assume they're unchanged if the CFI doesn't
// mention them, which is clearly wrong for $eip and $esp.
{ toUniqueString("$eip"), toUniqueString(".ra"), false,
{ ToUniqueString("$eip"), ToUniqueString(".ra"), false,
StackFrameX86::CONTEXT_VALID_EIP, &MDRawContextX86::eip },
{ toUniqueString("$esp"), toUniqueString(".cfa"), false,
{ ToUniqueString("$esp"), ToUniqueString(".cfa"), false,
StackFrameX86::CONTEXT_VALID_ESP, &MDRawContextX86::esp },
{ toUniqueString("$ebp"), NULL, true,
{ ToUniqueString("$ebp"), NULL, true,
StackFrameX86::CONTEXT_VALID_EBP, &MDRawContextX86::ebp },
{ toUniqueString("$eax"), NULL, false,
{ ToUniqueString("$eax"), NULL, false,
StackFrameX86::CONTEXT_VALID_EAX, &MDRawContextX86::eax },
{ toUniqueString("$ebx"), NULL, true,
{ ToUniqueString("$ebx"), NULL, true,
StackFrameX86::CONTEXT_VALID_EBX, &MDRawContextX86::ebx },
{ toUniqueString("$ecx"), NULL, false,
{ ToUniqueString("$ecx"), NULL, false,
StackFrameX86::CONTEXT_VALID_ECX, &MDRawContextX86::ecx },
{ toUniqueString("$edx"), NULL, false,
{ ToUniqueString("$edx"), NULL, false,
StackFrameX86::CONTEXT_VALID_EDX, &MDRawContextX86::edx },
{ toUniqueString("$esi"), NULL, true,
{ ToUniqueString("$esi"), NULL, true,
StackFrameX86::CONTEXT_VALID_ESI, &MDRawContextX86::esi },
{ toUniqueString("$edi"), NULL, true,
{ ToUniqueString("$edi"), NULL, true,
StackFrameX86::CONTEXT_VALID_EDI, &MDRawContextX86::edi },
};

View File

@ -0,0 +1,44 @@

Microsoft Visual Studio Solution File, Format Version 10.00
# Visual C++ Express 2008
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libglog", "vsprojects\libglog\libglog.vcproj", "{34BD04BD-BC1D-4BFC-AAFC-ED02D9E960F1}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "logging_unittest", "vsprojects\logging_unittest\logging_unittest.vcproj", "{DD0690AA-5E09-46B5-83FD-4B28604CABA8}"
ProjectSection(ProjectDependencies) = postProject
{34BD04BD-BC1D-4BFC-AAFC-ED02D9E960F1} = {34BD04BD-BC1D-4BFC-AAFC-ED02D9E960F1}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libglog_static", "vsprojects\libglog_static\libglog_static.vcproj", "{772C2111-BBBF-49E6-B912-198A7F7A88E5}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "logging_unittest_static", "vsprojects\logging_unittest_static\logging_unittest_static.vcproj", "{9B239B45-84A9-4E06-AC46-8E220CD43974}"
ProjectSection(ProjectDependencies) = postProject
{772C2111-BBBF-49E6-B912-198A7F7A88E5} = {772C2111-BBBF-49E6-B912-198A7F7A88E5}
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{34BD04BD-BC1D-4BFC-AAFC-ED02D9E960F1}.Debug|Win32.ActiveCfg = Debug|Win32
{34BD04BD-BC1D-4BFC-AAFC-ED02D9E960F1}.Debug|Win32.Build.0 = Debug|Win32
{34BD04BD-BC1D-4BFC-AAFC-ED02D9E960F1}.Release|Win32.ActiveCfg = Release|Win32
{34BD04BD-BC1D-4BFC-AAFC-ED02D9E960F1}.Release|Win32.Build.0 = Release|Win32
{DD0690AA-5E09-46B5-83FD-4B28604CABA8}.Debug|Win32.ActiveCfg = Debug|Win32
{DD0690AA-5E09-46B5-83FD-4B28604CABA8}.Debug|Win32.Build.0 = Debug|Win32
{DD0690AA-5E09-46B5-83FD-4B28604CABA8}.Release|Win32.ActiveCfg = Release|Win32
{DD0690AA-5E09-46B5-83FD-4B28604CABA8}.Release|Win32.Build.0 = Release|Win32
{772C2111-BBBF-49E6-B912-198A7F7A88E5}.Debug|Win32.ActiveCfg = Debug|Win32
{772C2111-BBBF-49E6-B912-198A7F7A88E5}.Debug|Win32.Build.0 = Debug|Win32
{772C2111-BBBF-49E6-B912-198A7F7A88E5}.Release|Win32.ActiveCfg = Release|Win32
{772C2111-BBBF-49E6-B912-198A7F7A88E5}.Release|Win32.Build.0 = Release|Win32
{9B239B45-84A9-4E06-AC46-8E220CD43974}.Debug|Win32.ActiveCfg = Debug|Win32
{9B239B45-84A9-4E06-AC46-8E220CD43974}.Debug|Win32.Build.0 = Debug|Win32
{9B239B45-84A9-4E06-AC46-8E220CD43974}.Release|Win32.ActiveCfg = Release|Win32
{9B239B45-84A9-4E06-AC46-8E220CD43974}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

View File

@ -106,6 +106,9 @@
D24997CC16B6C16800E588C5 /* unique_string.cc in Sources */ = {isa = PBXBuildFile; fileRef = D24997CA16B6C16800E588C5 /* unique_string.cc */; };
D24997CD16B6C16800E588C5 /* unique_string.cc in Sources */ = {isa = PBXBuildFile; fileRef = D24997CA16B6C16800E588C5 /* unique_string.cc */; };
D24997CE16B6C16800E588C5 /* unique_string.cc in Sources */ = {isa = PBXBuildFile; fileRef = D24997CA16B6C16800E588C5 /* unique_string.cc */; };
D2499A0016B9BA6A00E588C5 /* unique_string.cc in Sources */ = {isa = PBXBuildFile; fileRef = D24997CA16B6C16800E588C5 /* unique_string.cc */; };
D2499A0216B9BA9600E588C5 /* unique_string.cc in Sources */ = {isa = PBXBuildFile; fileRef = D24997CA16B6C16800E588C5 /* unique_string.cc */; };
D2499A0316B9BA9D00E588C5 /* unique_string.cc in Sources */ = {isa = PBXBuildFile; fileRef = D24997CA16B6C16800E588C5 /* unique_string.cc */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@ -949,6 +952,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
D2499A0216B9BA9600E588C5 /* unique_string.cc in Sources */,
B84A91FB116CF7AF006C210E /* module.cc in Sources */,
B84A91FC116CF7AF006C210E /* stabs_to_module.cc in Sources */,
B84A91FD116CF7AF006C210E /* stabs_to_module_unittest.cc in Sources */,
@ -1009,6 +1013,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
D2499A0316B9BA9D00E588C5 /* unique_string.cc in Sources */,
B88FB0FA116CF00E00407530 /* dwarf_line_to_module.cc in Sources */,
B88FB0FE116CF02400407530 /* module.cc in Sources */,
B88FB0FB116CF00E00407530 /* dwarf_line_to_module_unittest.cc in Sources */,
@ -1019,6 +1024,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
D2499A0016B9BA6A00E588C5 /* unique_string.cc in Sources */,
B88FB112116CF1F000407530 /* dwarf_cu_to_module.cc in Sources */,
B88FB113116CF1F000407530 /* dwarf_cu_to_module_unittest.cc in Sources */,
B88FB114116CF1F000407530 /* language.cc in Sources */,