зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
283e84505d
Коммит
98609c8753
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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 §ion,
|
||||
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, §ion_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");
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 §ion,
|
||||
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
|
|
@ -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
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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_
|
||||
|
|
|
@ -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 -
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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_);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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
|
|
@ -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");
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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_
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 },
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
@ -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 },
|
||||
};
|
||||
|
||||
|
|
44
toolkit/crashreporter/google-breakpad/src/third_party/glog/google-glog.sln
поставляемый
Executable file
44
toolkit/crashreporter/google-breakpad/src/third_party/glog/google-glog.sln
поставляемый
Executable 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
|
|
@ -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 */,
|
||||
|
|
Загрузка…
Ссылка в новой задаче