зеркало из https://github.com/mozilla/gecko-dev.git
bug 848880 - Update to Breakpad SVN r1128. r=upstream
This commit is contained in:
Родитель
75c8a44a47
Коммит
a30e14f4ea
|
@ -1,15 +1,20 @@
|
|||
# HG changeset patch
|
||||
# User Ted Mielczarek <ted@mielczarek.org>
|
||||
# Date 1352220493 18000
|
||||
# Node ID a38d670da97e338234375756313b2f47650e01fb
|
||||
# Parent 201b7c6793586b6b7cfcaa02f4e29700c4c12ef1
|
||||
# Node ID c3b1109dd392c16a9fe4e85da693010966dbbf0b
|
||||
# Parent 03db269a2868503cca9e80f62ce676aabbf967fd
|
||||
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
|
||||
@@ -63,7 +63,7 @@
|
||||
@@ -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();
|
||||
it != functions_.end(); ++it) {
|
||||
delete *it;
|
||||
}
|
||||
|
@ -18,7 +23,17 @@ diff --git a/src/common/module.cc b/src/common/module.cc
|
|||
it != stack_frame_entries_.end(); ++it) {
|
||||
delete *it;
|
||||
}
|
||||
@@ -93,8 +93,14 @@
|
||||
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)
|
||||
AddFunction(*it);
|
||||
}
|
||||
|
||||
|
@ -35,7 +50,16 @@ diff --git a/src/common/module.cc b/src/common/module.cc
|
|||
}
|
||||
|
||||
void Module::AddExtern(Extern *ext) {
|
||||
@@ -111,11 +117,50 @@
|
||||
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());
|
||||
}
|
||||
|
||||
|
@ -86,7 +110,17 @@ 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
|
||||
@@ -155,8 +200,25 @@
|
||||
// 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)
|
||||
vec->push_back(it->second);
|
||||
}
|
||||
|
||||
|
@ -114,19 +148,39 @@ diff --git a/src/common/module.cc b/src/common/module.cc
|
|||
}
|
||||
|
||||
void Module::AssignSourceIds() {
|
||||
@@ -261,7 +323,7 @@
|
||||
// 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 @@
|
||||
stream << "PUBLIC " << hex
|
||||
<< (ext->address - load_address_) << " 0 "
|
||||
<< ext->name << dec << endl;
|
||||
}
|
||||
}
|
||||
|
||||
if (cfi) {
|
||||
if (symbol_data != NO_CFI) {
|
||||
// Write out 'STACK CFI INIT' and 'STACK CFI' records.
|
||||
- vector<StackFrameEntry *>::const_iterator frame_it;
|
||||
+ 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))
|
||||
diff --git a/src/common/module.h b/src/common/module.h
|
||||
--- a/src/common/module.h
|
||||
+++ b/src/common/module.h
|
||||
@@ -168,6 +168,13 @@
|
||||
@@ -164,16 +164,23 @@
|
||||
|
||||
struct ExternCompare {
|
||||
bool operator() (const Extern *lhs,
|
||||
const Extern *rhs) const {
|
||||
return lhs->address < rhs->address;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -140,7 +194,17 @@ 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,
|
||||
@@ -227,6 +234,10 @@
|
||||
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
|
||||
@@ -223,37 +230,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
|
||||
// appropriate interface.)
|
||||
void GetFunctions(vector<Function *> *vec, vector<Function *>::iterator i);
|
||||
|
||||
|
@ -151,7 +215,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
|
||||
@@ -234,6 +245,10 @@
|
||||
// mostly useful for testing; other uses should probably get a more
|
||||
// appropriate interface.)
|
||||
void GetExterns(vector<Extern *> *vec, vector<Extern *>::iterator i);
|
||||
|
||||
|
@ -162,7 +226,14 @@ 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,
|
||||
@@ -248,6 +263,10 @@
|
||||
// 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
|
||||
// a more appropriate interface.)
|
||||
void GetStackFrameEntries(vector<StackFrameEntry *> *vec);
|
||||
|
||||
|
@ -173,7 +244,17 @@ 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
|
||||
@@ -301,6 +320,9 @@
|
||||
// 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
|
||||
@@ -299,25 +318,28 @@
|
||||
typedef map<const string *, File *, CompareStringPtrs> FileByNameMap;
|
||||
|
||||
// A set containing Function structures, sorted by address.
|
||||
typedef set<Function *, FunctionCompare> FunctionSet;
|
||||
|
||||
// A set containing Extern structures, sorted by address.
|
||||
typedef set<Extern *, ExternCompare> ExternSet;
|
||||
|
||||
|
@ -183,7 +264,8 @@ 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.
|
||||
@@ -309,7 +331,7 @@
|
||||
FileByNameMap files_; // This module's source files.
|
||||
FunctionSet functions_; // This module's functions.
|
||||
|
||||
// The module owns all the call frame info entries that have been
|
||||
// added to it.
|
||||
|
@ -192,11 +274,21 @@ 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
|
||||
@@ -334,11 +334,6 @@
|
||||
m.Write(s, true);
|
||||
@@ -329,63 +329,63 @@
|
||||
entry3->rule_changes[0x36682fad3763ffffULL][".cfa"] =
|
||||
"I think I know";
|
||||
m.AddStackFrameEntry(entry3);
|
||||
|
||||
// Check that Write writes STACK CFI records properly.
|
||||
m.Write(s, ALL_SYMBOL_DATA);
|
||||
string contents = s.str();
|
||||
EXPECT_STREQ("MODULE os-name architecture id-string name with spaces\n"
|
||||
- "STACK CFI INIT ddb5f41285aa7757 1486493370dc5073 \n"
|
||||
|
@ -207,7 +299,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"
|
||||
@@ -346,7 +341,12 @@
|
||||
" .cfa: I think I know"
|
||||
" stromboli: his house is in\n"
|
||||
"STACK CFI 47ceb0f63c269d7f"
|
||||
" calzone: the village though"
|
||||
|
@ -221,7 +313,7 @@ diff --git a/src/common/module_unittest.cc b/src/common/module_unittest.cc
|
|||
contents.c_str());
|
||||
|
||||
// Check that GetStackFrameEntries works.
|
||||
@@ -354,10 +354,18 @@
|
||||
vector<Module::StackFrameEntry *> entries;
|
||||
m.GetStackFrameEntries(&entries);
|
||||
ASSERT_EQ(3U, entries.size());
|
||||
// Check first entry.
|
||||
|
@ -244,7 +336,11 @@ 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);
|
||||
@@ -369,18 +377,10 @@
|
||||
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";
|
||||
EXPECT_THAT(entries[1]->initial_rules, ContainerEq(entry2_initial));
|
||||
ASSERT_EQ(0U, entries[1]->rule_changes.size());
|
||||
// Check third entry.
|
||||
|
@ -267,7 +363,17 @@ diff --git a/src/common/module_unittest.cc b/src/common/module_unittest.cc
|
|||
}
|
||||
|
||||
TEST(Construct, UniqueFiles) {
|
||||
@@ -488,3 +488,150 @@
|
||||
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, ALL_SYMBOL_DATA);
|
||||
string contents = s.str();
|
||||
|
||||
EXPECT_STREQ("MODULE " MODULE_OS " " MODULE_ARCH " "
|
||||
MODULE_ID " " MODULE_NAME "\n"
|
||||
"PUBLIC ffff 0 _xyz\n",
|
||||
contents.c_str());
|
||||
}
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,10 +1,10 @@
|
|||
# HG changeset patch
|
||||
# User Ted Mielczarek <ted.mielczarek@gmail.com>
|
||||
# Date 1360255134 18000
|
||||
# Node ID 229852c0b835929a56f207996034cf072307b343
|
||||
# Parent c53ab35ef4dce39824c2d8103f75faccb4c380e9
|
||||
# Node ID d7bfb673574a3afe8b4f76f42fb52e2545770dad
|
||||
# Parent d23a69a6c34a1f1c21e241f37b388c8689f2386b
|
||||
Rework PostfixEvaluator to use a UniqueString type
|
||||
R=ted
|
||||
Patch by Julian Seward <jseward@acm.org>, R=ted
|
||||
|
||||
diff --git a/Makefile.am b/Makefile.am
|
||||
--- a/Makefile.am
|
||||
|
@ -1353,15 +1353,15 @@ diff --git a/src/common/dwarf_cfi_to_module_unittest.cc b/src/common/dwarf_cfi_t
|
|||
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
|
||||
@@ -76,16 +76,17 @@
|
||||
using google_breakpad::ElfClass;
|
||||
using google_breakpad::ElfClass32;
|
||||
@@ -80,16 +80,17 @@
|
||||
using google_breakpad::ElfClass64;
|
||||
using google_breakpad::FindElfSectionByName;
|
||||
using google_breakpad::GetOffset;
|
||||
using google_breakpad::IsValidElf;
|
||||
using google_breakpad::Module;
|
||||
#ifndef NO_STABS_SUPPORT
|
||||
using google_breakpad::StabsToModule;
|
||||
#endif
|
||||
+using google_breakpad::UniqueString;
|
||||
using google_breakpad::scoped_ptr;
|
||||
|
||||
|
@ -1371,7 +1371,7 @@ diff --git a/src/common/linux/dump_symbols.cc b/src/common/linux/dump_symbols.cc
|
|||
// Wrapper class to make sure opened file is closed.
|
||||
//
|
||||
class FDWrapper {
|
||||
@@ -264,17 +265,17 @@
|
||||
@@ -270,17 +271,17 @@
|
||||
|
||||
// Fill REGISTER_NAMES with the register names appropriate to the
|
||||
// machine architecture given in HEADER, indexed by the register
|
||||
|
@ -1390,7 +1390,7 @@ diff --git a/src/common/linux/dump_symbols.cc b/src/common/linux/dump_symbols.cc
|
|||
*register_names = DwarfCFIToModule::RegisterNames::ARM();
|
||||
return true;
|
||||
case EM_X86_64:
|
||||
@@ -292,17 +293,17 @@
|
||||
@@ -298,17 +299,17 @@
|
||||
const typename ElfClass::Shdr* section,
|
||||
const bool eh_frame,
|
||||
const typename ElfClass::Shdr* got_section,
|
||||
|
@ -2357,8 +2357,8 @@ diff --git a/src/processor/cfi_frame_info.cc b/src/processor/cfi_frame_info.cc
|
|||
|
||||
namespace google_breakpad {
|
||||
|
||||
template<typename V>
|
||||
@@ -61,33 +62,33 @@
|
||||
#ifdef _WIN32
|
||||
@@ -65,33 +66,33 @@
|
||||
V cfa;
|
||||
working = registers;
|
||||
if (!evaluator.EvaluateForValue(cfa_rule_, &cfa))
|
||||
|
@ -2396,7 +2396,7 @@ diff --git a/src/processor/cfi_frame_info.cc b/src/processor/cfi_frame_info.cc
|
|||
template bool CFIFrameInfo::FindCallerRegs<uint32_t>(
|
||||
const RegisterValueMap<uint32_t> ®isters,
|
||||
const MemoryRegion &memory,
|
||||
@@ -103,81 +104,98 @@
|
||||
@@ -107,81 +108,98 @@
|
||||
if (!cfa_rule_.invalid()) {
|
||||
stream << ".cfa: " << cfa_rule_;
|
||||
}
|
||||
|
@ -4397,7 +4397,7 @@ diff --git a/src/tools/mac/dump_syms/dump_syms.xcodeproj/project.pbxproj b/src/t
|
|||
B88FB0D7116CEC0600407530 /* dwarf_line_to_module_unittest.cc */,
|
||||
B88FAE221166603300407530 /* language.cc */,
|
||||
B88FAE231166603300407530 /* language.h */,
|
||||
@@ -937,16 +947,17 @@
|
||||
@@ -940,16 +950,17 @@
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
|
@ -4415,7 +4415,7 @@ diff --git a/src/tools/mac/dump_syms/dump_syms.xcodeproj/project.pbxproj b/src/t
|
|||
};
|
||||
B88FAF2C116A591D00407530 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
@@ -980,56 +991,60 @@
|
||||
@@ -983,56 +994,60 @@
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
B88FB0B6116CEABF00407530 /* Sources */ = {
|
||||
|
@ -4476,7 +4476,7 @@ diff --git a/src/tools/mac/dump_syms/dump_syms.xcodeproj/project.pbxproj b/src/t
|
|||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
B88FB13D116CF38300407530 /* cfi_assembler.cc in Sources */,
|
||||
@@ -1083,16 +1098,17 @@
|
||||
@@ -1086,16 +1101,17 @@
|
||||
B88FAE261166603300407530 /* dwarf_cu_to_module.cc in Sources */,
|
||||
B88FAE271166603300407530 /* dwarf_line_to_module.cc in Sources */,
|
||||
B88FAE281166603300407530 /* language.cc in Sources */,
|
||||
|
|
|
@ -1,15 +1,20 @@
|
|||
# HG changeset patch
|
||||
# User Ted Mielczarek <ted.mielczarek@gmail.com>
|
||||
# Date 1360255134 18000
|
||||
# Node ID 97572beba4ad7fa4f76c3d1871d2001839a65b32
|
||||
# Parent 229852c0b835929a56f207996034cf072307b343
|
||||
# Node ID 294ce0d64d35a90be8ea91b719ead8b82aed29f7
|
||||
# Parent d7bfb673574a3afe8b4f76f42fb52e2545770dad
|
||||
Rework PostfixEvaluator to use UniqueStringMap
|
||||
R=ted
|
||||
Patch by Julian Seward <jseward@acm.org>, R=ted
|
||||
|
||||
diff --git a/src/common/unique_string.h b/src/common/unique_string.h
|
||||
--- a/src/common/unique_string.h
|
||||
+++ b/src/common/unique_string.h
|
||||
@@ -30,6 +30,7 @@
|
||||
@@ -25,16 +25,17 @@
|
||||
// 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_
|
||||
|
||||
|
@ -17,7 +22,17 @@ diff --git a/src/common/unique_string.h b/src/common/unique_string.h
|
|||
#include <string>
|
||||
#include "common/using_std_string.h"
|
||||
|
||||
@@ -234,6 +235,107 @@
|
||||
namespace google_breakpad {
|
||||
|
||||
// Abstract type
|
||||
class UniqueString;
|
||||
|
||||
@@ -229,11 +230,112 @@
|
||||
|
||||
// ".ra"
|
||||
inline static const UniqueString* ustr__ZDra() {
|
||||
static const UniqueString* us = NULL;
|
||||
if (!us) us = ToUniqueString(".ra");
|
||||
return us;
|
||||
}
|
||||
|
||||
|
@ -128,7 +143,12 @@ diff --git a/src/common/unique_string.h b/src/common/unique_string.h
|
|||
diff --git a/src/processor/basic_source_line_resolver_unittest.cc b/src/processor/basic_source_line_resolver_unittest.cc
|
||||
--- a/src/processor/basic_source_line_resolver_unittest.cc
|
||||
+++ b/src/processor/basic_source_line_resolver_unittest.cc
|
||||
@@ -29,6 +29,7 @@
|
||||
@@ -24,16 +24,17 @@
|
||||
// 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 <stdio.h>
|
||||
|
||||
|
@ -136,7 +156,17 @@ diff --git a/src/processor/basic_source_line_resolver_unittest.cc b/src/processo
|
|||
#include <string>
|
||||
|
||||
#include "breakpad_googletest_includes.h"
|
||||
@@ -52,6 +53,7 @@
|
||||
#include "common/scoped_ptr.h"
|
||||
#include "common/using_std_string.h"
|
||||
#include "google_breakpad/processor/basic_source_line_resolver.h"
|
||||
#include "google_breakpad/processor/code_module.h"
|
||||
#include "google_breakpad/processor/stack_frame.h"
|
||||
@@ -47,16 +48,17 @@
|
||||
|
||||
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;
|
||||
|
@ -144,7 +174,17 @@ diff --git a/src/processor/basic_source_line_resolver_unittest.cc b/src/processo
|
|||
using google_breakpad::WindowsFrameInfo;
|
||||
using google_breakpad::linked_ptr;
|
||||
using google_breakpad::scoped_ptr;
|
||||
@@ -118,9 +120,12 @@
|
||||
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;
|
||||
@@ -113,27 +115,30 @@
|
||||
};
|
||||
|
||||
// Verify that, for every association in ACTUAL, EXPECTED has the same
|
||||
// association. (That is, ACTUAL's associations should be a subset of
|
||||
// EXPECTED's.) Also verify that ACTUAL has associations for ".ra" and
|
||||
// ".cfa".
|
||||
static bool VerifyRegisters(
|
||||
const char *file, int line,
|
||||
|
@ -160,7 +200,7 @@ diff --git a/src/processor/basic_source_line_resolver_unittest.cc b/src/processo
|
|||
a = actual.find(ustr__ZDcfa());
|
||||
if (a == actual.end())
|
||||
return false;
|
||||
@@ -128,7 +133,7 @@
|
||||
a = actual.find(ustr__ZDra());
|
||||
if (a == actual.end())
|
||||
return false;
|
||||
for (a = actual.begin(); a != actual.end(); a++) {
|
||||
|
@ -169,7 +209,17 @@ diff --git a/src/processor/basic_source_line_resolver_unittest.cc b/src/processo
|
|||
expected.find(a->first);
|
||||
if (e == expected.end()) {
|
||||
fprintf(stderr, "%s:%d: unexpected register '%s' recovered, value 0x%x\n",
|
||||
@@ -263,7 +268,7 @@
|
||||
file, line, FromUniqueString(a->first), a->second);
|
||||
return false;
|
||||
}
|
||||
if (e->second != a->second) {
|
||||
fprintf(stderr,
|
||||
@@ -258,86 +263,86 @@
|
||||
|
||||
frame.instruction = 0x3e9f;
|
||||
frame.module = &module1;
|
||||
cfi_frame_info.reset(resolver.FindCFIFrameInfo(&frame));
|
||||
ASSERT_FALSE(cfi_frame_info.get());
|
||||
|
||||
CFIFrameInfo::RegisterValueMap<uint32_t> current_registers;
|
||||
CFIFrameInfo::RegisterValueMap<uint32_t> caller_registers;
|
||||
|
@ -178,7 +228,14 @@ diff --git a/src/processor/basic_source_line_resolver_unittest.cc b/src/processo
|
|||
MockMemoryRegion memory;
|
||||
|
||||
// Regardless of which instruction evaluation takes place at, it
|
||||
@@ -278,11 +283,11 @@
|
||||
// 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;
|
||||
current_registers.clear();
|
||||
|
@ -195,7 +252,9 @@ diff --git a/src/processor/basic_source_line_resolver_unittest.cc b/src/processo
|
|||
cfi_frame_info.reset(resolver.FindCFIFrameInfo(&frame));
|
||||
ASSERT_TRUE(cfi_frame_info.get());
|
||||
ASSERT_TRUE(cfi_frame_info.get()
|
||||
@@ -292,7 +297,7 @@
|
||||
->FindCallerRegs<uint32_t>(current_registers, memory,
|
||||
&caller_registers));
|
||||
ASSERT_TRUE(VerifyRegisters(__FILE__, __LINE__,
|
||||
expected_caller_registers, caller_registers));
|
||||
|
||||
frame.instruction = 0x3d41;
|
||||
|
@ -204,7 +263,9 @@ diff --git a/src/processor/basic_source_line_resolver_unittest.cc b/src/processo
|
|||
cfi_frame_info.reset(resolver.FindCFIFrameInfo(&frame));
|
||||
ASSERT_TRUE(cfi_frame_info.get());
|
||||
ASSERT_TRUE(cfi_frame_info.get()
|
||||
@@ -302,7 +307,7 @@
|
||||
->FindCallerRegs<uint32_t>(current_registers, memory,
|
||||
&caller_registers));
|
||||
ASSERT_TRUE(VerifyRegisters(__FILE__, __LINE__,
|
||||
expected_caller_registers, caller_registers));
|
||||
|
||||
frame.instruction = 0x3d43;
|
||||
|
@ -213,7 +274,9 @@ diff --git a/src/processor/basic_source_line_resolver_unittest.cc b/src/processo
|
|||
cfi_frame_info.reset(resolver.FindCFIFrameInfo(&frame));
|
||||
ASSERT_TRUE(cfi_frame_info.get());
|
||||
ASSERT_TRUE(cfi_frame_info.get()
|
||||
@@ -312,7 +317,7 @@
|
||||
->FindCallerRegs<uint32_t>(current_registers, memory,
|
||||
&caller_registers));
|
||||
VerifyRegisters(__FILE__, __LINE__,
|
||||
expected_caller_registers, caller_registers);
|
||||
|
||||
frame.instruction = 0x3d54;
|
||||
|
@ -222,7 +285,9 @@ diff --git a/src/processor/basic_source_line_resolver_unittest.cc b/src/processo
|
|||
cfi_frame_info.reset(resolver.FindCFIFrameInfo(&frame));
|
||||
ASSERT_TRUE(cfi_frame_info.get());
|
||||
ASSERT_TRUE(cfi_frame_info.get()
|
||||
@@ -322,7 +327,7 @@
|
||||
->FindCallerRegs<uint32_t>(current_registers, memory,
|
||||
&caller_registers));
|
||||
VerifyRegisters(__FILE__, __LINE__,
|
||||
expected_caller_registers, caller_registers);
|
||||
|
||||
frame.instruction = 0x3d5a;
|
||||
|
@ -231,7 +296,9 @@ diff --git a/src/processor/basic_source_line_resolver_unittest.cc b/src/processo
|
|||
cfi_frame_info.reset(resolver.FindCFIFrameInfo(&frame));
|
||||
ASSERT_TRUE(cfi_frame_info.get());
|
||||
ASSERT_TRUE(cfi_frame_info.get()
|
||||
@@ -332,7 +337,7 @@
|
||||
->FindCallerRegs<uint32_t>(current_registers, memory,
|
||||
&caller_registers));
|
||||
VerifyRegisters(__FILE__, __LINE__,
|
||||
expected_caller_registers, caller_registers);
|
||||
|
||||
frame.instruction = 0x3d84;
|
||||
|
@ -240,10 +307,20 @@ diff --git a/src/processor/basic_source_line_resolver_unittest.cc b/src/processo
|
|||
cfi_frame_info.reset(resolver.FindCFIFrameInfo(&frame));
|
||||
ASSERT_TRUE(cfi_frame_info.get());
|
||||
ASSERT_TRUE(cfi_frame_info.get()
|
||||
->FindCallerRegs<uint32_t>(current_registers, memory,
|
||||
&caller_registers));
|
||||
VerifyRegisters(__FILE__, __LINE__,
|
||||
expected_caller_registers, caller_registers);
|
||||
|
||||
diff --git a/src/processor/cfi_frame_info-inl.h b/src/processor/cfi_frame_info-inl.h
|
||||
--- a/src/processor/cfi_frame_info-inl.h
|
||||
+++ b/src/processor/cfi_frame_info-inl.h
|
||||
@@ -40,30 +40,29 @@
|
||||
@@ -35,64 +35,64 @@
|
||||
|
||||
#ifndef PROCESSOR_CFI_FRAME_INFO_INL_H_
|
||||
#define PROCESSOR_CFI_FRAME_INFO_INL_H_
|
||||
|
||||
#include <string.h>
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
|
@ -281,7 +358,8 @@ diff --git a/src/processor/cfi_frame_info-inl.h b/src/processor/cfi_frame_info-i
|
|||
return false;
|
||||
|
||||
// Populate *caller_context with the values the rules placed in
|
||||
@@ -72,12 +71,12 @@
|
||||
// caller_registers.
|
||||
memset(caller_context, 0xda, sizeof(*caller_context));
|
||||
*caller_validity = 0;
|
||||
for (size_t i = 0; i < map_size_; i++) {
|
||||
const RegisterSet &r = register_map_[i];
|
||||
|
@ -298,7 +376,7 @@ diff --git a/src/processor/cfi_frame_info-inl.h b/src/processor/cfi_frame_info-i
|
|||
*caller_validity |= r.validity_flag;
|
||||
continue;
|
||||
}
|
||||
@@ -85,9 +84,10 @@
|
||||
|
||||
// Did the rules provide a value for this register under its
|
||||
// alternate name?
|
||||
if (r.alternate_name) {
|
||||
|
@ -312,10 +390,20 @@ diff --git a/src/processor/cfi_frame_info-inl.h b/src/processor/cfi_frame_info-i
|
|||
*caller_validity |= r.validity_flag;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Is this a callee-saves register? The walker assumes that these
|
||||
// still hold the caller's value if the CFI doesn't mention them.
|
||||
//
|
||||
diff --git a/src/processor/cfi_frame_info.cc b/src/processor/cfi_frame_info.cc
|
||||
--- a/src/processor/cfi_frame_info.cc
|
||||
+++ b/src/processor/cfi_frame_info.cc
|
||||
@@ -67,7 +67,7 @@
|
||||
@@ -66,33 +66,33 @@
|
||||
V cfa;
|
||||
working = registers;
|
||||
if (!evaluator.EvaluateForValue(cfa_rule_, &cfa))
|
||||
return false;
|
||||
|
||||
// Then, compute the return address.
|
||||
V ra;
|
||||
working = registers;
|
||||
|
@ -324,7 +412,8 @@ diff --git a/src/processor/cfi_frame_info.cc b/src/processor/cfi_frame_info.cc
|
|||
if (!evaluator.EvaluateForValue(ra_rule_, &ra))
|
||||
return false;
|
||||
|
||||
@@ -76,14 +76,14 @@
|
||||
// Now, compute values for all the registers register_rules_ mentions.
|
||||
for (RuleMap::const_iterator it = register_rules_.begin();
|
||||
it != register_rules_.end(); it++) {
|
||||
V value;
|
||||
working = registers;
|
||||
|
@ -343,10 +432,20 @@ diff --git a/src/processor/cfi_frame_info.cc b/src/processor/cfi_frame_info.cc
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Explicit instantiations for 32-bit and 64-bit architectures.
|
||||
template bool CFIFrameInfo::FindCallerRegs<uint32_t>(
|
||||
const RegisterValueMap<uint32_t> ®isters,
|
||||
const MemoryRegion &memory,
|
||||
diff --git a/src/processor/cfi_frame_info.h b/src/processor/cfi_frame_info.h
|
||||
--- a/src/processor/cfi_frame_info.h
|
||||
+++ b/src/processor/cfi_frame_info.h
|
||||
@@ -69,7 +69,7 @@
|
||||
@@ -64,17 +64,17 @@
|
||||
// changes given by the 'STACK CFI' records up to our instruction's
|
||||
// address. Then, use the FindCallerRegs member function to apply the
|
||||
// rules to the callee frame's register values, yielding the caller
|
||||
// frame's register values.
|
||||
class CFIFrameInfo {
|
||||
public:
|
||||
// A map from register names onto values.
|
||||
template<typename ValueType> class RegisterValueMap:
|
||||
|
@ -355,10 +454,20 @@ diff --git a/src/processor/cfi_frame_info.h b/src/processor/cfi_frame_info.h
|
|||
|
||||
// Set the expression for computing a call frame address, return
|
||||
// address, or register's value. At least the CFA rule and the RA
|
||||
// rule must be set before calling FindCallerRegs.
|
||||
void SetCFARule(const Module::Expr& rule) { cfa_rule_ = rule; }
|
||||
void SetRARule(const Module::Expr& rule) { ra_rule_ = rule; }
|
||||
void SetRegisterRule(const UniqueString* register_name,
|
||||
const Module::Expr& rule) {
|
||||
diff --git a/src/processor/cfi_frame_info_unittest.cc b/src/processor/cfi_frame_info_unittest.cc
|
||||
--- a/src/processor/cfi_frame_info_unittest.cc
|
||||
+++ b/src/processor/cfi_frame_info_unittest.cc
|
||||
@@ -116,9 +116,8 @@
|
||||
@@ -111,19 +111,18 @@
|
||||
|
||||
TEST_F(Simple, SetCFAAndRARule) {
|
||||
ExpectNoMemoryReferences();
|
||||
|
||||
cfi.SetCFARule(Module::Expr("330903416631436410"));
|
||||
cfi.SetRARule(Module::Expr("5870666104170902211"));
|
||||
ASSERT_TRUE(cfi.FindCallerRegs<uint64_t>(registers, memory,
|
||||
&caller_registers));
|
||||
|
@ -370,7 +479,17 @@ diff --git a/src/processor/cfi_frame_info_unittest.cc b/src/processor/cfi_frame_
|
|||
|
||||
ASSERT_EQ(".cfa: 330903416631436410 .ra: 5870666104170902211",
|
||||
cfi.Serialize());
|
||||
@@ -141,13 +140,12 @@
|
||||
}
|
||||
|
||||
TEST_F(Simple, SetManyRules) {
|
||||
ExpectNoMemoryReferences();
|
||||
|
||||
@@ -136,23 +135,22 @@
|
||||
const UniqueString* reg4 = ToUniqueString("uncopyrightables");
|
||||
|
||||
cfi.SetRegisterRule(reg1, Module::Expr(".cfa 54370437 *"));
|
||||
cfi.SetRegisterRule(reg2, Module::Expr("24076308 .cfa +"));
|
||||
cfi.SetRegisterRule(reg3, Module::Expr(".cfa 29801007 -"));
|
||||
cfi.SetRegisterRule(reg4, Module::Expr("92642917 .cfa /"));
|
||||
ASSERT_TRUE(cfi.FindCallerRegs<uint64_t>(registers, memory,
|
||||
&caller_registers));
|
||||
|
@ -390,7 +509,17 @@ diff --git a/src/processor/cfi_frame_info_unittest.cc b/src/processor/cfi_frame_
|
|||
ASSERT_EQ(".cfa: $temp1 68737028 = $temp2 61072337 = $temp1 $temp2 - "
|
||||
".ra: .cfa 99804755 + "
|
||||
"pubvexingfjordschmaltzy: .cfa 29801007 - "
|
||||
@@ -165,9 +163,8 @@
|
||||
"register1: .cfa 54370437 * "
|
||||
"uncopyrightables: 92642917 .cfa / "
|
||||
"vodkathumbscrewingly: 24076308 .cfa +",
|
||||
cfi.Serialize());
|
||||
}
|
||||
@@ -160,19 +158,18 @@
|
||||
TEST_F(Simple, RulesOverride) {
|
||||
ExpectNoMemoryReferences();
|
||||
|
||||
cfi.SetCFARule(Module::Expr("330903416631436410"));
|
||||
cfi.SetRARule(Module::Expr("5870666104170902211"));
|
||||
cfi.SetCFARule(Module::Expr("2828089117179001"));
|
||||
ASSERT_TRUE(cfi.FindCallerRegs<uint64_t>(registers, memory,
|
||||
&caller_registers));
|
||||
|
@ -402,7 +531,17 @@ diff --git a/src/processor/cfi_frame_info_unittest.cc b/src/processor/cfi_frame_
|
|||
ASSERT_EQ(".cfa: 2828089117179001 .ra: 5870666104170902211",
|
||||
cfi.Serialize());
|
||||
}
|
||||
@@ -201,15 +198,14 @@
|
||||
|
||||
class Scope: public CFIFixture, public Test { };
|
||||
|
||||
// There should be no value for .cfa in scope when evaluating the CFA rule.
|
||||
TEST_F(Scope, CFALacksCFA) {
|
||||
@@ -196,37 +193,35 @@
|
||||
|
||||
// The current frame's registers should be in scope when evaluating
|
||||
// the CFA rule.
|
||||
TEST_F(Scope, CFASeesCurrentRegs) {
|
||||
ExpectNoMemoryReferences();
|
||||
|
||||
const UniqueString* reg1 = ToUniqueString(".baraminology");
|
||||
const UniqueString* reg2 = ToUniqueString(".ornithorhynchus");
|
||||
|
@ -421,7 +560,10 @@ diff --git a/src/processor/cfi_frame_info_unittest.cc b/src/processor/cfi_frame_
|
|||
}
|
||||
|
||||
// .cfa should be in scope in the return address expression.
|
||||
@@ -220,8 +216,7 @@
|
||||
TEST_F(Scope, RASeesCFA) {
|
||||
ExpectNoMemoryReferences();
|
||||
|
||||
cfi.SetCFARule(Module::Expr("48364076"));
|
||||
cfi.SetRARule(Module::Expr(".cfa"));
|
||||
ASSERT_TRUE(cfi.FindCallerRegs<uint64_t>(registers, memory,
|
||||
&caller_registers));
|
||||
|
@ -431,7 +573,17 @@ diff --git a/src/processor/cfi_frame_info_unittest.cc b/src/processor/cfi_frame_
|
|||
}
|
||||
|
||||
// There should be no value for .ra in scope when evaluating the CFA rule.
|
||||
@@ -241,12 +236,11 @@
|
||||
TEST_F(Scope, RALacksRA) {
|
||||
ExpectNoMemoryReferences();
|
||||
|
||||
cfi.SetCFARule(Module::Expr("0"));
|
||||
cfi.SetRARule(Module::Expr(".ra"));
|
||||
@@ -236,36 +231,34 @@
|
||||
|
||||
// The current frame's registers should be in scope in the return
|
||||
// address expression.
|
||||
TEST_F(Scope, RASeesCurrentRegs) {
|
||||
ExpectNoMemoryReferences();
|
||||
|
||||
cfi.SetCFARule(Module::Expr("10359370"));
|
||||
const UniqueString* reg1 = ToUniqueString("noachian");
|
||||
|
@ -446,7 +598,12 @@ diff --git a/src/processor/cfi_frame_info_unittest.cc b/src/processor/cfi_frame_
|
|||
}
|
||||
|
||||
// .cfa should be in scope for register rules.
|
||||
@@ -259,8 +253,7 @@
|
||||
TEST_F(Scope, RegistersSeeCFA) {
|
||||
ExpectNoMemoryReferences();
|
||||
|
||||
cfi.SetCFARule(Module::Expr("6515179"));
|
||||
cfi.SetRARule(Module::Expr(".cfa"));
|
||||
const UniqueString* reg1 = ToUniqueString("rogerian");
|
||||
cfi.SetRegisterRule(reg1, Module::Expr(".cfa"));
|
||||
ASSERT_TRUE(cfi.FindCallerRegs<uint64_t>(registers, memory,
|
||||
&caller_registers));
|
||||
|
@ -456,7 +613,17 @@ diff --git a/src/processor/cfi_frame_info_unittest.cc b/src/processor/cfi_frame_
|
|||
}
|
||||
|
||||
// The return address should not be in scope for register rules.
|
||||
@@ -281,17 +274,16 @@
|
||||
TEST_F(Scope, RegsLackRA) {
|
||||
ExpectNoMemoryReferences();
|
||||
|
||||
cfi.SetCFARule(Module::Expr("42740329"));
|
||||
cfi.SetRARule(Module::Expr("27045204"));
|
||||
@@ -276,27 +269,26 @@
|
||||
}
|
||||
|
||||
// Register rules can see the current frame's register values.
|
||||
TEST_F(Scope, RegsSeeRegs) {
|
||||
ExpectNoMemoryReferences();
|
||||
|
||||
const UniqueString* reg1 = ToUniqueString("$r1");
|
||||
const UniqueString* reg2 = ToUniqueString("$r2");
|
||||
|
@ -478,7 +645,17 @@ diff --git a/src/processor/cfi_frame_info_unittest.cc b/src/processor/cfi_frame_
|
|||
}
|
||||
|
||||
// Each rule's temporaries are separate.
|
||||
@@ -445,12 +437,12 @@
|
||||
TEST_F(Scope, SeparateTempsRA) {
|
||||
ExpectNoMemoryReferences();
|
||||
|
||||
cfi.SetCFARule(Module::Expr("$temp1 76569129 = $temp1"));
|
||||
cfi.SetRARule(Module::Expr("0"));
|
||||
@@ -440,39 +432,39 @@
|
||||
CFIFrameInfoParseHandler handler;
|
||||
};
|
||||
|
||||
class ParseHandler: public ParseHandlerFixture, public Test { };
|
||||
|
||||
TEST_F(ParseHandler, CFARARule) {
|
||||
handler.CFARule("reg-for-cfa");
|
||||
handler.RARule("reg-for-ra");
|
||||
|
@ -495,7 +672,7 @@ diff --git a/src/processor/cfi_frame_info_unittest.cc b/src/processor/cfi_frame_
|
|||
}
|
||||
|
||||
TEST_F(ParseHandler, RegisterRules) {
|
||||
@@ -458,16 +450,16 @@
|
||||
handler.CFARule("reg-for-cfa");
|
||||
handler.RARule("reg-for-ra");
|
||||
handler.RegisterRule(ToUniqueString("reg1"), "reg-for-reg1");
|
||||
handler.RegisterRule(ToUniqueString("reg2"), "reg-for-reg2");
|
||||
|
@ -520,10 +697,20 @@ diff --git a/src/processor/cfi_frame_info_unittest.cc b/src/processor/cfi_frame_
|
|||
}
|
||||
|
||||
struct SimpleCFIWalkerFixture {
|
||||
struct RawContext {
|
||||
uint64_t r0, r1, r2, r3, r4, sp, pc;
|
||||
};
|
||||
enum Validity {
|
||||
R0_VALID = 0x01,
|
||||
diff --git a/src/processor/fast_source_line_resolver_unittest.cc b/src/processor/fast_source_line_resolver_unittest.cc
|
||||
--- a/src/processor/fast_source_line_resolver_unittest.cc
|
||||
+++ b/src/processor/fast_source_line_resolver_unittest.cc
|
||||
@@ -64,6 +64,7 @@
|
||||
@@ -59,16 +59,17 @@
|
||||
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;
|
||||
|
@ -531,7 +718,17 @@ diff --git a/src/processor/fast_source_line_resolver_unittest.cc b/src/processor
|
|||
using google_breakpad::WindowsFrameInfo;
|
||||
using google_breakpad::linked_ptr;
|
||||
using google_breakpad::scoped_ptr;
|
||||
@@ -130,9 +131,12 @@
|
||||
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;
|
||||
@@ -125,27 +126,30 @@
|
||||
};
|
||||
|
||||
// Verify that, for every association in ACTUAL, EXPECTED has the same
|
||||
// association. (That is, ACTUAL's associations should be a subset of
|
||||
// EXPECTED's.) Also verify that ACTUAL has associations for ".ra" and
|
||||
// ".cfa".
|
||||
static bool VerifyRegisters(
|
||||
const char *file, int line,
|
||||
|
@ -547,7 +744,7 @@ diff --git a/src/processor/fast_source_line_resolver_unittest.cc b/src/processor
|
|||
a = actual.find(ustr__ZDcfa());
|
||||
if (a == actual.end())
|
||||
return false;
|
||||
@@ -140,7 +144,7 @@
|
||||
a = actual.find(ustr__ZDra());
|
||||
if (a == actual.end())
|
||||
return false;
|
||||
for (a = actual.begin(); a != actual.end(); a++) {
|
||||
|
@ -556,7 +753,17 @@ diff --git a/src/processor/fast_source_line_resolver_unittest.cc b/src/processor
|
|||
expected.find(a->first);
|
||||
if (e == expected.end()) {
|
||||
fprintf(stderr, "%s:%d: unexpected register '%s' recovered, value 0x%x\n",
|
||||
@@ -291,13 +295,14 @@
|
||||
file, line, FromUniqueString(a->first), a->second);
|
||||
return false;
|
||||
}
|
||||
if (e->second != a->second) {
|
||||
fprintf(stderr,
|
||||
@@ -286,86 +290,87 @@
|
||||
|
||||
frame.instruction = 0x3e9f;
|
||||
frame.module = &module1;
|
||||
cfi_frame_info.reset(fast_resolver.FindCFIFrameInfo(&frame));
|
||||
ASSERT_FALSE(cfi_frame_info.get());
|
||||
|
||||
CFIFrameInfo::RegisterValueMap<uint32_t> current_registers;
|
||||
CFIFrameInfo::RegisterValueMap<uint32_t> caller_registers;
|
||||
|
@ -573,7 +780,8 @@ diff --git a/src/processor/fast_source_line_resolver_unittest.cc b/src/processor
|
|||
expected_caller_registers[ustr__ZSebp()] = 0x10038;
|
||||
expected_caller_registers[ustr__ZSebx()] = 0x98ecadc3;
|
||||
expected_caller_registers[ustr__ZSesi()] = 0x878f7524;
|
||||
@@ -306,11 +311,11 @@
|
||||
expected_caller_registers[ustr__ZSedi()] = 0x6312f9a5;
|
||||
|
||||
frame.instruction = 0x3d40;
|
||||
frame.module = &module1;
|
||||
current_registers.clear();
|
||||
|
@ -590,7 +798,9 @@ diff --git a/src/processor/fast_source_line_resolver_unittest.cc b/src/processor
|
|||
cfi_frame_info.reset(fast_resolver.FindCFIFrameInfo(&frame));
|
||||
ASSERT_TRUE(cfi_frame_info.get());
|
||||
ASSERT_TRUE(cfi_frame_info.get()
|
||||
@@ -320,7 +325,7 @@
|
||||
->FindCallerRegs<uint32_t>(current_registers, memory,
|
||||
&caller_registers));
|
||||
ASSERT_TRUE(VerifyRegisters(__FILE__, __LINE__,
|
||||
expected_caller_registers, caller_registers));
|
||||
|
||||
frame.instruction = 0x3d41;
|
||||
|
@ -599,7 +809,9 @@ diff --git a/src/processor/fast_source_line_resolver_unittest.cc b/src/processor
|
|||
cfi_frame_info.reset(fast_resolver.FindCFIFrameInfo(&frame));
|
||||
ASSERT_TRUE(cfi_frame_info.get());
|
||||
ASSERT_TRUE(cfi_frame_info.get()
|
||||
@@ -330,7 +335,7 @@
|
||||
->FindCallerRegs<uint32_t>(current_registers, memory,
|
||||
&caller_registers));
|
||||
ASSERT_TRUE(VerifyRegisters(__FILE__, __LINE__,
|
||||
expected_caller_registers, caller_registers));
|
||||
|
||||
frame.instruction = 0x3d43;
|
||||
|
@ -608,7 +820,9 @@ diff --git a/src/processor/fast_source_line_resolver_unittest.cc b/src/processor
|
|||
cfi_frame_info.reset(fast_resolver.FindCFIFrameInfo(&frame));
|
||||
ASSERT_TRUE(cfi_frame_info.get());
|
||||
ASSERT_TRUE(cfi_frame_info.get()
|
||||
@@ -340,7 +345,7 @@
|
||||
->FindCallerRegs<uint32_t>(current_registers, memory,
|
||||
&caller_registers));
|
||||
VerifyRegisters(__FILE__, __LINE__,
|
||||
expected_caller_registers, caller_registers);
|
||||
|
||||
frame.instruction = 0x3d54;
|
||||
|
@ -617,7 +831,9 @@ diff --git a/src/processor/fast_source_line_resolver_unittest.cc b/src/processor
|
|||
cfi_frame_info.reset(fast_resolver.FindCFIFrameInfo(&frame));
|
||||
ASSERT_TRUE(cfi_frame_info.get());
|
||||
ASSERT_TRUE(cfi_frame_info.get()
|
||||
@@ -350,7 +355,7 @@
|
||||
->FindCallerRegs<uint32_t>(current_registers, memory,
|
||||
&caller_registers));
|
||||
VerifyRegisters(__FILE__, __LINE__,
|
||||
expected_caller_registers, caller_registers);
|
||||
|
||||
frame.instruction = 0x3d5a;
|
||||
|
@ -626,7 +842,9 @@ diff --git a/src/processor/fast_source_line_resolver_unittest.cc b/src/processor
|
|||
cfi_frame_info.reset(fast_resolver.FindCFIFrameInfo(&frame));
|
||||
ASSERT_TRUE(cfi_frame_info.get());
|
||||
ASSERT_TRUE(cfi_frame_info.get()
|
||||
@@ -360,7 +365,7 @@
|
||||
->FindCallerRegs<uint32_t>(current_registers, memory,
|
||||
&caller_registers));
|
||||
VerifyRegisters(__FILE__, __LINE__,
|
||||
expected_caller_registers, caller_registers);
|
||||
|
||||
frame.instruction = 0x3d84;
|
||||
|
@ -635,10 +853,20 @@ diff --git a/src/processor/fast_source_line_resolver_unittest.cc b/src/processor
|
|||
cfi_frame_info.reset(fast_resolver.FindCFIFrameInfo(&frame));
|
||||
ASSERT_TRUE(cfi_frame_info.get());
|
||||
ASSERT_TRUE(cfi_frame_info.get()
|
||||
->FindCallerRegs<uint32_t>(current_registers, memory,
|
||||
&caller_registers));
|
||||
VerifyRegisters(__FILE__, __LINE__,
|
||||
expected_caller_registers, caller_registers);
|
||||
|
||||
diff --git a/src/processor/postfix_evaluator-inl.h b/src/processor/postfix_evaluator-inl.h
|
||||
--- a/src/processor/postfix_evaluator-inl.h
|
||||
+++ b/src/processor/postfix_evaluator-inl.h
|
||||
@@ -190,9 +190,9 @@
|
||||
@@ -185,19 +185,19 @@
|
||||
return false;
|
||||
}
|
||||
if (identifier == ustr__empty() || Index(identifier,0) != '$') {
|
||||
BPLOG(ERROR) << "Can't assign " << HexString(value) << " to " <<
|
||||
identifier << ": " << expression;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -650,7 +878,17 @@ diff --git a/src/processor/postfix_evaluator-inl.h b/src/processor/postfix_evalu
|
|||
} else {
|
||||
// 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).
|
||||
@@ -305,18 +305,18 @@
|
||||
//
|
||||
// First, try to treat the value as a literal. Literals may have leading
|
||||
// '-' sign, and the entire remaining string must be parseable as
|
||||
// ValueType. If this isn't possible, it can't be a literal, so treat it
|
||||
// as an identifier instead.
|
||||
@@ -300,28 +300,28 @@
|
||||
|
||||
return PopValue(result);
|
||||
}
|
||||
|
||||
// Simple-form expressions
|
||||
case Module::kExprSimple:
|
||||
case Module::kExprSimpleMem: {
|
||||
// Look up the base value
|
||||
|
@ -674,7 +912,17 @@ diff --git a/src/processor/postfix_evaluator-inl.h b/src/processor/postfix_evalu
|
|||
|
||||
// and dereference if necessary
|
||||
if (expr.how_ == Module::kExprSimpleMem) {
|
||||
@@ -373,9 +373,9 @@
|
||||
ValueType derefd;
|
||||
if (!memory_ || !memory_->GetMemoryAtAddress(sum, &derefd)) {
|
||||
return false;
|
||||
}
|
||||
*result = derefd;
|
||||
@@ -368,27 +368,27 @@
|
||||
if ((result = PopValueOrIdentifier(&literal, &token)) == POP_RESULT_FAIL) {
|
||||
return false;
|
||||
} else if (result == POP_RESULT_VALUE) {
|
||||
// This is the easy case.
|
||||
*value = literal;
|
||||
} else { // result == POP_RESULT_IDENTIFIER
|
||||
// There was an identifier at the top of the stack. Resolve it to a
|
||||
// value by looking it up in the dictionary.
|
||||
|
@ -687,7 +935,7 @@ diff --git a/src/processor/postfix_evaluator-inl.h b/src/processor/postfix_evalu
|
|||
// The identifier wasn't found in the dictionary. Don't imply any
|
||||
// default value, just fail.
|
||||
BPLOG(INFO) << "Identifier " << FromUniqueString(token)
|
||||
@@ -383,7 +383,7 @@
|
||||
<< " not in dictionary";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -696,10 +944,20 @@ diff --git a/src/processor/postfix_evaluator-inl.h b/src/processor/postfix_evalu
|
|||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
template<typename ValueType>
|
||||
bool PostfixEvaluator<ValueType>::PopValues(ValueType *value1,
|
||||
diff --git a/src/processor/postfix_evaluator.h b/src/processor/postfix_evaluator.h
|
||||
--- a/src/processor/postfix_evaluator.h
|
||||
+++ b/src/processor/postfix_evaluator.h
|
||||
@@ -98,8 +98,8 @@
|
||||
@@ -93,18 +93,18 @@
|
||||
StackElem(const UniqueString* ustr) { isValue = false; u.ustr = ustr; }
|
||||
bool isValue;
|
||||
union { ValueType val; const UniqueString* ustr; } u;
|
||||
};
|
||||
|
||||
template<typename ValueType>
|
||||
class PostfixEvaluator {
|
||||
public:
|
||||
|
@ -710,10 +968,20 @@ diff --git a/src/processor/postfix_evaluator.h b/src/processor/postfix_evaluator
|
|||
|
||||
// Create a PostfixEvaluator object that may be used (with Evaluate) on
|
||||
// one or more expressions. PostfixEvaluator does not take ownership of
|
||||
// either argument. |memory| may be NULL, in which case dereferencing
|
||||
// (^) will not be supported. |dictionary| may be NULL, but evaluation
|
||||
// will fail in that case unless set_dictionary is used before calling
|
||||
// Evaluate.
|
||||
PostfixEvaluator(DictionaryType *dictionary, const MemoryRegion *memory)
|
||||
diff --git a/src/processor/postfix_evaluator_unittest.cc b/src/processor/postfix_evaluator_unittest.cc
|
||||
--- a/src/processor/postfix_evaluator_unittest.cc
|
||||
+++ b/src/processor/postfix_evaluator_unittest.cc
|
||||
@@ -183,12 +183,12 @@
|
||||
@@ -178,22 +178,22 @@
|
||||
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
|
||||
// instead of a real stack snapshot, but the program strings are real and
|
||||
// the implementation doesn't know or care that the data is not real.
|
||||
PostfixEvaluator<unsigned int>::DictionaryType dictionary_1;
|
||||
|
@ -732,7 +1000,17 @@ diff --git a/src/processor/postfix_evaluator_unittest.cc b/src/processor/postfix
|
|||
const EvaluateTest evaluate_tests_1[] = {
|
||||
{ "$T0 $ebp = $eip $T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + = "
|
||||
"$L $T0 .cbSavedRegs - = $P $T0 8 + .cbParams + =", true },
|
||||
@@ -278,12 +278,8 @@
|
||||
// Intermediate state: $T0 = 0xbfff0010, $eip = 0xbfff0015,
|
||||
// $ebp = 0xbfff0011, $esp = 0xbfff0018,
|
||||
// $L = 0xbfff000c, $P = 0xbfff001c
|
||||
{ "$T0 $ebp = $eip $T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + = "
|
||||
"$L $T0 .cbSavedRegs - = $P $T0 8 + .cbParams + = $ebx $T0 28 - ^ =",
|
||||
@@ -273,70 +273,65 @@
|
||||
for (map<const UniqueString*, unsigned int>::const_iterator
|
||||
validate_iterator =
|
||||
evaluate_test_set->validate_data->begin();
|
||||
validate_iterator != evaluate_test_set->validate_data->end();
|
||||
++validate_iterator) {
|
||||
const UniqueString* identifier = validate_iterator->first;
|
||||
unsigned int expected_value = validate_iterator->second;
|
||||
|
||||
|
@ -746,7 +1024,9 @@ diff --git a/src/processor/postfix_evaluator_unittest.cc b/src/processor/postfix
|
|||
fprintf(stderr, "FAIL: evaluate test set %d/%d, "
|
||||
"validate identifier \"%s\", "
|
||||
"expected %d, observed not found\n",
|
||||
@@ -293,7 +289,8 @@
|
||||
evaluate_test_set_index, evaluate_test_set_count,
|
||||
FromUniqueString(identifier), expected_value);
|
||||
return false;
|
||||
}
|
||||
|
||||
// The value in the dictionary must be the same as the expected value.
|
||||
|
@ -756,7 +1036,13 @@ diff --git a/src/processor/postfix_evaluator_unittest.cc b/src/processor/postfix
|
|||
if (expected_value != observed_value) {
|
||||
fprintf(stderr, "FAIL: evaluate test set %d/%d, "
|
||||
"validate identifier \"%s\", "
|
||||
@@ -307,10 +304,8 @@
|
||||
"expected %d, observed %d\n",
|
||||
evaluate_test_set_index, evaluate_test_set_count,
|
||||
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 observed_assigned = false;
|
||||
|
@ -769,7 +1055,15 @@ diff --git a/src/processor/postfix_evaluator_unittest.cc b/src/processor/postfix
|
|||
}
|
||||
if (expected_assigned != observed_assigned) {
|
||||
fprintf(stderr, "FAIL: evaluate test set %d/%d, "
|
||||
@@ -326,12 +321,12 @@
|
||||
"validate assignment of \"%s\", "
|
||||
"expected %d, observed %d\n",
|
||||
evaluate_test_set_index, evaluate_test_set_count,
|
||||
FromUniqueString(identifier), expected_assigned,
|
||||
observed_assigned);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// EvaluateForValue tests.
|
||||
PostfixEvaluator<unsigned int>::DictionaryType dictionary_2;
|
||||
|
@ -788,7 +1082,17 @@ diff --git a/src/processor/postfix_evaluator_unittest.cc b/src/processor/postfix
|
|||
const EvaluateForValueTest evaluate_for_value_tests_2[] = {
|
||||
{ "28907223", true, 28907223 }, // simple constant
|
||||
{ "89854293 40010015 +", true, 89854293 + 40010015 }, // arithmetic
|
||||
@@ -375,12 +370,14 @@
|
||||
{ "-870245 8769343 +", true, 7899098 }, // negative constants
|
||||
{ "$ebp $esp - $eip +", true, 0x10000010 }, // variable references
|
||||
{ "18929794 34015074", false, 0 }, // too many values
|
||||
{ "$ebp $ebp 4 - =", false, 0 }, // too few values
|
||||
{ "$new $eip = $new", true, 0x10000000 }, // make new variable
|
||||
@@ -370,41 +365,43 @@
|
||||
if (test->evaluable && result != test->value) {
|
||||
fprintf(stderr, "FAIL: evaluate for value test %d, "
|
||||
"expected value to be 0x%x, but it was 0x%x\n",
|
||||
i, test->value, result);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -805,7 +1109,9 @@ diff --git a/src/processor/postfix_evaluator_unittest.cc b/src/processor/postfix
|
|||
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);
|
||||
@@ -390,16 +387,16 @@
|
||||
return false;
|
||||
} 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, a->second);
|
||||
return false;
|
||||
|
@ -828,10 +1134,20 @@ diff --git a/src/processor/postfix_evaluator_unittest.cc b/src/processor/postfix
|
|||
fprintf(stderr, " dict[\"%s\"] == 0x%x\n",
|
||||
FromUniqueString(remaining->first), remaining->second);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
diff --git a/src/processor/stackwalker_arm.cc b/src/processor/stackwalker_arm.cc
|
||||
--- a/src/processor/stackwalker_arm.cc
|
||||
+++ b/src/processor/stackwalker_arm.cc
|
||||
@@ -102,7 +102,7 @@
|
||||
@@ -97,70 +97,70 @@
|
||||
ToUniqueString("fps"), ToUniqueString("cpsr"),
|
||||
NULL
|
||||
};
|
||||
|
||||
// Populate a dictionary with the valid register values in last_frame.
|
||||
CFIFrameInfo::RegisterValueMap<uint32_t> callee_registers;
|
||||
for (int i = 0; register_names[i]; i++)
|
||||
if (last_frame->context_validity & StackFrameARM::RegisterValidFlag(i))
|
||||
|
@ -840,7 +1156,10 @@ diff --git a/src/processor/stackwalker_arm.cc b/src/processor/stackwalker_arm.cc
|
|||
|
||||
// Use the STACK CFI data to recover the caller's register values.
|
||||
CFIFrameInfo::RegisterValueMap<uint32_t> caller_registers;
|
||||
@@ -113,13 +113,13 @@
|
||||
if (!cfi_frame_info->FindCallerRegs(callee_registers, *memory_,
|
||||
&caller_registers))
|
||||
return NULL;
|
||||
|
||||
// Construct a new stack frame given the values the CFI recovered.
|
||||
scoped_ptr<StackFrameARM> frame(new StackFrameARM());
|
||||
for (int i = 0; register_names[i]; i++) {
|
||||
|
@ -858,7 +1177,12 @@ diff --git a/src/processor/stackwalker_arm.cc b/src/processor/stackwalker_arm.cc
|
|||
} else if (4 <= i && i <= 11 && (last_frame->context_validity &
|
||||
StackFrameARM::RegisterValidFlag(i))) {
|
||||
// If the STACK CFI data doesn't mention some callee-saves register, and
|
||||
@@ -132,18 +132,18 @@
|
||||
// it is valid in the callee, assume the callee has not yet changed it.
|
||||
// Registers r4 through r11 are callee-saves, according to the Procedure
|
||||
// Call Standard for the ARM Architecture, which the Linux ABI follows.
|
||||
frame->context_validity |= StackFrameARM::RegisterValidFlag(i);
|
||||
frame->context.iregs[i] = last_frame->context.iregs[i];
|
||||
}
|
||||
}
|
||||
// If the CFI doesn't recover the PC explicitly, then use .ra.
|
||||
if (!(frame->context_validity & StackFrameARM::CONTEXT_VALID_PC)) {
|
||||
|
@ -882,7 +1206,7 @@ diff --git a/src/processor/stackwalker_arm.cc b/src/processor/stackwalker_arm.cc
|
|||
frame->context.iregs[MD_CONTEXT_ARM_REG_PC] =
|
||||
last_frame->context.iregs[MD_CONTEXT_ARM_REG_LR];
|
||||
}
|
||||
@@ -151,11 +151,11 @@
|
||||
}
|
||||
}
|
||||
// If the CFI doesn't recover the SP explicitly, then use .cfa.
|
||||
if (!(frame->context_validity & StackFrameARM::CONTEXT_VALID_SP)) {
|
||||
|
@ -898,10 +1222,20 @@ diff --git a/src/processor/stackwalker_arm.cc b/src/processor/stackwalker_arm.cc
|
|||
}
|
||||
}
|
||||
|
||||
// If we didn't recover the PC and the SP, then the frame isn't very useful.
|
||||
static const int essentials = (StackFrameARM::CONTEXT_VALID_SP
|
||||
| StackFrameARM::CONTEXT_VALID_PC);
|
||||
if ((frame->context_validity & essentials) != essentials)
|
||||
return NULL;
|
||||
diff --git a/src/processor/stackwalker_x86.cc b/src/processor/stackwalker_x86.cc
|
||||
--- a/src/processor/stackwalker_x86.cc
|
||||
+++ b/src/processor/stackwalker_x86.cc
|
||||
@@ -199,16 +199,16 @@
|
||||
@@ -194,26 +194,26 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Set up the dictionary for the PostfixEvaluator. %ebp and %esp are used
|
||||
// in each program string, and their previous values are known, so set them
|
||||
// here.
|
||||
PostfixEvaluator<uint32_t>::DictionaryType dictionary;
|
||||
// Provide the current register values.
|
||||
|
@ -923,7 +1257,17 @@ diff --git a/src/processor/stackwalker_x86.cc b/src/processor/stackwalker_x86.cc
|
|||
|
||||
uint32_t raSearchStart = last_frame->context.esp +
|
||||
last_frame_callee_parameter_size +
|
||||
@@ -237,10 +237,10 @@
|
||||
last_frame_info->local_size +
|
||||
last_frame_info->saved_register_size;
|
||||
|
||||
uint32_t raSearchStartOld = raSearchStart;
|
||||
uint32_t found = 0; // dummy value
|
||||
@@ -232,20 +232,20 @@
|
||||
// Skip one slot from the stack and do another scan in order to get the
|
||||
// actual return address.
|
||||
raSearchStart += 4;
|
||||
ScanForReturnAddress(raSearchStart, &raSearchStart, &found, 3);
|
||||
}
|
||||
|
||||
// The difference between raSearch and raSearchStart is unknown,
|
||||
// but making them the same seems to work well in practice.
|
||||
|
@ -937,7 +1281,17 @@ diff --git a/src/processor/stackwalker_x86.cc b/src/processor/stackwalker_x86.cc
|
|||
|
||||
// Decide what type of program string to use. The program string is in
|
||||
// postfix notation and will be passed to PostfixEvaluator::Evaluate.
|
||||
@@ -330,8 +330,8 @@
|
||||
// Given the dictionary and the program string, it is possible to compute
|
||||
// the return address and the values of other registers in the calling
|
||||
// function. Because of bugs described below, the stack may need to be
|
||||
// scanned for these values. The results of program string evaluation
|
||||
// will be used to determine whether to scan for better values.
|
||||
@@ -325,18 +325,18 @@
|
||||
}
|
||||
|
||||
// Now crank it out, making sure that the program string set at least the
|
||||
// two required variables.
|
||||
PostfixEvaluator<uint32_t> evaluator =
|
||||
PostfixEvaluator<uint32_t>(&dictionary, memory_);
|
||||
PostfixEvaluator<uint32_t>::DictionaryValidityType dictionary_validity;
|
||||
if (!evaluator.Evaluate(program_string, &dictionary_validity) ||
|
||||
|
@ -948,7 +1302,17 @@ diff --git a/src/processor/stackwalker_x86.cc b/src/processor/stackwalker_x86.cc
|
|||
// Program string evaluation failed. It may be that %eip is not somewhere
|
||||
// with stack frame info, and %ebp is pointing to non-stack memory, so
|
||||
// our evaluation couldn't succeed. We'll scan the stack for a return
|
||||
@@ -349,8 +349,8 @@
|
||||
// address. This can happen if the stack is in a module for which
|
||||
// we don't have symbols, and that module is compiled without a
|
||||
// frame pointer.
|
||||
uint32_t location_start = last_frame->context.esp;
|
||||
uint32_t location, eip;
|
||||
@@ -344,69 +344,70 @@
|
||||
// if we can't find an instruction pointer even with stack scanning,
|
||||
// give up.
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// This seems like a reasonable return address. Since program string
|
||||
// evaluation failed, use it and set %esp to the location above the
|
||||
// one where the return address was found.
|
||||
|
@ -959,7 +1323,10 @@ diff --git a/src/processor/stackwalker_x86.cc b/src/processor/stackwalker_x86.cc
|
|||
trust = StackFrame::FRAME_TRUST_SCAN;
|
||||
}
|
||||
|
||||
@@ -361,7 +361,8 @@
|
||||
// Since this stack frame did not use %ebp in a traditional way,
|
||||
// locating the return address isn't entirely deterministic. In that
|
||||
// case, the stack can be scanned to locate the return address.
|
||||
//
|
||||
// However, if program string evaluation resulted in both %eip and
|
||||
// %ebp values of 0, trust that the end of the stack has been
|
||||
// reached and don't scan for anything else.
|
||||
|
@ -969,7 +1336,14 @@ diff --git a/src/processor/stackwalker_x86.cc b/src/processor/stackwalker_x86.cc
|
|||
int offset = 0;
|
||||
|
||||
// This scan can only be done if a CodeModules object is available, to
|
||||
@@ -376,18 +377,18 @@
|
||||
// check that candidate return addresses are in fact inside a module.
|
||||
//
|
||||
// TODO(mmentovai): This ignores dynamically-generated code. One possible
|
||||
// solution is to check the minidump's memory map to see if the candidate
|
||||
// %eip value comes from a mapped executable page, although this would
|
||||
// require dumps that contain MINIDUMP_MEMORY_INFO, which the Breakpad
|
||||
// client doesn't currently write (it would need to call MiniDumpWriteDump
|
||||
// with the MiniDumpWithFullMemoryInfo type bit set). Even given this
|
||||
// ability, older OSes (pre-XP SP2) and CPUs (pre-P4) don't enforce
|
||||
// an independent execute privilege on memory pages.
|
||||
|
||||
|
@ -992,7 +1366,13 @@ diff --git a/src/processor/stackwalker_x86.cc b/src/processor/stackwalker_x86.cc
|
|||
offset = location - location_start;
|
||||
trust = StackFrame::FRAME_TRUST_CFI_SCAN;
|
||||
}
|
||||
@@ -401,7 +402,7 @@
|
||||
}
|
||||
|
||||
if (recover_ebp) {
|
||||
// When trying to recover the previous value of the frame pointer (%ebp),
|
||||
// start looking at the lowest possible address in the saved-register
|
||||
// area, and look at the entire saved register area, increased by the
|
||||
// size of |offset| to account for additional data that may be on the
|
||||
// stack. The scan is performed from the highest possible address to
|
||||
// the lowest, because the expectation is that the function's prolog
|
||||
// would have saved %ebp early.
|
||||
|
@ -1001,7 +1381,17 @@ diff --git a/src/processor/stackwalker_x86.cc b/src/processor/stackwalker_x86.cc
|
|||
|
||||
// When a scan for return address is used, it is possible to skip one or
|
||||
// more frames (when return address is not in a known module). One
|
||||
@@ -425,7 +426,7 @@
|
||||
// indication for skipped frames is when the value of %ebp is lower than
|
||||
// the location of the return address on the stack
|
||||
bool has_skipped_frames =
|
||||
(trust != StackFrame::FRAME_TRUST_CFI && ebp <= raSearchStart + offset);
|
||||
|
||||
@@ -420,49 +421,49 @@
|
||||
location >= location_end;
|
||||
location -= 4) {
|
||||
if (!memory_->GetMemoryAtAddress(location, &ebp))
|
||||
break;
|
||||
|
||||
if (memory_->GetMemoryAtAddress(ebp, &value)) {
|
||||
// The candidate value is a pointer to the same memory region
|
||||
// (the stack). Prefer it as a recovered %ebp result.
|
||||
|
@ -1010,7 +1400,13 @@ diff --git a/src/processor/stackwalker_x86.cc b/src/processor/stackwalker_x86.cc
|
|||
break;
|
||||
}
|
||||
}
|
||||
@@ -439,25 +440,25 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create a new stack frame (ownership will be transferred to the caller)
|
||||
// and fill it in.
|
||||
StackFrameX86* frame = new StackFrameX86();
|
||||
|
||||
frame->trust = trust;
|
||||
frame->context = last_frame->context;
|
||||
|
@ -1045,3 +1441,8 @@ diff --git a/src/processor/stackwalker_x86.cc b/src/processor/stackwalker_x86.cc
|
|||
frame->context_validity |= StackFrameX86::CONTEXT_VALID_EDI;
|
||||
}
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
StackFrameX86* StackwalkerX86::GetCallerByCFIFrameInfo(
|
||||
const vector<StackFrame*> &frames,
|
||||
|
|
|
@ -1,46 +0,0 @@
|
|||
# HG changeset patch
|
||||
# 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
|
||||
@@ -39,7 +39,9 @@
|
||||
#include "common/dwarf_cu_to_module.h"
|
||||
|
||||
#include <assert.h>
|
||||
+#if !defined(__ANDROID__)
|
||||
#include <cxxabi.h>
|
||||
+#endif
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
|
||||
@@ -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__)
|
||||
+ demangled = abi::__cxa_demangle(data.c_str(), NULL, NULL, NULL);
|
||||
+#endif
|
||||
if (demangled) {
|
||||
demangled_name_ = AddStringToPool(demangled);
|
||||
free(reinterpret_cast<void*>(demangled));
|
||||
@@ -783,9 +788,9 @@
|
||||
// complexity from here on out is linear.
|
||||
|
||||
// Put both our functions and lines in order by address.
|
||||
- sort(functions->begin(), functions->end(),
|
||||
- Module::Function::CompareByAddress);
|
||||
- sort(lines_.begin(), lines_.end(), Module::Line::CompareByAddress);
|
||||
+ std::sort(functions->begin(), functions->end(),
|
||||
+ Module::Function::CompareByAddress);
|
||||
+ std::sort(lines_.begin(), lines_.end(), Module::Line::CompareByAddress);
|
||||
|
||||
// The last line that we used any piece of. We use this only for
|
||||
// generating warnings.
|
|
@ -1,97 +0,0 @@
|
|||
# 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
|
|
@ -1,174 +0,0 @@
|
|||
# HG changeset patch
|
||||
# Parent 6131d396790eefed8441bf0566ff38f59ca092b3
|
||||
Fix some more Win32 compat issues in processor code
|
||||
R=mark at https://breakpad.appspot.com/535003/
|
||||
|
||||
diff --git a/src/google_breakpad/common/breakpad_types.h b/src/google_breakpad/common/breakpad_types.h
|
||||
--- a/src/google_breakpad/common/breakpad_types.h
|
||||
+++ b/src/google_breakpad/common/breakpad_types.h
|
||||
@@ -57,16 +57,17 @@
|
||||
* there are often subtle type incompatibilities.
|
||||
*/
|
||||
#include BREAKPAD_CUSTOM_STDINT_H
|
||||
#else
|
||||
#include <WTypes.h>
|
||||
|
||||
typedef unsigned __int8 uint8_t;
|
||||
typedef unsigned __int16 uint16_t;
|
||||
+typedef __int32 int32_t;
|
||||
typedef unsigned __int32 uint32_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
#endif
|
||||
|
||||
#endif /* !_WIN32 */
|
||||
|
||||
typedef struct {
|
||||
uint64_t high;
|
||||
diff --git a/src/processor/basic_source_line_resolver.cc b/src/processor/basic_source_line_resolver.cc
|
||||
--- a/src/processor/basic_source_line_resolver.cc
|
||||
+++ b/src/processor/basic_source_line_resolver.cc
|
||||
@@ -49,16 +49,21 @@
|
||||
#include "processor/tokenize.h"
|
||||
|
||||
using std::map;
|
||||
using std::vector;
|
||||
using std::make_pair;
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
+#ifdef _WIN32
|
||||
+#define strtok_r strtok_s
|
||||
+#define strtoull _strtoui64
|
||||
+#endif
|
||||
+
|
||||
static const char *kWhitespace = " \r\n";
|
||||
|
||||
BasicSourceLineResolver::BasicSourceLineResolver() :
|
||||
SourceLineResolverBase(new BasicModuleFactory) { }
|
||||
|
||||
bool BasicSourceLineResolver::Module::LoadMapFromMemory(char *memory_buffer) {
|
||||
linked_ptr<Function> cur_func;
|
||||
int line_number = 0;
|
||||
diff --git a/src/processor/cfi_frame_info.cc b/src/processor/cfi_frame_info.cc
|
||||
--- a/src/processor/cfi_frame_info.cc
|
||||
+++ b/src/processor/cfi_frame_info.cc
|
||||
@@ -39,16 +39,20 @@
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
|
||||
#include "common/scoped_ptr.h"
|
||||
#include "processor/postfix_evaluator-inl.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
+#ifdef _WIN32
|
||||
+#define strtok_r strtok_s
|
||||
+#endif
|
||||
+
|
||||
template<typename V>
|
||||
bool CFIFrameInfo::FindCallerRegs(const RegisterValueMap<V> ®isters,
|
||||
const MemoryRegion &memory,
|
||||
RegisterValueMap<V> *caller_registers) const {
|
||||
// If there are not rules for both .ra and .cfa in effect at this address,
|
||||
// don't use this CFI data for stack walking.
|
||||
if (cfa_rule_.invalid() || ra_rule_.invalid())
|
||||
return false;
|
||||
diff --git a/src/processor/minidump.cc b/src/processor/minidump.cc
|
||||
--- a/src/processor/minidump.cc
|
||||
+++ b/src/processor/minidump.cc
|
||||
@@ -32,25 +32,23 @@
|
||||
// See minidump.h for documentation.
|
||||
//
|
||||
// Author: Mark Mentovai
|
||||
|
||||
#include "google_breakpad/processor/minidump.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <fcntl.h>
|
||||
+#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <io.h>
|
||||
-#if _MSC_VER < 1600
|
||||
-typedef SSIZE_T ssize_t;
|
||||
-#endif
|
||||
#define PRIx64 "llx"
|
||||
#define PRIx32 "lx"
|
||||
#define snprintf _snprintf
|
||||
#else // _WIN32
|
||||
#include <unistd.h>
|
||||
#define O_BINARY 0
|
||||
#endif // _WIN32
|
||||
|
||||
diff --git a/src/processor/source_line_resolver_base_types.h b/src/processor/source_line_resolver_base_types.h
|
||||
--- a/src/processor/source_line_resolver_base_types.h
|
||||
+++ b/src/processor/source_line_resolver_base_types.h
|
||||
@@ -38,16 +38,17 @@
|
||||
//
|
||||
// Author: Siyang Xie (lambxsy@google.com)
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
+#include "google_breakpad/common/breakpad_types.h"
|
||||
#include "google_breakpad/processor/source_line_resolver_base.h"
|
||||
#include "google_breakpad/processor/stack_frame.h"
|
||||
#include "processor/cfi_frame_info.h"
|
||||
#include "processor/windows_frame_info.h"
|
||||
|
||||
#ifndef PROCESSOR_SOURCE_LINE_RESOLVER_BASE_TYPES_H__
|
||||
#define PROCESSOR_SOURCE_LINE_RESOLVER_BASE_TYPES_H__
|
||||
|
||||
diff --git a/src/processor/tokenize.cc b/src/processor/tokenize.cc
|
||||
--- a/src/processor/tokenize.cc
|
||||
+++ b/src/processor/tokenize.cc
|
||||
@@ -31,16 +31,20 @@
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "common/using_std_string.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
+#ifdef _WIN32
|
||||
+#define strtok_r strtok_s
|
||||
+#endif
|
||||
+
|
||||
using std::vector;
|
||||
|
||||
bool Tokenize(char *line,
|
||||
const char *separators,
|
||||
int max_tokens,
|
||||
vector<char*> *tokens) {
|
||||
tokens->clear();
|
||||
tokens->reserve(max_tokens);
|
||||
diff --git a/src/processor/windows_frame_info.h b/src/processor/windows_frame_info.h
|
||||
--- a/src/processor/windows_frame_info.h
|
||||
+++ b/src/processor/windows_frame_info.h
|
||||
@@ -46,16 +46,20 @@
|
||||
|
||||
#include "common/using_std_string.h"
|
||||
#include "google_breakpad/common/breakpad_types.h"
|
||||
#include "processor/logging.h"
|
||||
#include "processor/tokenize.h"
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
+#ifdef _WIN32
|
||||
+#define strtoull _strtoui64
|
||||
+#endif
|
||||
+
|
||||
struct WindowsFrameInfo {
|
||||
public:
|
||||
enum Validity {
|
||||
VALID_NONE = 0,
|
||||
VALID_PARAMETER_SIZE = 1,
|
||||
VALID_ALL = -1
|
||||
};
|
||||
|
|
@ -1,5 +1,8 @@
|
|||
# HG changeset patch
|
||||
# Parent 370ef99fecb269ea8c30a56c4a0cf5ab11844868
|
||||
# User Ted Mielczarek <ted@mielczarek.org>
|
||||
# Date 1362600444 18000
|
||||
# Node ID 0eb3c7ba8a38a269ab975eff3f95a1a5d5d937b9
|
||||
# Parent 6b68e82037b8322fb392cea369d517aeeaaee9d3
|
||||
Stop using dynamic_cast in dwarf2reader
|
||||
Patch by Julian Seward <jseward@acm.org>, R=ted
|
||||
|
||||
|
|
|
@ -1,118 +0,0 @@
|
|||
# HG changeset patch
|
||||
# Parent b82a8a320d2e1fc61565872cdd355605895a7602
|
||||
Allow building symbol dumping without STABS support
|
||||
|
||||
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
|
||||
@@ -58,34 +58,38 @@
|
||||
#include "common/dwarf_cu_to_module.h"
|
||||
#include "common/dwarf_line_to_module.h"
|
||||
#include "common/linux/elfutils.h"
|
||||
#include "common/linux/elfutils-inl.h"
|
||||
#include "common/linux/elf_symbols_to_module.h"
|
||||
#include "common/linux/file_id.h"
|
||||
#include "common/module.h"
|
||||
#include "common/scoped_ptr.h"
|
||||
+#ifndef NO_STABS_SUPPORT
|
||||
#include "common/stabs_reader.h"
|
||||
#include "common/stabs_to_module.h"
|
||||
+#endif
|
||||
#include "common/using_std_string.h"
|
||||
|
||||
// This namespace contains helper functions.
|
||||
namespace {
|
||||
|
||||
using google_breakpad::DwarfCFIToModule;
|
||||
using google_breakpad::DwarfCUToModule;
|
||||
using google_breakpad::DwarfLineToModule;
|
||||
using google_breakpad::ElfClass;
|
||||
using google_breakpad::ElfClass32;
|
||||
using google_breakpad::ElfClass64;
|
||||
using google_breakpad::FindElfSectionByName;
|
||||
using google_breakpad::GetOffset;
|
||||
using google_breakpad::IsValidElf;
|
||||
using google_breakpad::Module;
|
||||
+#ifndef NO_STABS_SUPPORT
|
||||
using google_breakpad::StabsToModule;
|
||||
+#endif
|
||||
using google_breakpad::UniqueString;
|
||||
using google_breakpad::scoped_ptr;
|
||||
|
||||
//
|
||||
// FDWrapper
|
||||
//
|
||||
// Wrapper class to make sure opened file is closed.
|
||||
//
|
||||
@@ -154,16 +158,17 @@
|
||||
if (header.p_type == PT_LOAD &&
|
||||
header.p_offset == 0)
|
||||
return header.p_vaddr;
|
||||
}
|
||||
// For other types of ELF, return 0.
|
||||
return 0;
|
||||
}
|
||||
|
||||
+#ifndef NO_STABS_SUPPORT
|
||||
template<typename ElfClass>
|
||||
bool LoadStabs(const typename ElfClass::Ehdr* elf_header,
|
||||
const typename ElfClass::Shdr* stab_section,
|
||||
const typename ElfClass::Shdr* stabstr_section,
|
||||
const bool big_endian,
|
||||
Module* module) {
|
||||
// A callback object to handle data from the STABS reader.
|
||||
StabsToModule handler(module);
|
||||
@@ -179,16 +184,17 @@
|
||||
stabstr, stabstr_section->sh_size,
|
||||
big_endian, 4, true, &handler);
|
||||
// Read the STABS data, and do post-processing.
|
||||
if (!reader.Process())
|
||||
return false;
|
||||
handler.Finalize();
|
||||
return true;
|
||||
}
|
||||
+#endif // NO_STABS_SUPPORT
|
||||
|
||||
// A line-to-module loader that accepts line number info parsed by
|
||||
// dwarf2reader::LineInfo and populates a Module and a line vector
|
||||
// with the results.
|
||||
class DumperLineToModule: public DwarfCUToModule::LineToModuleHandler {
|
||||
public:
|
||||
// Create a line-to-module converter using BYTE_READER.
|
||||
explicit DumperLineToModule(dwarf2reader::ByteReader *byte_reader)
|
||||
@@ -533,16 +539,17 @@
|
||||
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;
|
||||
bool found_debug_info_section = false;
|
||||
bool found_usable_info = false;
|
||||
|
||||
if (symbol_data != ONLY_CFI) {
|
||||
+#ifndef NO_STABS_SUPPORT
|
||||
// Look for STABS debugging information, and load it if present.
|
||||
const Shdr* stab_section =
|
||||
FindElfSectionByName<ElfClass>(".stab", SHT_PROGBITS,
|
||||
sections, names, names_end,
|
||||
elf_header->e_shnum);
|
||||
if (stab_section) {
|
||||
const Shdr* stabstr_section = stab_section->sh_link + sections;
|
||||
if (stabstr_section) {
|
||||
@@ -551,16 +558,17 @@
|
||||
info->LoadedSection(".stab");
|
||||
if (!LoadStabs<ElfClass>(elf_header, stab_section, stabstr_section,
|
||||
big_endian, module)) {
|
||||
fprintf(stderr, "%s: \".stab\" section found, but failed to load"
|
||||
" STABS debugging information\n", obj_file.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
+#endif // NO_STABS_SUPPORT
|
||||
|
||||
// Look for DWARF debugging information, and load it if present.
|
||||
const Shdr* dwarf_section =
|
||||
FindElfSectionByName<ElfClass>(".debug_info", SHT_PROGBITS,
|
||||
sections, names, names_end,
|
||||
elf_header->e_shnum);
|
||||
if (dwarf_section) {
|
||||
found_debug_info_section = true;
|
|
@ -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: 1120
|
||||
Revision: 1128
|
||||
Node Kind: directory
|
||||
Schedule: normal
|
||||
Last Changed Author: ted.mielczarek@gmail.com
|
||||
Last Changed Rev: 1120
|
||||
Last Changed Date: 2013-03-04 10:42:50 -0500 (Mon, 04 Mar 2013)
|
||||
Last Changed Rev: 1128
|
||||
Last Changed Date: 2013-03-06 15:14:34 -0500 (Wed, 06 Mar 2013)
|
||||
|
||||
|
|
|
@ -363,11 +363,14 @@ bool ExceptionHandler::WriteMinidumpWithException(int exception_type,
|
|||
// decide if this should be sent.
|
||||
if (filter_ && !filter_(callback_context_))
|
||||
return false;
|
||||
return crash_generation_client_->RequestDumpForException(
|
||||
result = crash_generation_client_->RequestDumpForException(
|
||||
exception_type,
|
||||
exception_code,
|
||||
exception_subcode,
|
||||
thread_name);
|
||||
if (result && exit_after_write) {
|
||||
_exit(exception_type);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
|
|
0
toolkit/crashreporter/google-breakpad/src/client/windows/crash_generation/minidump_generator.h
Normal file → Executable file
0
toolkit/crashreporter/google-breakpad/src/client/windows/crash_generation/minidump_generator.h
Normal file → Executable file
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -210,7 +210,7 @@ class MachMessage {
|
|||
struct MessageDataPacket {
|
||||
int32_t id; // little-endian
|
||||
int32_t data_length; // little-endian
|
||||
uint8_t data[1]; // actual size limited by sizeof(MachMessage)
|
||||
uint8_t data[1]; // actual size limited by sizeof(MachMessage)
|
||||
};
|
||||
|
||||
MessageDataPacket* GetDataPacket();
|
||||
|
@ -223,7 +223,7 @@ class MachMessage {
|
|||
|
||||
mach_msg_header_t head;
|
||||
mach_msg_body_t body;
|
||||
uint8_t padding[1024]; // descriptors and data may be embedded here
|
||||
uint8_t padding[1024]; // descriptors and data may be embedded here
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
|
|
|
@ -57,7 +57,6 @@
|
|||
#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))
|
||||
|
|
|
@ -328,9 +328,9 @@ bool Module::Write(std::ostream &stream, SymbolData symbol_data) {
|
|||
<< 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
|
||||
|
@ -351,8 +351,6 @@ bool Module::Write(std::ostream &stream, SymbolData symbol_data) {
|
|||
stream << "PUBLIC " << hex
|
||||
<< (ext->address - load_address_) << " 0 "
|
||||
<< ext->name << dec << endl;
|
||||
if (!stream.good())
|
||||
return ReportError();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -72,7 +72,7 @@ typedef unsigned __int64 uint64_t;
|
|||
typedef struct {
|
||||
uint64_t high;
|
||||
uint64_t low;
|
||||
} uint128_t;
|
||||
} uint128_struct;
|
||||
|
||||
typedef uint64_t breakpad_time_t;
|
||||
|
||||
|
|
|
@ -67,7 +67,7 @@
|
|||
* equivalent types and values in the Windows Platform SDK are given in
|
||||
* comments.
|
||||
*
|
||||
* Author: Mark Mentovai
|
||||
* Author: Mark Mentovai
|
||||
* Change to split into its own file: Neal Sidhwaney */
|
||||
|
||||
#ifndef GOOGLE_BREAKPAD_COMMON_MINIDUMP_CPU_AMD64_H__
|
||||
|
@ -79,22 +79,22 @@
|
|||
*/
|
||||
|
||||
typedef struct {
|
||||
uint16_t control_word;
|
||||
uint16_t status_word;
|
||||
uint8_t tag_word;
|
||||
uint8_t reserved1;
|
||||
uint16_t error_opcode;
|
||||
uint32_t error_offset;
|
||||
uint16_t error_selector;
|
||||
uint16_t reserved2;
|
||||
uint32_t data_offset;
|
||||
uint16_t data_selector;
|
||||
uint16_t reserved3;
|
||||
uint32_t mx_csr;
|
||||
uint32_t mx_csr_mask;
|
||||
uint128_t float_registers[8];
|
||||
uint128_t xmm_registers[16];
|
||||
uint8_t reserved4[96];
|
||||
uint16_t control_word;
|
||||
uint16_t status_word;
|
||||
uint8_t tag_word;
|
||||
uint8_t reserved1;
|
||||
uint16_t error_opcode;
|
||||
uint32_t error_offset;
|
||||
uint16_t error_selector;
|
||||
uint16_t reserved2;
|
||||
uint32_t data_offset;
|
||||
uint16_t data_selector;
|
||||
uint16_t reserved3;
|
||||
uint32_t mx_csr;
|
||||
uint32_t mx_csr_mask;
|
||||
uint128_struct float_registers[8];
|
||||
uint128_struct xmm_registers[16];
|
||||
uint8_t reserved4[96];
|
||||
} MDXmmSaveArea32AMD64; /* XMM_SAVE_AREA32 */
|
||||
|
||||
#define MD_CONTEXT_AMD64_VR_COUNT 26
|
||||
|
@ -127,7 +127,7 @@ typedef struct {
|
|||
/* The next 2 registers are included with MD_CONTEXT_AMD64_CONTROL */
|
||||
uint16_t ss;
|
||||
uint32_t eflags;
|
||||
|
||||
|
||||
/* The next 6 registers are included with MD_CONTEXT_AMD64_DEBUG_REGISTERS */
|
||||
uint64_t dr0;
|
||||
uint64_t dr1;
|
||||
|
@ -167,29 +167,29 @@ typedef struct {
|
|||
union {
|
||||
MDXmmSaveArea32AMD64 flt_save;
|
||||
struct {
|
||||
uint128_t header[2];
|
||||
uint128_t legacy[8];
|
||||
uint128_t xmm0;
|
||||
uint128_t xmm1;
|
||||
uint128_t xmm2;
|
||||
uint128_t xmm3;
|
||||
uint128_t xmm4;
|
||||
uint128_t xmm5;
|
||||
uint128_t xmm6;
|
||||
uint128_t xmm7;
|
||||
uint128_t xmm8;
|
||||
uint128_t xmm9;
|
||||
uint128_t xmm10;
|
||||
uint128_t xmm11;
|
||||
uint128_t xmm12;
|
||||
uint128_t xmm13;
|
||||
uint128_t xmm14;
|
||||
uint128_t xmm15;
|
||||
uint128_struct header[2];
|
||||
uint128_struct legacy[8];
|
||||
uint128_struct xmm0;
|
||||
uint128_struct xmm1;
|
||||
uint128_struct xmm2;
|
||||
uint128_struct xmm3;
|
||||
uint128_struct xmm4;
|
||||
uint128_struct xmm5;
|
||||
uint128_struct xmm6;
|
||||
uint128_struct xmm7;
|
||||
uint128_struct xmm8;
|
||||
uint128_struct xmm9;
|
||||
uint128_struct xmm10;
|
||||
uint128_struct xmm11;
|
||||
uint128_struct xmm12;
|
||||
uint128_struct xmm13;
|
||||
uint128_struct xmm14;
|
||||
uint128_struct xmm15;
|
||||
} sse_registers;
|
||||
};
|
||||
|
||||
uint128_t vector_register[MD_CONTEXT_AMD64_VR_COUNT];
|
||||
uint64_t vector_control;
|
||||
uint128_struct vector_register[MD_CONTEXT_AMD64_VR_COUNT];
|
||||
uint64_t vector_control;
|
||||
|
||||
/* The next 5 registers are included with MD_CONTEXT_AMD64_DEBUG_REGISTERS */
|
||||
uint64_t debug_control;
|
||||
|
@ -197,7 +197,7 @@ typedef struct {
|
|||
uint64_t last_branch_from_rip;
|
||||
uint64_t last_exception_to_rip;
|
||||
uint64_t last_exception_from_rip;
|
||||
|
||||
|
||||
} MDRawContextAMD64; /* CONTEXT */
|
||||
|
||||
/* For (MDRawContextAMD64).context_flags. These values indicate the type of
|
||||
|
|
|
@ -77,10 +77,10 @@
|
|||
* are not exactly minidumps.
|
||||
*/
|
||||
typedef struct {
|
||||
uint64_t fpscr; /* FPU status register */
|
||||
uint64_t fpscr; /* FPU status register */
|
||||
|
||||
/* 32 64-bit floating point registers, d0 .. d31. */
|
||||
uint64_t regs[MD_FLOATINGSAVEAREA_ARM_FPR_COUNT];
|
||||
uint64_t regs[MD_FLOATINGSAVEAREA_ARM_FPR_COUNT];
|
||||
|
||||
/* Miscellaneous control words */
|
||||
uint32_t extra[MD_FLOATINGSAVEAREA_ARM_FPEXTRA_COUNT];
|
||||
|
@ -92,7 +92,7 @@ typedef struct {
|
|||
/* The next field determines the layout of the structure, and which parts
|
||||
* of it are populated
|
||||
*/
|
||||
uint32_t context_flags;
|
||||
uint32_t context_flags;
|
||||
|
||||
/* 16 32-bit integer registers, r0 .. r15
|
||||
* Note the following fixed uses:
|
||||
|
@ -116,7 +116,7 @@ typedef struct {
|
|||
|
||||
} MDRawContextARM;
|
||||
|
||||
/* Indices into iregs for registers with a dedicated or conventional
|
||||
/* Indices into iregs for registers with a dedicated or conventional
|
||||
* purpose.
|
||||
*/
|
||||
enum MDARMRegisterNumbers {
|
||||
|
|
|
@ -94,11 +94,11 @@ typedef struct {
|
|||
typedef struct {
|
||||
/* Vector registers (including vscr) are 128 bits, but mach/ppc/_types.h
|
||||
* exposes them as four 32-bit quantities. */
|
||||
uint128_t save_vr[MD_VECTORSAVEAREA_PPC_VR_COUNT];
|
||||
uint128_t save_vscr; /* Status/control */
|
||||
uint32_t save_pad5[4];
|
||||
uint32_t save_vrvalid; /* Identifies which vector registers are saved */
|
||||
uint32_t save_pad6[7];
|
||||
uint128_struct save_vr[MD_VECTORSAVEAREA_PPC_VR_COUNT];
|
||||
uint128_struct save_vscr; /* Status/control */
|
||||
uint32_t save_pad5[4];
|
||||
uint32_t save_vrvalid; /* Indicates which vector registers are saved */
|
||||
uint32_t save_pad6[7];
|
||||
} MDVectorSaveAreaPPC; /* ppc_vector_state */
|
||||
|
||||
|
||||
|
@ -117,21 +117,21 @@ typedef struct {
|
|||
/* context_flags is not present in ppc_thread_state, but it aids
|
||||
* identification of MDRawContextPPC among other raw context types,
|
||||
* and it guarantees alignment when we get to float_save. */
|
||||
uint32_t context_flags;
|
||||
uint32_t context_flags;
|
||||
|
||||
uint32_t srr0; /* Machine status save/restore: stores pc
|
||||
uint32_t srr0; /* Machine status save/restore: stores pc
|
||||
* (instruction) */
|
||||
uint32_t srr1; /* Machine status save/restore: stores msr
|
||||
uint32_t srr1; /* Machine status save/restore: stores msr
|
||||
* (ps, program/machine state) */
|
||||
/* ppc_thread_state contains 32 fields, r0 .. r31. Here, an array is
|
||||
* used for brevity. */
|
||||
uint32_t gpr[MD_CONTEXT_PPC_GPR_COUNT];
|
||||
uint32_t cr; /* Condition */
|
||||
uint32_t xer; /* Integer (fiXed-point) exception */
|
||||
uint32_t lr; /* Link */
|
||||
uint32_t ctr; /* Count */
|
||||
uint32_t mq; /* Multiply/Quotient (PPC 601, POWER only) */
|
||||
uint32_t vrsave; /* Vector save */
|
||||
uint32_t gpr[MD_CONTEXT_PPC_GPR_COUNT];
|
||||
uint32_t cr; /* Condition */
|
||||
uint32_t xer; /* Integer (fiXed-point) exception */
|
||||
uint32_t lr; /* Link */
|
||||
uint32_t ctr; /* Count */
|
||||
uint32_t mq; /* Multiply/Quotient (PPC 601, POWER only) */
|
||||
uint32_t vrsave; /* Vector save */
|
||||
|
||||
/* float_save and vector_save aren't present in ppc_thread_state, but
|
||||
* are represented in separate structures that still define a thread's
|
||||
|
|
|
@ -90,20 +90,20 @@ typedef struct {
|
|||
/* context_flags is not present in ppc_thread_state, but it aids
|
||||
* identification of MDRawContextPPC among other raw context types,
|
||||
* and it guarantees alignment when we get to float_save. */
|
||||
uint64_t context_flags;
|
||||
uint64_t context_flags;
|
||||
|
||||
uint64_t srr0; /* Machine status save/restore: stores pc
|
||||
uint64_t srr0; /* Machine status save/restore: stores pc
|
||||
* (instruction) */
|
||||
uint64_t srr1; /* Machine status save/restore: stores msr
|
||||
uint64_t srr1; /* Machine status save/restore: stores msr
|
||||
* (ps, program/machine state) */
|
||||
/* ppc_thread_state contains 32 fields, r0 .. r31. Here, an array is
|
||||
* used for brevity. */
|
||||
uint64_t gpr[MD_CONTEXT_PPC64_GPR_COUNT];
|
||||
uint64_t cr; /* Condition */
|
||||
uint64_t xer; /* Integer (fiXed-point) exception */
|
||||
uint64_t lr; /* Link */
|
||||
uint64_t ctr; /* Count */
|
||||
uint64_t vrsave; /* Vector save */
|
||||
uint64_t gpr[MD_CONTEXT_PPC64_GPR_COUNT];
|
||||
uint64_t cr; /* Condition */
|
||||
uint64_t xer; /* Integer (fiXed-point) exception */
|
||||
uint64_t lr; /* Link */
|
||||
uint64_t ctr; /* Count */
|
||||
uint64_t vrsave; /* Vector save */
|
||||
|
||||
/* float_save and vector_save aren't present in ppc_thread_state, but
|
||||
* are represented in separate structures that still define a thread's
|
||||
|
|
|
@ -82,10 +82,10 @@
|
|||
typedef struct {
|
||||
|
||||
/* FPU floating point regs */
|
||||
uint64_t regs[MD_FLOATINGSAVEAREA_SPARC_FPR_COUNT];
|
||||
uint64_t regs[MD_FLOATINGSAVEAREA_SPARC_FPR_COUNT];
|
||||
|
||||
uint64_t filler;
|
||||
uint64_t fsr; /* FPU status register */
|
||||
uint64_t filler;
|
||||
uint64_t fsr; /* FPU status register */
|
||||
} MDFloatingSaveAreaSPARC; /* FLOATING_SAVE_AREA */
|
||||
|
||||
#define MD_CONTEXT_SPARC_GPR_COUNT 32
|
||||
|
@ -94,8 +94,8 @@ typedef struct {
|
|||
/* The next field determines the layout of the structure, and which parts
|
||||
* of it are populated
|
||||
*/
|
||||
uint32_t context_flags;
|
||||
uint32_t flag_pad;
|
||||
uint32_t context_flags;
|
||||
uint32_t flag_pad;
|
||||
/*
|
||||
* General register access (SPARC).
|
||||
* Don't confuse definitions here with definitions in <sys/regset.h>.
|
||||
|
|
|
@ -234,7 +234,7 @@ typedef struct {
|
|||
typedef uint32_t MDRVA; /* RVA */
|
||||
|
||||
typedef struct {
|
||||
uint32_t data_size;
|
||||
uint32_t data_size;
|
||||
MDRVA rva;
|
||||
} MDLocationDescriptor; /* MINIDUMP_LOCATION_DESCRIPTOR */
|
||||
|
||||
|
@ -242,22 +242,22 @@ typedef struct {
|
|||
typedef struct {
|
||||
/* The base address of the memory range on the host that produced the
|
||||
* minidump. */
|
||||
uint64_t start_of_memory_range;
|
||||
uint64_t start_of_memory_range;
|
||||
|
||||
MDLocationDescriptor memory;
|
||||
} MDMemoryDescriptor; /* MINIDUMP_MEMORY_DESCRIPTOR */
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint32_t signature;
|
||||
uint32_t version;
|
||||
uint32_t stream_count;
|
||||
uint32_t signature;
|
||||
uint32_t version;
|
||||
uint32_t stream_count;
|
||||
MDRVA stream_directory_rva; /* A |stream_count|-sized array of
|
||||
* MDRawDirectory structures. */
|
||||
uint32_t checksum; /* Can be 0. In fact, that's all that's
|
||||
uint32_t checksum; /* Can be 0. In fact, that's all that's
|
||||
* been found in minidump files. */
|
||||
uint32_t time_date_stamp; /* time_t */
|
||||
uint64_t flags;
|
||||
uint32_t time_date_stamp; /* time_t */
|
||||
uint64_t flags;
|
||||
} MDRawHeader; /* MINIDUMP_HEADER */
|
||||
|
||||
/* For (MDRawHeader).signature and (MDRawHeader).version. Note that only the
|
||||
|
@ -302,7 +302,7 @@ typedef enum {
|
|||
|
||||
|
||||
typedef struct {
|
||||
uint32_t stream_type;
|
||||
uint32_t stream_type;
|
||||
MDLocationDescriptor location;
|
||||
} MDRawDirectory; /* MINIDUMP_DIRECTORY */
|
||||
|
||||
|
@ -355,18 +355,18 @@ static const size_t MDString_minsize = offsetof(MDString, buffer[0]);
|
|||
|
||||
|
||||
typedef struct {
|
||||
uint32_t thread_id;
|
||||
uint32_t suspend_count;
|
||||
uint32_t priority_class;
|
||||
uint32_t priority;
|
||||
uint64_t teb; /* Thread environment block */
|
||||
uint32_t thread_id;
|
||||
uint32_t suspend_count;
|
||||
uint32_t priority_class;
|
||||
uint32_t priority;
|
||||
uint64_t teb; /* Thread environment block */
|
||||
MDMemoryDescriptor stack;
|
||||
MDLocationDescriptor thread_context; /* MDRawContext[CPU] */
|
||||
} MDRawThread; /* MINIDUMP_THREAD */
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint32_t number_of_threads;
|
||||
uint32_t number_of_threads;
|
||||
MDRawThread threads[1];
|
||||
} MDRawThreadList; /* MINIDUMP_THREAD_LIST */
|
||||
|
||||
|
@ -375,10 +375,10 @@ static const size_t MDRawThreadList_minsize = offsetof(MDRawThreadList,
|
|||
|
||||
|
||||
typedef struct {
|
||||
uint64_t base_of_image;
|
||||
uint32_t size_of_image;
|
||||
uint32_t checksum; /* 0 if unknown */
|
||||
uint32_t time_date_stamp; /* time_t */
|
||||
uint64_t base_of_image;
|
||||
uint32_t size_of_image;
|
||||
uint32_t checksum; /* 0 if unknown */
|
||||
uint32_t time_date_stamp; /* time_t */
|
||||
MDRVA module_name_rva; /* MDString, pathname or filename */
|
||||
MDVSFixedFileInfo version_info;
|
||||
|
||||
|
@ -402,8 +402,8 @@ typedef struct {
|
|||
* As a workaround, reserved0 and reserved1 are instead defined here as
|
||||
* four 32-bit quantities. This should be harmless, as there are
|
||||
* currently no known uses for these fields. */
|
||||
uint32_t reserved0[2];
|
||||
uint32_t reserved1[2];
|
||||
uint32_t reserved0[2];
|
||||
uint32_t reserved1[2];
|
||||
} MDRawModule; /* MINIDUMP_MODULE */
|
||||
|
||||
/* The inclusion of a 64-bit type in MINIDUMP_MODULE forces the struct to
|
||||
|
@ -425,9 +425,9 @@ typedef struct {
|
|||
|
||||
typedef struct {
|
||||
MDCVHeader cv_header;
|
||||
uint32_t signature; /* time_t debug information created */
|
||||
uint32_t age; /* revision of PDB file */
|
||||
uint8_t pdb_file_name[1]; /* Pathname or filename of PDB file */
|
||||
uint32_t signature; /* time_t debug information created */
|
||||
uint32_t age; /* revision of PDB file */
|
||||
uint8_t pdb_file_name[1]; /* Pathname or filename of PDB file */
|
||||
} MDCVInfoPDB20;
|
||||
|
||||
static const size_t MDCVInfoPDB20_minsize = offsetof(MDCVInfoPDB20,
|
||||
|
@ -436,10 +436,10 @@ static const size_t MDCVInfoPDB20_minsize = offsetof(MDCVInfoPDB20,
|
|||
#define MD_CVINFOPDB20_SIGNATURE 0x3031424e /* cvHeader.signature = '01BN' */
|
||||
|
||||
typedef struct {
|
||||
uint32_t cv_signature;
|
||||
uint32_t cv_signature;
|
||||
MDGUID signature; /* GUID, identifies PDB file */
|
||||
uint32_t age; /* Identifies incremental changes to PDB file */
|
||||
uint8_t pdb_file_name[1]; /* Pathname or filename of PDB file,
|
||||
uint32_t age; /* Identifies incremental changes to PDB file */
|
||||
uint8_t pdb_file_name[1]; /* Pathname or filename of PDB file,
|
||||
* 0-terminated 8-bit character data (UTF-8?) */
|
||||
} MDCVInfoPDB70;
|
||||
|
||||
|
@ -454,7 +454,7 @@ typedef struct {
|
|||
uint32_t data3;
|
||||
uint32_t data4;
|
||||
uint32_t data5[3];
|
||||
uint8_t extra[2];
|
||||
uint8_t extra[2];
|
||||
} MDCVInfoELF;
|
||||
|
||||
/* In addition to the two CodeView record formats above, used for linking
|
||||
|
@ -479,12 +479,12 @@ typedef struct {
|
|||
* obsolete with modules built by recent toolchains. */
|
||||
|
||||
typedef struct {
|
||||
uint32_t data_type; /* IMAGE_DEBUG_TYPE_*, not defined here because
|
||||
uint32_t data_type; /* IMAGE_DEBUG_TYPE_*, not defined here because
|
||||
* this debug record type is mostly obsolete. */
|
||||
uint32_t length; /* Length of entire MDImageDebugMisc structure */
|
||||
uint8_t unicode; /* True if data is multibyte */
|
||||
uint8_t reserved[3];
|
||||
uint8_t data[1];
|
||||
uint32_t length; /* Length of entire MDImageDebugMisc structure */
|
||||
uint8_t unicode; /* True if data is multibyte */
|
||||
uint8_t reserved[3];
|
||||
uint8_t data[1];
|
||||
} MDImageDebugMisc; /* IMAGE_DEBUG_MISC */
|
||||
|
||||
static const size_t MDImageDebugMisc_minsize = offsetof(MDImageDebugMisc,
|
||||
|
@ -492,7 +492,7 @@ static const size_t MDImageDebugMisc_minsize = offsetof(MDImageDebugMisc,
|
|||
|
||||
|
||||
typedef struct {
|
||||
uint32_t number_of_modules;
|
||||
uint32_t number_of_modules;
|
||||
MDRawModule modules[1];
|
||||
} MDRawModuleList; /* MINIDUMP_MODULE_LIST */
|
||||
|
||||
|
@ -501,7 +501,7 @@ static const size_t MDRawModuleList_minsize = offsetof(MDRawModuleList,
|
|||
|
||||
|
||||
typedef struct {
|
||||
uint32_t number_of_memory_ranges;
|
||||
uint32_t number_of_memory_ranges;
|
||||
MDMemoryDescriptor memory_ranges[1];
|
||||
} MDRawMemoryList; /* MINIDUMP_MEMORY_LIST */
|
||||
|
||||
|
@ -512,21 +512,21 @@ static const size_t MDRawMemoryList_minsize = offsetof(MDRawMemoryList,
|
|||
#define MD_EXCEPTION_MAXIMUM_PARAMETERS 15
|
||||
|
||||
typedef struct {
|
||||
uint32_t exception_code; /* Windows: MDExceptionCodeWin,
|
||||
uint32_t exception_code; /* Windows: MDExceptionCodeWin,
|
||||
* Mac OS X: MDExceptionMac,
|
||||
* Linux: MDExceptionCodeLinux. */
|
||||
uint32_t exception_flags; /* Windows: 1 if noncontinuable,
|
||||
uint32_t exception_flags; /* Windows: 1 if noncontinuable,
|
||||
Mac OS X: MDExceptionCodeMac. */
|
||||
uint64_t exception_record; /* Address (in the minidump-producing host's
|
||||
uint64_t exception_record; /* Address (in the minidump-producing host's
|
||||
* memory) of another MDException, for
|
||||
* nested exceptions. */
|
||||
uint64_t exception_address; /* The address that caused the exception.
|
||||
uint64_t exception_address; /* The address that caused the exception.
|
||||
* Mac OS X: exception subcode (which is
|
||||
* typically the address). */
|
||||
uint32_t number_parameters; /* Number of valid elements in
|
||||
uint32_t number_parameters; /* Number of valid elements in
|
||||
* exception_information. */
|
||||
uint32_t __align;
|
||||
uint64_t exception_information[MD_EXCEPTION_MAXIMUM_PARAMETERS];
|
||||
uint32_t __align;
|
||||
uint64_t exception_information[MD_EXCEPTION_MAXIMUM_PARAMETERS];
|
||||
} MDException; /* MINIDUMP_EXCEPTION */
|
||||
|
||||
#include "minidump_exception_win32.h"
|
||||
|
@ -535,10 +535,10 @@ typedef struct {
|
|||
#include "minidump_exception_solaris.h"
|
||||
|
||||
typedef struct {
|
||||
uint32_t thread_id; /* Thread in which the exception
|
||||
uint32_t thread_id; /* Thread in which the exception
|
||||
* occurred. Corresponds to
|
||||
* (MDRawThread).thread_id. */
|
||||
uint32_t __align;
|
||||
uint32_t __align;
|
||||
MDException exception_record;
|
||||
MDLocationDescriptor thread_context; /* MDRawContext[CPU] */
|
||||
} MDRawExceptionStream; /* MINIDUMP_EXCEPTION_STREAM */
|
||||
|
@ -560,20 +560,20 @@ typedef union {
|
|||
typedef struct {
|
||||
/* The next 3 fields and numberOfProcessors are from the SYSTEM_INFO
|
||||
* structure as returned by GetSystemInfo */
|
||||
uint16_t processor_architecture;
|
||||
uint16_t processor_level; /* x86: 5 = 586, 6 = 686, ... */
|
||||
uint16_t processor_revision; /* x86: 0xMMSS, where MM=model,
|
||||
uint16_t processor_architecture;
|
||||
uint16_t processor_level; /* x86: 5 = 586, 6 = 686, ... */
|
||||
uint16_t processor_revision; /* x86: 0xMMSS, where MM=model,
|
||||
* SS=stepping */
|
||||
|
||||
uint8_t number_of_processors;
|
||||
uint8_t product_type; /* Windows: VER_NT_* from WinNT.h */
|
||||
uint8_t number_of_processors;
|
||||
uint8_t product_type; /* Windows: VER_NT_* from WinNT.h */
|
||||
|
||||
/* The next 5 fields are from the OSVERSIONINFO structure as returned
|
||||
* by GetVersionEx */
|
||||
uint32_t major_version;
|
||||
uint32_t minor_version;
|
||||
uint32_t build_number;
|
||||
uint32_t platform_id;
|
||||
uint32_t major_version;
|
||||
uint32_t minor_version;
|
||||
uint32_t build_number;
|
||||
uint32_t platform_id;
|
||||
MDRVA csd_version_rva; /* MDString further identifying the
|
||||
* host OS.
|
||||
* Windows: name of the installed OS
|
||||
|
@ -582,8 +582,8 @@ typedef struct {
|
|||
* (sw_vers -buildVersion).
|
||||
* Linux: uname -srvmo */
|
||||
|
||||
uint16_t suite_mask; /* Windows: VER_SUITE_* from WinNT.h */
|
||||
uint16_t reserved2;
|
||||
uint16_t suite_mask; /* Windows: VER_SUITE_* from WinNT.h */
|
||||
uint16_t reserved2;
|
||||
|
||||
MDCPUInformation cpu;
|
||||
} MDRawSystemInfo; /* MINIDUMP_SYSTEM_INFO */
|
||||
|
@ -666,7 +666,7 @@ typedef enum {
|
|||
/* MINIDUMP_MISC1_PROCESSOR_POWER_INFO */
|
||||
} MDMiscInfoFlags1;
|
||||
|
||||
/*
|
||||
/*
|
||||
* Around DbgHelp version 6.0, the style of new LIST structures changed
|
||||
* from including an array of length 1 at the end of the struct to
|
||||
* represent the variable-length data to including explicit
|
||||
|
@ -683,18 +683,18 @@ typedef struct {
|
|||
} MDRawMemoryInfoList; /* MINIDUMP_MEMORY_INFO_LIST */
|
||||
|
||||
typedef struct {
|
||||
uint64_t base_address; /* Base address of a region of pages */
|
||||
uint64_t allocation_base; /* Base address of a range of pages
|
||||
uint64_t base_address; /* Base address of a region of pages */
|
||||
uint64_t allocation_base; /* Base address of a range of pages
|
||||
* within this region. */
|
||||
uint32_t allocation_protection; /* Memory protection when this region
|
||||
uint32_t allocation_protection; /* Memory protection when this region
|
||||
* was originally allocated:
|
||||
* MDMemoryProtection */
|
||||
uint32_t __alignment1;
|
||||
uint64_t region_size;
|
||||
uint32_t state; /* MDMemoryState */
|
||||
uint32_t protection; /* MDMemoryProtection */
|
||||
uint32_t type; /* MDMemoryType */
|
||||
uint32_t __alignment2;
|
||||
uint32_t __alignment1;
|
||||
uint64_t region_size;
|
||||
uint32_t state; /* MDMemoryState */
|
||||
uint32_t protection; /* MDMemoryProtection */
|
||||
uint32_t type; /* MDMemoryType */
|
||||
uint32_t __alignment2;
|
||||
} MDRawMemoryInfo; /* MINIDUMP_MEMORY_INFO */
|
||||
|
||||
/* For (MDRawMemoryInfo).state */
|
||||
|
@ -806,9 +806,9 @@ typedef struct {
|
|||
} MDRawLinkMap;
|
||||
|
||||
typedef struct {
|
||||
uint32_t version;
|
||||
uint32_t version;
|
||||
MDRVA map;
|
||||
uint32_t dso_count;
|
||||
uint32_t dso_count;
|
||||
void* brk;
|
||||
void* ldbase;
|
||||
void* dynamic;
|
||||
|
|
|
@ -63,10 +63,10 @@ class MemoryRegion {
|
|||
// program. Returns true on success. Fails and returns false if address
|
||||
// is out of the region's bounds (after considering the width of value),
|
||||
// or for other types of errors.
|
||||
virtual bool GetMemoryAtAddress(uint64_t address, uint8_t* value) const =0;
|
||||
virtual bool GetMemoryAtAddress(uint64_t address, uint16_t* value) const =0;
|
||||
virtual bool GetMemoryAtAddress(uint64_t address, uint32_t* value) const =0;
|
||||
virtual bool GetMemoryAtAddress(uint64_t address, uint64_t* value) const =0;
|
||||
virtual bool GetMemoryAtAddress(uint64_t address, uint8_t* value) const = 0;
|
||||
virtual bool GetMemoryAtAddress(uint64_t address, uint16_t* value) const = 0;
|
||||
virtual bool GetMemoryAtAddress(uint64_t address, uint32_t* value) const = 0;
|
||||
virtual bool GetMemoryAtAddress(uint64_t address, uint64_t* value) const = 0;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -106,6 +106,9 @@ class ProcessState {
|
|||
}
|
||||
const SystemInfo* system_info() const { return &system_info_; }
|
||||
const CodeModules* modules() const { return modules_; }
|
||||
const vector<const CodeModule*>* modules_without_symbols() const {
|
||||
return &modules_without_symbols_;
|
||||
}
|
||||
ExploitabilityRating exploitability() const { return exploitability_; }
|
||||
|
||||
private:
|
||||
|
@ -158,6 +161,9 @@ class ProcessState {
|
|||
// ProcessState.
|
||||
const CodeModules *modules_;
|
||||
|
||||
// The modules that didn't have symbols when the report was processed.
|
||||
vector<const CodeModule*> modules_without_symbols_;
|
||||
|
||||
// The exploitability rating as determined by the exploitability
|
||||
// engine. When the exploitability engine is not enabled this
|
||||
// defaults to EXPLOITABILITY_NONE.
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "common/using_std_string.h"
|
||||
#include "google_breakpad/common/breakpad_types.h"
|
||||
|
@ -57,6 +58,7 @@ class MinidumpContext;
|
|||
class StackFrameSymbolizer;
|
||||
|
||||
using std::set;
|
||||
using std::vector;
|
||||
|
||||
class Stackwalker {
|
||||
public:
|
||||
|
@ -66,7 +68,15 @@ class Stackwalker {
|
|||
// GetCallerFrame. The frames are further processed to fill all available
|
||||
// data. Returns true if the stackwalk completed, or false if it was
|
||||
// interrupted by SymbolSupplier::GetSymbolFile().
|
||||
bool Walk(CallStack* stack);
|
||||
// Upon return, modules_without_symbols will be populated with pointers to
|
||||
// the code modules (CodeModule*) that DON'T have symbols.
|
||||
// modules_without_symbols DOES NOT take ownership of the code modules.
|
||||
// The lifetime of these code modules is the same as the lifetime of the
|
||||
// CodeModules passed to the StackWalker constructor (which currently
|
||||
// happens to be the lifetime of the Breakpad's ProcessingState object).
|
||||
// There is a check for duplicate modules so no duplicates are expected.
|
||||
bool Walk(CallStack* stack,
|
||||
vector<const CodeModule*>* modules_without_symbols);
|
||||
|
||||
// Returns a new concrete subclass suitable for the CPU that a stack was
|
||||
// generated on, according to the CPU type indicated by the context
|
||||
|
|
|
@ -304,8 +304,8 @@ BasicSourceLineResolver::Module::ParseFunction(char *function_line) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
uint64_t address = strtoull(tokens[0], NULL, 16);
|
||||
uint64_t size = strtoull(tokens[1], NULL, 16);
|
||||
uint64_t address = strtoull(tokens[0], NULL, 16);
|
||||
uint64_t size = strtoull(tokens[1], NULL, 16);
|
||||
int stack_param_size = strtoull(tokens[2], NULL, 16);
|
||||
char *name = tokens[3];
|
||||
|
||||
|
@ -320,8 +320,8 @@ BasicSourceLineResolver::Line* BasicSourceLineResolver::Module::ParseLine(
|
|||
return NULL;
|
||||
}
|
||||
|
||||
uint64_t address = strtoull(tokens[0], NULL, 16);
|
||||
uint64_t size = strtoull(tokens[1], NULL, 16);
|
||||
uint64_t address = strtoull(tokens[0], NULL, 16);
|
||||
uint64_t size = strtoull(tokens[1], NULL, 16);
|
||||
int line_number = atoi(tokens[2]);
|
||||
int source_file = atoi(tokens[3]);
|
||||
if (line_number <= 0) {
|
||||
|
@ -342,7 +342,7 @@ bool BasicSourceLineResolver::Module::ParsePublicSymbol(char *public_line) {
|
|||
return false;
|
||||
}
|
||||
|
||||
uint64_t address = strtoull(tokens[0], NULL, 16);
|
||||
uint64_t address = strtoull(tokens[0], NULL, 16);
|
||||
int stack_param_size = strtoull(tokens[1], NULL, 16);
|
||||
char *name = tokens[2];
|
||||
|
||||
|
|
|
@ -1,450 +0,0 @@
|
|||
// Copyright (c) 2010 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.
|
||||
//
|
||||
// basic_source_line_resolver.cc: BasicSourceLineResolver implementation.
|
||||
//
|
||||
// See basic_source_line_resolver.h and basic_source_line_resolver_types.h
|
||||
// for documentation.
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "google_breakpad/processor/basic_source_line_resolver.h"
|
||||
#include "processor/basic_source_line_resolver_types.h"
|
||||
#include "processor/module_factory.h"
|
||||
|
||||
#include "processor/tokenize.h"
|
||||
|
||||
using std::map;
|
||||
using std::vector;
|
||||
using std::make_pair;
|
||||
|
||||
namespace google_breakpad {
|
||||
|
||||
static const char *kWhitespace = " \r\n";
|
||||
|
||||
BasicSourceLineResolver::BasicSourceLineResolver() :
|
||||
SourceLineResolverBase(new BasicModuleFactory) { }
|
||||
|
||||
bool BasicSourceLineResolver::Module::LoadMapFromMemory(char *memory_buffer) {
|
||||
linked_ptr<Function> cur_func;
|
||||
int line_number = 0;
|
||||
char *save_ptr;
|
||||
size_t map_buffer_length = strlen(memory_buffer);
|
||||
|
||||
// If the length is 0, we can still pretend we have a symbol file. This is
|
||||
// for scenarios that want to test symbol lookup, but don't necessarily care
|
||||
// if certain modules do not have any information, like system libraries.
|
||||
if (map_buffer_length == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (memory_buffer[map_buffer_length - 1] == '\n') {
|
||||
memory_buffer[map_buffer_length - 1] = '\0';
|
||||
}
|
||||
|
||||
char *buffer;
|
||||
buffer = strtok_r(memory_buffer, "\r\n", &save_ptr);
|
||||
|
||||
while (buffer != NULL) {
|
||||
++line_number;
|
||||
|
||||
if (strncmp(buffer, "FILE ", 5) == 0) {
|
||||
if (!ParseFile(buffer)) {
|
||||
BPLOG(ERROR) << "ParseFile on buffer failed at " <<
|
||||
":" << line_number;
|
||||
return false;
|
||||
}
|
||||
} else if (strncmp(buffer, "STACK ", 6) == 0) {
|
||||
if (!ParseStackInfo(buffer)) {
|
||||
BPLOG(ERROR) << "ParseStackInfo failed at " <<
|
||||
":" << line_number;
|
||||
return false;
|
||||
}
|
||||
} else if (strncmp(buffer, "FUNC ", 5) == 0) {
|
||||
cur_func.reset(ParseFunction(buffer));
|
||||
if (!cur_func.get()) {
|
||||
BPLOG(ERROR) << "ParseFunction failed at " <<
|
||||
":" << line_number;
|
||||
return false;
|
||||
}
|
||||
// StoreRange will fail if the function has an invalid address or size.
|
||||
// We'll silently ignore this, the function and any corresponding lines
|
||||
// will be destroyed when cur_func is released.
|
||||
functions_.StoreRange(cur_func->address, cur_func->size, cur_func);
|
||||
} else if (strncmp(buffer, "PUBLIC ", 7) == 0) {
|
||||
// Clear cur_func: public symbols don't contain line number information.
|
||||
cur_func.reset();
|
||||
|
||||
if (!ParsePublicSymbol(buffer)) {
|
||||
BPLOG(ERROR) << "ParsePublicSymbol failed at " <<
|
||||
":" << line_number;
|
||||
return false;
|
||||
}
|
||||
} else if (strncmp(buffer, "MODULE ", 7) == 0) {
|
||||
// Ignore these. They're not of any use to BasicSourceLineResolver,
|
||||
// which is fed modules by a SymbolSupplier. These lines are present to
|
||||
// aid other tools in properly placing symbol files so that they can
|
||||
// be accessed by a SymbolSupplier.
|
||||
//
|
||||
// MODULE <guid> <age> <filename>
|
||||
} else if (strncmp(buffer, "INFO ", 5) == 0) {
|
||||
// Ignore these as well, they're similarly just for housekeeping.
|
||||
//
|
||||
// INFO CODE_ID <code id> <filename>
|
||||
} else {
|
||||
if (!cur_func.get()) {
|
||||
BPLOG(ERROR) << "Found source line data without a function at " <<
|
||||
":" << line_number;
|
||||
return false;
|
||||
}
|
||||
Line *line = ParseLine(buffer);
|
||||
if (!line) {
|
||||
BPLOG(ERROR) << "ParseLine failed at " << line_number << " for " <<
|
||||
buffer;
|
||||
return false;
|
||||
}
|
||||
cur_func->lines.StoreRange(line->address, line->size,
|
||||
linked_ptr<Line>(line));
|
||||
}
|
||||
buffer = strtok_r(NULL, "\r\n", &save_ptr);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void BasicSourceLineResolver::Module::LookupAddress(StackFrame *frame) const {
|
||||
MemAddr address = frame->instruction - frame->module->base_address();
|
||||
|
||||
// First, look for a FUNC record that covers address. Use
|
||||
// RetrieveNearestRange instead of RetrieveRange so that, if there
|
||||
// is no such function, we can use the next function to bound the
|
||||
// extent of the PUBLIC symbol we find, below. This does mean we
|
||||
// need to check that address indeed falls within the function we
|
||||
// find; do the range comparison in an overflow-friendly way.
|
||||
linked_ptr<Function> func;
|
||||
linked_ptr<PublicSymbol> public_symbol;
|
||||
MemAddr function_base;
|
||||
MemAddr function_size;
|
||||
MemAddr public_address;
|
||||
if (functions_.RetrieveNearestRange(address, &func,
|
||||
&function_base, &function_size) &&
|
||||
address >= function_base && address - function_base < function_size) {
|
||||
frame->function_name = func->name;
|
||||
frame->function_base = frame->module->base_address() + function_base;
|
||||
|
||||
linked_ptr<Line> line;
|
||||
MemAddr line_base;
|
||||
if (func->lines.RetrieveRange(address, &line, &line_base, NULL)) {
|
||||
FileMap::const_iterator it = files_.find(line->source_file_id);
|
||||
if (it != files_.end()) {
|
||||
frame->source_file_name = files_.find(line->source_file_id)->second;
|
||||
}
|
||||
frame->source_line = line->line;
|
||||
frame->source_line_base = frame->module->base_address() + line_base;
|
||||
}
|
||||
} else if (public_symbols_.Retrieve(address,
|
||||
&public_symbol, &public_address) &&
|
||||
(!func.get() || public_address > function_base)) {
|
||||
frame->function_name = public_symbol->name;
|
||||
frame->function_base = frame->module->base_address() + public_address;
|
||||
}
|
||||
}
|
||||
|
||||
WindowsFrameInfo *BasicSourceLineResolver::Module::FindWindowsFrameInfo(
|
||||
const StackFrame *frame) const {
|
||||
MemAddr address = frame->instruction - frame->module->base_address();
|
||||
scoped_ptr<WindowsFrameInfo> result(new WindowsFrameInfo());
|
||||
|
||||
// We only know about WindowsFrameInfo::STACK_INFO_FRAME_DATA and
|
||||
// WindowsFrameInfo::STACK_INFO_FPO. Prefer them in this order.
|
||||
// WindowsFrameInfo::STACK_INFO_FRAME_DATA is the newer type that
|
||||
// includes its own program string.
|
||||
// WindowsFrameInfo::STACK_INFO_FPO is the older type
|
||||
// corresponding to the FPO_DATA struct. See stackwalker_x86.cc.
|
||||
linked_ptr<WindowsFrameInfo> frame_info;
|
||||
if ((windows_frame_info_[WindowsFrameInfo::STACK_INFO_FRAME_DATA]
|
||||
.RetrieveRange(address, &frame_info))
|
||||
|| (windows_frame_info_[WindowsFrameInfo::STACK_INFO_FPO]
|
||||
.RetrieveRange(address, &frame_info))) {
|
||||
result->CopyFrom(*frame_info.get());
|
||||
return result.release();
|
||||
}
|
||||
|
||||
// Even without a relevant STACK line, many functions contain
|
||||
// information about how much space their parameters consume on the
|
||||
// stack. Use RetrieveNearestRange instead of RetrieveRange, so that
|
||||
// we can use the function to bound the extent of the PUBLIC symbol,
|
||||
// below. However, this does mean we need to check that ADDRESS
|
||||
// falls within the retrieved function's range; do the range
|
||||
// comparison in an overflow-friendly way.
|
||||
linked_ptr<Function> function;
|
||||
MemAddr function_base, function_size;
|
||||
if (functions_.RetrieveNearestRange(address, &function,
|
||||
&function_base, &function_size) &&
|
||||
address >= function_base && address - function_base < function_size) {
|
||||
result->parameter_size = function->parameter_size;
|
||||
result->valid |= WindowsFrameInfo::VALID_PARAMETER_SIZE;
|
||||
return result.release();
|
||||
}
|
||||
|
||||
// PUBLIC symbols might have a parameter size. Use the function we
|
||||
// found above to limit the range the public symbol covers.
|
||||
linked_ptr<PublicSymbol> public_symbol;
|
||||
MemAddr public_address;
|
||||
if (public_symbols_.Retrieve(address, &public_symbol, &public_address) &&
|
||||
(!function.get() || public_address > function_base)) {
|
||||
result->parameter_size = public_symbol->parameter_size;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CFIFrameInfo *BasicSourceLineResolver::Module::FindCFIFrameInfo(
|
||||
const StackFrame *frame) const {
|
||||
MemAddr address = frame->instruction - frame->module->base_address();
|
||||
MemAddr initial_base, initial_size;
|
||||
string initial_rules;
|
||||
|
||||
// Find the initial rule whose range covers this address. That
|
||||
// provides an initial set of register recovery rules. Then, walk
|
||||
// forward from the initial rule's starting address to frame's
|
||||
// instruction address, applying delta rules.
|
||||
if (!cfi_initial_rules_.RetrieveRange(address, &initial_rules,
|
||||
&initial_base, &initial_size)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Create a frame info structure, and populate it with the rules from
|
||||
// the STACK CFI INIT record.
|
||||
scoped_ptr<CFIFrameInfo> rules(new CFIFrameInfo());
|
||||
if (!ParseCFIRuleSet(initial_rules, rules.get()))
|
||||
return NULL;
|
||||
|
||||
// Find the first delta rule that falls within the initial rule's range.
|
||||
map<MemAddr, string>::const_iterator delta =
|
||||
cfi_delta_rules_.lower_bound(initial_base);
|
||||
|
||||
// Apply delta rules up to and including the frame's address.
|
||||
while (delta != cfi_delta_rules_.end() && delta->first <= address) {
|
||||
ParseCFIRuleSet(delta->second, rules.get());
|
||||
delta++;
|
||||
}
|
||||
|
||||
return rules.release();
|
||||
}
|
||||
|
||||
bool BasicSourceLineResolver::Module::ParseFile(char *file_line) {
|
||||
// FILE <id> <filename>
|
||||
file_line += 5; // skip prefix
|
||||
|
||||
vector<char*> tokens;
|
||||
if (!Tokenize(file_line, kWhitespace, 2, &tokens)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int index = atoi(tokens[0]);
|
||||
if (index < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
char *filename = tokens[1];
|
||||
if (!filename) {
|
||||
return false;
|
||||
}
|
||||
|
||||
files_.insert(make_pair(index, string(filename)));
|
||||
return true;
|
||||
}
|
||||
|
||||
BasicSourceLineResolver::Function*
|
||||
BasicSourceLineResolver::Module::ParseFunction(char *function_line) {
|
||||
// FUNC <address> <size> <stack_param_size> <name>
|
||||
function_line += 5; // skip prefix
|
||||
|
||||
vector<char*> tokens;
|
||||
if (!Tokenize(function_line, kWhitespace, 4, &tokens)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
u_int64_t address = strtoull(tokens[0], NULL, 16);
|
||||
u_int64_t size = strtoull(tokens[1], NULL, 16);
|
||||
int stack_param_size = strtoull(tokens[2], NULL, 16);
|
||||
char *name = tokens[3];
|
||||
|
||||
return new Function(name, address, size, stack_param_size);
|
||||
}
|
||||
|
||||
BasicSourceLineResolver::Line* BasicSourceLineResolver::Module::ParseLine(
|
||||
char *line_line) {
|
||||
// <address> <line number> <source file id>
|
||||
vector<char*> tokens;
|
||||
if (!Tokenize(line_line, kWhitespace, 4, &tokens)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
u_int64_t address = strtoull(tokens[0], NULL, 16);
|
||||
u_int64_t size = strtoull(tokens[1], NULL, 16);
|
||||
int line_number = atoi(tokens[2]);
|
||||
int source_file = atoi(tokens[3]);
|
||||
if (line_number <= 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return new Line(address, size, source_file, line_number);
|
||||
}
|
||||
|
||||
bool BasicSourceLineResolver::Module::ParsePublicSymbol(char *public_line) {
|
||||
// PUBLIC <address> <stack_param_size> <name>
|
||||
|
||||
// Skip "PUBLIC " prefix.
|
||||
public_line += 7;
|
||||
|
||||
vector<char*> tokens;
|
||||
if (!Tokenize(public_line, kWhitespace, 3, &tokens)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
u_int64_t address = strtoull(tokens[0], NULL, 16);
|
||||
int stack_param_size = strtoull(tokens[1], NULL, 16);
|
||||
char *name = tokens[2];
|
||||
|
||||
// A few public symbols show up with an address of 0. This has been seen
|
||||
// in the dumped output of ntdll.pdb for symbols such as _CIlog, _CIpow,
|
||||
// RtlDescribeChunkLZNT1, and RtlReserveChunkLZNT1. They would conflict
|
||||
// with one another if they were allowed into the public_symbols_ map,
|
||||
// but since the address is obviously invalid, gracefully accept them
|
||||
// as input without putting them into the map.
|
||||
if (address == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
linked_ptr<PublicSymbol> symbol(new PublicSymbol(name, address,
|
||||
stack_param_size));
|
||||
return public_symbols_.Store(address, symbol);
|
||||
}
|
||||
|
||||
bool BasicSourceLineResolver::Module::ParseStackInfo(char *stack_info_line) {
|
||||
// Skip "STACK " prefix.
|
||||
stack_info_line += 6;
|
||||
|
||||
// Find the token indicating what sort of stack frame walking
|
||||
// information this is.
|
||||
while (*stack_info_line == ' ')
|
||||
stack_info_line++;
|
||||
const char *platform = stack_info_line;
|
||||
while (!strchr(kWhitespace, *stack_info_line))
|
||||
stack_info_line++;
|
||||
*stack_info_line++ = '\0';
|
||||
|
||||
// MSVC stack frame info.
|
||||
if (strcmp(platform, "WIN") == 0) {
|
||||
int type = 0;
|
||||
u_int64_t rva, code_size;
|
||||
linked_ptr<WindowsFrameInfo>
|
||||
stack_frame_info(WindowsFrameInfo::ParseFromString(stack_info_line,
|
||||
type,
|
||||
rva,
|
||||
code_size));
|
||||
if (stack_frame_info == NULL)
|
||||
return false;
|
||||
|
||||
// TODO(mmentovai): I wanted to use StoreRange's return value as this
|
||||
// method's return value, but MSVC infrequently outputs stack info that
|
||||
// violates the containment rules. This happens with a section of code
|
||||
// in strncpy_s in test_app.cc (testdata/minidump2). There, problem looks
|
||||
// like this:
|
||||
// STACK WIN 4 4242 1a a 0 ... (STACK WIN 4 base size prolog 0 ...)
|
||||
// STACK WIN 4 4243 2e 9 0 ...
|
||||
// ContainedRangeMap treats these two blocks as conflicting. In reality,
|
||||
// when the prolog lengths are taken into account, the actual code of
|
||||
// these blocks doesn't conflict. However, we can't take the prolog lengths
|
||||
// into account directly here because we'd wind up with a different set
|
||||
// of range conflicts when MSVC outputs stack info like this:
|
||||
// STACK WIN 4 1040 73 33 0 ...
|
||||
// STACK WIN 4 105a 59 19 0 ...
|
||||
// because in both of these entries, the beginning of the code after the
|
||||
// prolog is at 0x1073, and the last byte of contained code is at 0x10b2.
|
||||
// Perhaps we could get away with storing ranges by rva + prolog_size
|
||||
// if ContainedRangeMap were modified to allow replacement of
|
||||
// already-stored values.
|
||||
|
||||
windows_frame_info_[type].StoreRange(rva, code_size, stack_frame_info);
|
||||
return true;
|
||||
} else if (strcmp(platform, "CFI") == 0) {
|
||||
// DWARF CFI stack frame info
|
||||
return ParseCFIFrameInfo(stack_info_line);
|
||||
} else {
|
||||
// Something unrecognized.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool BasicSourceLineResolver::Module::ParseCFIFrameInfo(
|
||||
char *stack_info_line) {
|
||||
char *cursor;
|
||||
|
||||
// Is this an INIT record or a delta record?
|
||||
char *init_or_address = strtok_r(stack_info_line, " \r\n", &cursor);
|
||||
if (!init_or_address)
|
||||
return false;
|
||||
|
||||
if (strcmp(init_or_address, "INIT") == 0) {
|
||||
// This record has the form "STACK INIT <address> <size> <rules...>".
|
||||
char *address_field = strtok_r(NULL, " \r\n", &cursor);
|
||||
if (!address_field) return false;
|
||||
|
||||
char *size_field = strtok_r(NULL, " \r\n", &cursor);
|
||||
if (!size_field) return false;
|
||||
|
||||
char *initial_rules = strtok_r(NULL, "\r\n", &cursor);
|
||||
if (!initial_rules) return false;
|
||||
|
||||
MemAddr address = strtoul(address_field, NULL, 16);
|
||||
MemAddr size = strtoul(size_field, NULL, 16);
|
||||
cfi_initial_rules_.StoreRange(address, size, initial_rules);
|
||||
return true;
|
||||
}
|
||||
|
||||
// This record has the form "STACK <address> <rules...>".
|
||||
char *address_field = init_or_address;
|
||||
char *delta_rules = strtok_r(NULL, "\r\n", &cursor);
|
||||
if (!delta_rules) return false;
|
||||
MemAddr address = strtoul(address_field, NULL, 16);
|
||||
cfi_delta_rules_[address] = delta_rules;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace google_breakpad
|
|
@ -125,7 +125,7 @@ static inline void Swap(uint64_t* value) {
|
|||
|
||||
// Given a pointer to a 128-bit int in the minidump data, set the "low"
|
||||
// and "high" fields appropriately.
|
||||
static void Normalize128(uint128_t* value, bool is_big_endian) {
|
||||
static void Normalize128(uint128_struct* value, bool is_big_endian) {
|
||||
// The struct format is [high, low], so if the format is big-endian,
|
||||
// the most significant bytes will already be in the high field.
|
||||
if (!is_big_endian) {
|
||||
|
@ -137,7 +137,7 @@ static void Normalize128(uint128_t* value, bool is_big_endian) {
|
|||
|
||||
// This just swaps each int64 half of the 128-bit value.
|
||||
// The value should also be normalized by calling Normalize128().
|
||||
static void Swap(uint128_t* value) {
|
||||
static void Swap(uint128_struct* value) {
|
||||
Swap(&value->low);
|
||||
Swap(&value->high);
|
||||
}
|
||||
|
|
|
@ -227,9 +227,10 @@ ProcessResult MinidumpProcessor::Process(
|
|||
|
||||
scoped_ptr<CallStack> stack(new CallStack());
|
||||
if (stackwalker.get()) {
|
||||
if (!stackwalker->Walk(stack.get())) {
|
||||
BPLOG(INFO) << "Stackwalker interrupt (missing symbols?) at " <<
|
||||
thread_string;
|
||||
if (!stackwalker->Walk(stack.get(),
|
||||
&process_state->modules_without_symbols_)) {
|
||||
BPLOG(INFO) << "Stackwalker interrupt (missing symbols?) at "
|
||||
<< thread_string;
|
||||
interrupted = true;
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -333,7 +333,51 @@ static void PrintStackMachineReadable(int thread_num, const CallStack *stack) {
|
|||
}
|
||||
}
|
||||
|
||||
static void PrintModules(const CodeModules *modules) {
|
||||
// ContainsModule checks whether a given |module| is in the vector
|
||||
// |modules_without_symbols|.
|
||||
static bool ContainsModule(
|
||||
const vector<const CodeModule*> *modules,
|
||||
const CodeModule *module) {
|
||||
assert(modules);
|
||||
assert(module);
|
||||
vector<const CodeModule*>::const_iterator iter;
|
||||
for (iter = modules->begin(); iter != modules->end(); ++iter) {
|
||||
if (module->debug_file().compare((*iter)->debug_file()) == 0 &&
|
||||
module->debug_identifier().compare((*iter)->debug_identifier()) == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// PrintModule prints a single |module| to stdout.
|
||||
// |modules_without_symbols| should contain the list of modules that were
|
||||
// confirmed to be missing their symbols during the stack walk.
|
||||
static void PrintModule(
|
||||
const CodeModule *module,
|
||||
const vector<const CodeModule*> *modules_without_symbols,
|
||||
uint64_t main_address) {
|
||||
string missing_symbols;
|
||||
if (ContainsModule(modules_without_symbols, module)) {
|
||||
missing_symbols = " (WARNING: No symbols, " +
|
||||
PathnameStripper::File(module->debug_file()) + ", " +
|
||||
module->debug_identifier() + ")";
|
||||
}
|
||||
uint64_t base_address = module->base_address();
|
||||
printf("0x%08" PRIx64 " - 0x%08" PRIx64 " %s %s%s%s\n",
|
||||
base_address, base_address + module->size() - 1,
|
||||
PathnameStripper::File(module->code_file()).c_str(),
|
||||
module->version().empty() ? "???" : module->version().c_str(),
|
||||
main_address != 0 && base_address == main_address ? " (main)" : "",
|
||||
missing_symbols.c_str());
|
||||
}
|
||||
|
||||
// PrintModules prints the list of all loaded |modules| to stdout.
|
||||
// |modules_without_symbols| should contain the list of modules that were
|
||||
// confirmed to be missing their symbols during the stack walk.
|
||||
static void PrintModules(
|
||||
const CodeModules *modules,
|
||||
const vector<const CodeModule*> *modules_without_symbols) {
|
||||
if (!modules)
|
||||
return;
|
||||
|
||||
|
@ -351,13 +395,7 @@ static void PrintModules(const CodeModules *modules) {
|
|||
module_sequence < module_count;
|
||||
++module_sequence) {
|
||||
const CodeModule *module = modules->GetModuleAtSequence(module_sequence);
|
||||
uint64_t base_address = module->base_address();
|
||||
printf("0x%08" PRIx64 " - 0x%08" PRIx64 " %s %s%s\n",
|
||||
base_address, base_address + module->size() - 1,
|
||||
PathnameStripper::File(module->code_file()).c_str(),
|
||||
module->version().empty() ? "???" : module->version().c_str(),
|
||||
main_module != NULL && base_address == main_address ?
|
||||
" (main)" : "");
|
||||
PrintModule(module, modules_without_symbols, main_address);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -449,7 +487,8 @@ static void PrintProcessState(const ProcessState& process_state) {
|
|||
}
|
||||
}
|
||||
|
||||
PrintModules(process_state.modules());
|
||||
PrintModules(process_state.modules(),
|
||||
process_state.modules_without_symbols());
|
||||
}
|
||||
|
||||
static void PrintProcessStateMachineReadable(const ProcessState& process_state)
|
||||
|
|
|
@ -57,6 +57,9 @@ void ProcessState::Clear() {
|
|||
}
|
||||
threads_.clear();
|
||||
system_info_.Clear();
|
||||
// modules_without_symbols_ DOES NOT owns the underlying CodeModule pointers.
|
||||
// Just clear the vector.
|
||||
modules_without_symbols_.clear();
|
||||
delete modules_;
|
||||
modules_ = NULL;
|
||||
}
|
||||
|
|
|
@ -70,11 +70,16 @@ Stackwalker::Stackwalker(const SystemInfo* system_info,
|
|||
}
|
||||
|
||||
|
||||
bool Stackwalker::Walk(CallStack* stack) {
|
||||
bool Stackwalker::Walk(CallStack* stack,
|
||||
vector<const CodeModule*>* modules_without_symbols) {
|
||||
BPLOG_IF(ERROR, !stack) << "Stackwalker::Walk requires |stack|";
|
||||
assert(stack);
|
||||
stack->Clear();
|
||||
|
||||
BPLOG_IF(ERROR, !modules_without_symbols) << "Stackwalker::Walk requires "
|
||||
<< "|modules_without_symbols|";
|
||||
assert(modules_without_symbols);
|
||||
|
||||
// Begin with the context frame, and keep getting callers until there are
|
||||
// no more.
|
||||
|
||||
|
@ -95,6 +100,27 @@ bool Stackwalker::Walk(CallStack* stack) {
|
|||
return false;
|
||||
}
|
||||
|
||||
// Keep track of modules that have no symbols.
|
||||
if (symbolizer_result == StackFrameSymbolizer::kError &&
|
||||
frame->module != NULL) {
|
||||
bool found = false;
|
||||
vector<const CodeModule*>::iterator iter;
|
||||
for (iter = modules_without_symbols->begin();
|
||||
iter != modules_without_symbols->end();
|
||||
++iter) {
|
||||
if (*iter == frame->module) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
BPLOG(INFO) << "Couldn't load symbols for: "
|
||||
<< frame->module->debug_file() << "|"
|
||||
<< frame->module->debug_identifier();
|
||||
modules_without_symbols->push_back(frame->module);
|
||||
}
|
||||
}
|
||||
|
||||
// Add the frame to the call stack. Relinquish the ownership claim
|
||||
// over the frame, because the stack now owns it.
|
||||
stack->frames_.push_back(frame.release());
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#include "google_breakpad/common/minidump_format.h"
|
||||
#include "google_breakpad/processor/basic_source_line_resolver.h"
|
||||
#include "google_breakpad/processor/call_stack.h"
|
||||
#include "google_breakpad/processor/code_module.h"
|
||||
#include "google_breakpad/processor/source_line_resolver_interface.h"
|
||||
#include "google_breakpad/processor/stack_frame_cpu.h"
|
||||
#include "processor/stackwalker_unittest_utils.h"
|
||||
|
@ -48,6 +49,7 @@
|
|||
|
||||
using google_breakpad::BasicSourceLineResolver;
|
||||
using google_breakpad::CallStack;
|
||||
using google_breakpad::CodeModule;
|
||||
using google_breakpad::StackFrameSymbolizer;
|
||||
using google_breakpad::StackFrame;
|
||||
using google_breakpad::StackFrameAMD64;
|
||||
|
@ -143,7 +145,10 @@ TEST_F(SanityCheck, NoResolver) {
|
|||
StackwalkerAMD64 walker(&system_info, &raw_context, &stack_region, &modules,
|
||||
&frame_symbolizer);
|
||||
// This should succeed even without a resolver or supplier.
|
||||
ASSERT_TRUE(walker.Walk(&call_stack));
|
||||
vector<const CodeModule*> modules_without_symbols;
|
||||
ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
|
||||
ASSERT_EQ(1U, modules_without_symbols.size());
|
||||
ASSERT_EQ("module1", modules_without_symbols[0]->debug_file());
|
||||
frames = call_stack.frames();
|
||||
ASSERT_GE(1U, frames->size());
|
||||
StackFrameAMD64 *frame = static_cast<StackFrameAMD64 *>(frames->at(0));
|
||||
|
@ -163,7 +168,10 @@ TEST_F(GetContextFrame, Simple) {
|
|||
StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
|
||||
StackwalkerAMD64 walker(&system_info, &raw_context, &stack_region, &modules,
|
||||
&frame_symbolizer);
|
||||
ASSERT_TRUE(walker.Walk(&call_stack));
|
||||
vector<const CodeModule*> modules_without_symbols;
|
||||
ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
|
||||
ASSERT_EQ(1U, modules_without_symbols.size());
|
||||
ASSERT_EQ("module1", modules_without_symbols[0]->debug_file());
|
||||
frames = call_stack.frames();
|
||||
ASSERT_GE(1U, frames->size());
|
||||
StackFrameAMD64 *frame = static_cast<StackFrameAMD64 *>(frames->at(0));
|
||||
|
@ -181,7 +189,10 @@ TEST_F(GetContextFrame, NoStackMemory) {
|
|||
StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
|
||||
StackwalkerAMD64 walker(&system_info, &raw_context, NULL, &modules,
|
||||
&frame_symbolizer);
|
||||
ASSERT_TRUE(walker.Walk(&call_stack));
|
||||
vector<const CodeModule*> modules_without_symbols;
|
||||
ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
|
||||
ASSERT_EQ(1U, modules_without_symbols.size());
|
||||
ASSERT_EQ("module1", modules_without_symbols[0]->debug_file());
|
||||
frames = call_stack.frames();
|
||||
ASSERT_GE(1U, frames->size());
|
||||
StackFrameAMD64 *frame = static_cast<StackFrameAMD64 *>(frames->at(0));
|
||||
|
@ -236,7 +247,11 @@ TEST_F(GetCallerFrame, ScanWithoutSymbols) {
|
|||
StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
|
||||
StackwalkerAMD64 walker(&system_info, &raw_context, &stack_region, &modules,
|
||||
&frame_symbolizer);
|
||||
ASSERT_TRUE(walker.Walk(&call_stack));
|
||||
vector<const CodeModule*> modules_without_symbols;
|
||||
ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
|
||||
ASSERT_EQ(2U, modules_without_symbols.size());
|
||||
ASSERT_EQ("module1", modules_without_symbols[0]->debug_file());
|
||||
ASSERT_EQ("module2", modules_without_symbols[1]->debug_file());
|
||||
frames = call_stack.frames();
|
||||
ASSERT_EQ(3U, frames->size());
|
||||
|
||||
|
@ -304,7 +319,9 @@ TEST_F(GetCallerFrame, ScanWithFunctionSymbols) {
|
|||
StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
|
||||
StackwalkerAMD64 walker(&system_info, &raw_context, &stack_region, &modules,
|
||||
&frame_symbolizer);
|
||||
ASSERT_TRUE(walker.Walk(&call_stack));
|
||||
vector<const CodeModule*> modules_without_symbols;
|
||||
ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
|
||||
ASSERT_EQ(0U, modules_without_symbols.size());
|
||||
frames = call_stack.frames();
|
||||
ASSERT_EQ(2U, frames->size());
|
||||
|
||||
|
@ -369,7 +386,9 @@ TEST_F(GetCallerFrame, CallerPushedRBP) {
|
|||
StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
|
||||
StackwalkerAMD64 walker(&system_info, &raw_context, &stack_region, &modules,
|
||||
&frame_symbolizer);
|
||||
ASSERT_TRUE(walker.Walk(&call_stack));
|
||||
vector<const CodeModule*> modules_without_symbols;
|
||||
ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
|
||||
ASSERT_EQ(0U, modules_without_symbols.size());
|
||||
frames = call_stack.frames();
|
||||
ASSERT_EQ(2U, frames->size());
|
||||
|
||||
|
@ -445,7 +464,9 @@ struct CFIFixture: public StackwalkerAMD64Fixture {
|
|||
StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
|
||||
StackwalkerAMD64 walker(&system_info, &raw_context, &stack_region, &modules,
|
||||
&frame_symbolizer);
|
||||
ASSERT_TRUE(walker.Walk(&call_stack));
|
||||
vector<const CodeModule*> modules_without_symbols;
|
||||
ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
|
||||
ASSERT_EQ(0U, modules_without_symbols.size());
|
||||
frames = call_stack.frames();
|
||||
ASSERT_EQ(2U, frames->size());
|
||||
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#include "google_breakpad/common/minidump_format.h"
|
||||
#include "google_breakpad/processor/basic_source_line_resolver.h"
|
||||
#include "google_breakpad/processor/call_stack.h"
|
||||
#include "google_breakpad/processor/code_module.h"
|
||||
#include "google_breakpad/processor/source_line_resolver_interface.h"
|
||||
#include "google_breakpad/processor/stack_frame_cpu.h"
|
||||
#include "processor/stackwalker_unittest_utils.h"
|
||||
|
@ -49,6 +50,7 @@
|
|||
|
||||
using google_breakpad::BasicSourceLineResolver;
|
||||
using google_breakpad::CallStack;
|
||||
using google_breakpad::CodeModule;
|
||||
using google_breakpad::StackFrameSymbolizer;
|
||||
using google_breakpad::StackFrame;
|
||||
using google_breakpad::StackFrameARM;
|
||||
|
@ -139,7 +141,9 @@ TEST_F(SanityCheck, NoResolver) {
|
|||
StackwalkerARM walker(&system_info, &raw_context, -1, &stack_region, &modules,
|
||||
&frame_symbolizer);
|
||||
// This should succeed even without a resolver or supplier.
|
||||
ASSERT_TRUE(walker.Walk(&call_stack));
|
||||
vector<const CodeModule*> modules_without_symbols;
|
||||
ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
|
||||
ASSERT_EQ(0U, modules_without_symbols.size());
|
||||
frames = call_stack.frames();
|
||||
ASSERT_EQ(1U, frames->size());
|
||||
StackFrameARM *frame = static_cast<StackFrameARM *>(frames->at(0));
|
||||
|
@ -157,7 +161,9 @@ TEST_F(GetContextFrame, Simple) {
|
|||
StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
|
||||
StackwalkerARM walker(&system_info, &raw_context, -1, &stack_region, &modules,
|
||||
&frame_symbolizer);
|
||||
ASSERT_TRUE(walker.Walk(&call_stack));
|
||||
vector<const CodeModule*> modules_without_symbols;
|
||||
ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
|
||||
ASSERT_EQ(0U, modules_without_symbols.size());
|
||||
frames = call_stack.frames();
|
||||
ASSERT_EQ(1U, frames->size());
|
||||
StackFrameARM *frame = static_cast<StackFrameARM *>(frames->at(0));
|
||||
|
@ -172,7 +178,9 @@ TEST_F(GetContextFrame, NoStackMemory) {
|
|||
StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
|
||||
StackwalkerARM walker(&system_info, &raw_context, -1, NULL, &modules,
|
||||
&frame_symbolizer);
|
||||
ASSERT_TRUE(walker.Walk(&call_stack));
|
||||
vector<const CodeModule*> modules_without_symbols;
|
||||
ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
|
||||
ASSERT_EQ(0U, modules_without_symbols.size());
|
||||
frames = call_stack.frames();
|
||||
ASSERT_EQ(1U, frames->size());
|
||||
StackFrameARM *frame = static_cast<StackFrameARM *>(frames->at(0));
|
||||
|
@ -220,7 +228,11 @@ TEST_F(GetCallerFrame, ScanWithoutSymbols) {
|
|||
StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
|
||||
StackwalkerARM walker(&system_info, &raw_context, -1, &stack_region, &modules,
|
||||
&frame_symbolizer);
|
||||
ASSERT_TRUE(walker.Walk(&call_stack));
|
||||
vector<const CodeModule*> modules_without_symbols;
|
||||
ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
|
||||
ASSERT_EQ(2U, modules_without_symbols.size());
|
||||
ASSERT_EQ("module1", modules_without_symbols[0]->debug_file());
|
||||
ASSERT_EQ("module2", modules_without_symbols[1]->debug_file());
|
||||
frames = call_stack.frames();
|
||||
ASSERT_EQ(3U, frames->size());
|
||||
|
||||
|
@ -284,7 +296,9 @@ TEST_F(GetCallerFrame, ScanWithFunctionSymbols) {
|
|||
StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
|
||||
StackwalkerARM walker(&system_info, &raw_context, -1, &stack_region, &modules,
|
||||
&frame_symbolizer);
|
||||
ASSERT_TRUE(walker.Walk(&call_stack));
|
||||
vector<const CodeModule*> modules_without_symbols;
|
||||
ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
|
||||
ASSERT_EQ(0U, modules_without_symbols.size());
|
||||
frames = call_stack.frames();
|
||||
ASSERT_EQ(2U, frames->size());
|
||||
|
||||
|
@ -345,7 +359,11 @@ TEST_F(GetCallerFrame, ScanFirstFrame) {
|
|||
StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
|
||||
StackwalkerARM walker(&system_info, &raw_context, -1, &stack_region, &modules,
|
||||
&frame_symbolizer);
|
||||
ASSERT_TRUE(walker.Walk(&call_stack));
|
||||
vector<const CodeModule*> modules_without_symbols;
|
||||
ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
|
||||
ASSERT_EQ(2U, modules_without_symbols.size());
|
||||
ASSERT_EQ("module1", modules_without_symbols[0]->debug_file());
|
||||
ASSERT_EQ("module2", modules_without_symbols[1]->debug_file());
|
||||
frames = call_stack.frames();
|
||||
ASSERT_EQ(2U, frames->size());
|
||||
|
||||
|
@ -453,7 +471,9 @@ struct CFIFixture: public StackwalkerARMFixture {
|
|||
StackwalkerARM walker(&system_info, &raw_context, -1, &stack_region,
|
||||
&modules, &frame_symbolizer);
|
||||
walker.SetContextFrameValidity(context_frame_validity);
|
||||
ASSERT_TRUE(walker.Walk(&call_stack));
|
||||
vector<const CodeModule*> modules_without_symbols;
|
||||
ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
|
||||
ASSERT_EQ(0U, modules_without_symbols.size());
|
||||
frames = call_stack.frames();
|
||||
ASSERT_EQ(2U, frames->size());
|
||||
|
||||
|
@ -645,7 +665,9 @@ TEST_F(CFI, RejectBackwards) {
|
|||
StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
|
||||
StackwalkerARM walker(&system_info, &raw_context, -1, &stack_region, &modules,
|
||||
&frame_symbolizer);
|
||||
ASSERT_TRUE(walker.Walk(&call_stack));
|
||||
vector<const CodeModule*> modules_without_symbols;
|
||||
ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
|
||||
ASSERT_EQ(0U, modules_without_symbols.size());
|
||||
frames = call_stack.frames();
|
||||
ASSERT_EQ(1U, frames->size());
|
||||
}
|
||||
|
@ -657,7 +679,9 @@ TEST_F(CFI, RejectBadExpressions) {
|
|||
StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
|
||||
StackwalkerARM walker(&system_info, &raw_context, -1, &stack_region, &modules,
|
||||
&frame_symbolizer);
|
||||
ASSERT_TRUE(walker.Walk(&call_stack));
|
||||
vector<const CodeModule*> modules_without_symbols;
|
||||
ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
|
||||
ASSERT_EQ(0U, modules_without_symbols.size());
|
||||
frames = call_stack.frames();
|
||||
ASSERT_EQ(1U, frames->size());
|
||||
}
|
||||
|
@ -715,7 +739,11 @@ TEST_F(GetFramesByFramePointer, OnlyFramePointer) {
|
|||
StackwalkerARM walker(&system_info, &raw_context, MD_CONTEXT_ARM_REG_IOS_FP,
|
||||
&stack_region, &modules, &frame_symbolizer);
|
||||
|
||||
ASSERT_TRUE(walker.Walk(&call_stack));
|
||||
vector<const CodeModule*> modules_without_symbols;
|
||||
ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
|
||||
ASSERT_EQ(2U, modules_without_symbols.size());
|
||||
ASSERT_EQ("module1", modules_without_symbols[0]->debug_file());
|
||||
ASSERT_EQ("module2", modules_without_symbols[1]->debug_file());
|
||||
frames = call_stack.frames();
|
||||
ASSERT_EQ(3U, frames->size());
|
||||
|
||||
|
@ -805,7 +833,10 @@ TEST_F(GetFramesByFramePointer, FramePointerAndCFI) {
|
|||
StackwalkerARM walker(&system_info, &raw_context, MD_CONTEXT_ARM_REG_IOS_FP,
|
||||
&stack_region, &modules, &frame_symbolizer);
|
||||
|
||||
ASSERT_TRUE(walker.Walk(&call_stack));
|
||||
vector<const CodeModule*> modules_without_symbols;
|
||||
ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
|
||||
ASSERT_EQ(1U, modules_without_symbols.size());
|
||||
ASSERT_EQ("module2", modules_without_symbols[0]->debug_file());
|
||||
frames = call_stack.frames();
|
||||
ASSERT_EQ(3U, frames->size());
|
||||
|
||||
|
|
|
@ -69,12 +69,14 @@
|
|||
#include "google_breakpad/common/minidump_format.h"
|
||||
#include "google_breakpad/processor/basic_source_line_resolver.h"
|
||||
#include "google_breakpad/processor/call_stack.h"
|
||||
#include "google_breakpad/processor/code_module.h"
|
||||
#include "google_breakpad/processor/memory_region.h"
|
||||
#include "google_breakpad/processor/stack_frame.h"
|
||||
#include "google_breakpad/processor/stack_frame_cpu.h"
|
||||
|
||||
using google_breakpad::BasicSourceLineResolver;
|
||||
using google_breakpad::CallStack;
|
||||
using google_breakpad::CodeModule;
|
||||
using google_breakpad::MemoryRegion;
|
||||
using google_breakpad::scoped_ptr;
|
||||
using google_breakpad::StackFrame;
|
||||
|
@ -337,7 +339,8 @@ static unsigned int CountCallerFrames() {
|
|||
#endif // __i386__ || __ppc__ || __sparc__
|
||||
|
||||
CallStack stack;
|
||||
stackwalker.Walk(&stack);
|
||||
vector<const CodeModule*> modules_without_symbols;
|
||||
stackwalker.Walk(&stack, &modules_without_symbols);
|
||||
|
||||
#ifdef PRINT_STACKS
|
||||
printf("\n");
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#include "google_breakpad/common/minidump_format.h"
|
||||
#include "google_breakpad/processor/basic_source_line_resolver.h"
|
||||
#include "google_breakpad/processor/call_stack.h"
|
||||
#include "google_breakpad/processor/code_module.h"
|
||||
#include "google_breakpad/processor/source_line_resolver_interface.h"
|
||||
#include "google_breakpad/processor/stack_frame_cpu.h"
|
||||
#include "processor/stackwalker_unittest_utils.h"
|
||||
|
@ -48,6 +49,7 @@
|
|||
|
||||
using google_breakpad::BasicSourceLineResolver;
|
||||
using google_breakpad::CallStack;
|
||||
using google_breakpad::CodeModule;
|
||||
using google_breakpad::StackFrameSymbolizer;
|
||||
using google_breakpad::StackFrame;
|
||||
using google_breakpad::StackFrameX86;
|
||||
|
@ -153,7 +155,10 @@ TEST_F(SanityCheck, NoResolver) {
|
|||
StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules,
|
||||
&frame_symbolizer);
|
||||
// This should succeed, even without a resolver or supplier.
|
||||
ASSERT_TRUE(walker.Walk(&call_stack));
|
||||
vector<const CodeModule*> modules_without_symbols;
|
||||
ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
|
||||
ASSERT_EQ(1U, modules_without_symbols.size());
|
||||
ASSERT_EQ("module1", modules_without_symbols[0]->debug_file());
|
||||
frames = call_stack.frames();
|
||||
StackFrameX86 *frame = static_cast<StackFrameX86 *>(frames->at(0));
|
||||
// Check that the values from the original raw context made it
|
||||
|
@ -173,7 +178,10 @@ TEST_F(GetContextFrame, Simple) {
|
|||
StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
|
||||
StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules,
|
||||
&frame_symbolizer);
|
||||
ASSERT_TRUE(walker.Walk(&call_stack));
|
||||
vector<const CodeModule*> modules_without_symbols;
|
||||
ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
|
||||
ASSERT_EQ(1U, modules_without_symbols.size());
|
||||
ASSERT_EQ("module1", modules_without_symbols[0]->debug_file());
|
||||
frames = call_stack.frames();
|
||||
StackFrameX86 *frame = static_cast<StackFrameX86 *>(frames->at(0));
|
||||
// Check that the values from the original raw context made it
|
||||
|
@ -190,7 +198,10 @@ TEST_F(GetContextFrame, NoStackMemory) {
|
|||
StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
|
||||
StackwalkerX86 walker(&system_info, &raw_context, NULL, &modules,
|
||||
&frame_symbolizer);
|
||||
ASSERT_TRUE(walker.Walk(&call_stack));
|
||||
vector<const CodeModule*> modules_without_symbols;
|
||||
ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
|
||||
ASSERT_EQ(1U, modules_without_symbols.size());
|
||||
ASSERT_EQ("module1", modules_without_symbols[0]->debug_file());
|
||||
frames = call_stack.frames();
|
||||
StackFrameX86 *frame = static_cast<StackFrameX86 *>(frames->at(0));
|
||||
// Check that the values from the original raw context made it
|
||||
|
@ -223,7 +234,10 @@ TEST_F(GetCallerFrame, Traditional) {
|
|||
StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
|
||||
StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules,
|
||||
&frame_symbolizer);
|
||||
ASSERT_TRUE(walker.Walk(&call_stack));
|
||||
vector<const CodeModule*> modules_without_symbols;
|
||||
ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
|
||||
ASSERT_EQ(1U, modules_without_symbols.size());
|
||||
ASSERT_EQ("module1", modules_without_symbols[0]->debug_file());
|
||||
frames = call_stack.frames();
|
||||
ASSERT_EQ(2U, frames->size());
|
||||
|
||||
|
@ -279,7 +293,10 @@ TEST_F(GetCallerFrame, TraditionalScan) {
|
|||
StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
|
||||
StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules,
|
||||
&frame_symbolizer);
|
||||
ASSERT_TRUE(walker.Walk(&call_stack));
|
||||
vector<const CodeModule*> modules_without_symbols;
|
||||
ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
|
||||
ASSERT_EQ(1U, modules_without_symbols.size());
|
||||
ASSERT_EQ("module1", modules_without_symbols[0]->debug_file());
|
||||
frames = call_stack.frames();
|
||||
ASSERT_EQ(2U, frames->size());
|
||||
|
||||
|
@ -341,7 +358,10 @@ TEST_F(GetCallerFrame, TraditionalScanLongWay) {
|
|||
StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
|
||||
StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules,
|
||||
&frame_symbolizer);
|
||||
ASSERT_TRUE(walker.Walk(&call_stack));
|
||||
vector<const CodeModule*> modules_without_symbols;
|
||||
ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
|
||||
ASSERT_EQ(1U, modules_without_symbols.size());
|
||||
ASSERT_EQ("module1", modules_without_symbols[0]->debug_file());
|
||||
frames = call_stack.frames();
|
||||
ASSERT_EQ(2U, frames->size());
|
||||
|
||||
|
@ -413,7 +433,9 @@ TEST_F(GetCallerFrame, WindowsFrameData) {
|
|||
StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
|
||||
StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules,
|
||||
&frame_symbolizer);
|
||||
ASSERT_TRUE(walker.Walk(&call_stack));
|
||||
vector<const CodeModule*> modules_without_symbols;
|
||||
ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
|
||||
ASSERT_EQ(0U, modules_without_symbols.size());
|
||||
frames = call_stack.frames();
|
||||
ASSERT_EQ(2U, frames->size());
|
||||
|
||||
|
@ -485,7 +507,10 @@ TEST_F(GetCallerFrame, WindowsFrameDataAligned) {
|
|||
StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
|
||||
StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules,
|
||||
&frame_symbolizer);
|
||||
ASSERT_TRUE(walker.Walk(&call_stack));
|
||||
vector<const CodeModule*> modules_without_symbols;
|
||||
ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
|
||||
ASSERT_EQ(1U, modules_without_symbols.size());
|
||||
ASSERT_EQ("module2", modules_without_symbols[0]->debug_file());
|
||||
frames = call_stack.frames();
|
||||
ASSERT_EQ(2U, frames->size());
|
||||
|
||||
|
@ -568,7 +593,9 @@ TEST_F(GetCallerFrame, WindowsFrameDataParameterSize) {
|
|||
StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
|
||||
StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules,
|
||||
&frame_symbolizer);
|
||||
ASSERT_TRUE(walker.Walk(&call_stack));
|
||||
vector<const CodeModule*> modules_without_symbols;
|
||||
ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
|
||||
ASSERT_EQ(0U, modules_without_symbols.size());
|
||||
frames = call_stack.frames();
|
||||
ASSERT_EQ(3U, frames->size());
|
||||
|
||||
|
@ -663,7 +690,9 @@ TEST_F(GetCallerFrame, WindowsFrameDataScan) {
|
|||
StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
|
||||
StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules,
|
||||
&frame_symbolizer);
|
||||
ASSERT_TRUE(walker.Walk(&call_stack));
|
||||
vector<const CodeModule*> modules_without_symbols;
|
||||
ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
|
||||
ASSERT_EQ(0U, modules_without_symbols.size());
|
||||
frames = call_stack.frames();
|
||||
ASSERT_EQ(2U, frames->size());
|
||||
|
||||
|
@ -747,7 +776,9 @@ TEST_F(GetCallerFrame, WindowsFrameDataBadEIPScan) {
|
|||
StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
|
||||
StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules,
|
||||
&frame_symbolizer);
|
||||
ASSERT_TRUE(walker.Walk(&call_stack));
|
||||
vector<const CodeModule*> modules_without_symbols;
|
||||
ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
|
||||
ASSERT_EQ(0U, modules_without_symbols.size());
|
||||
frames = call_stack.frames();
|
||||
ASSERT_EQ(2U, frames->size());
|
||||
|
||||
|
@ -815,7 +846,9 @@ TEST_F(GetCallerFrame, WindowsFPOUnchangedEBP) {
|
|||
StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
|
||||
StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules,
|
||||
&frame_symbolizer);
|
||||
ASSERT_TRUE(walker.Walk(&call_stack));
|
||||
vector<const CodeModule*> modules_without_symbols;
|
||||
ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
|
||||
ASSERT_EQ(0U, modules_without_symbols.size());
|
||||
frames = call_stack.frames();
|
||||
ASSERT_EQ(2U, frames->size());
|
||||
|
||||
|
@ -892,7 +925,9 @@ TEST_F(GetCallerFrame, WindowsFPOUsedEBP) {
|
|||
StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
|
||||
StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules,
|
||||
&frame_symbolizer);
|
||||
ASSERT_TRUE(walker.Walk(&call_stack));
|
||||
vector<const CodeModule*> modules_without_symbols;
|
||||
ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
|
||||
ASSERT_EQ(0U, modules_without_symbols.size());
|
||||
frames = call_stack.frames();
|
||||
ASSERT_EQ(2U, frames->size());
|
||||
|
||||
|
@ -1030,7 +1065,9 @@ TEST_F(GetCallerFrame, WindowsFPOSystemCall) {
|
|||
StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
|
||||
StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules,
|
||||
&frame_symbolizer);
|
||||
ASSERT_TRUE(walker.Walk(&call_stack));
|
||||
vector<const CodeModule*> modules_without_symbols;
|
||||
ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
|
||||
ASSERT_EQ(0U, modules_without_symbols.size());
|
||||
frames = call_stack.frames();
|
||||
|
||||
ASSERT_EQ(4U, frames->size());
|
||||
|
@ -1238,7 +1275,9 @@ TEST_F(GetCallerFrame, ReturnAddressIsNotInKnownModule) {
|
|||
StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
|
||||
StackwalkerX86 walker(&system_info, &raw_context, &stack_region,
|
||||
&local_modules, &frame_symbolizer);
|
||||
ASSERT_TRUE(walker.Walk(&call_stack));
|
||||
vector<const CodeModule*> modules_without_symbols;
|
||||
ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
|
||||
ASSERT_EQ(0U, modules_without_symbols.size());
|
||||
frames = call_stack.frames();
|
||||
|
||||
ASSERT_EQ(3U, frames->size());
|
||||
|
@ -1365,7 +1404,9 @@ struct CFIFixture: public StackwalkerX86Fixture {
|
|||
StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
|
||||
StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules,
|
||||
&frame_symbolizer);
|
||||
ASSERT_TRUE(walker.Walk(&call_stack));
|
||||
vector<const CodeModule*> modules_without_symbols;
|
||||
ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
|
||||
ASSERT_EQ(0U, modules_without_symbols.size());
|
||||
frames = call_stack.frames();
|
||||
ASSERT_EQ(2U, frames->size());
|
||||
|
||||
|
|
|
@ -116,7 +116,7 @@ struct WindowsFrameInfo {
|
|||
int &type,
|
||||
uint64_t &rva,
|
||||
uint64_t &code_size) {
|
||||
// The format of a STACK WIN record is documented at:
|
||||
// The format of a STACK WIN record is documented at:
|
||||
//
|
||||
// http://code.google.com/p/google-breakpad/wiki/SymbolFiles
|
||||
|
||||
|
@ -132,12 +132,12 @@ struct WindowsFrameInfo {
|
|||
|
||||
rva = strtoull(tokens[1], NULL, 16);
|
||||
code_size = strtoull(tokens[2], NULL, 16);
|
||||
uint32_t prolog_size = strtoul(tokens[3], NULL, 16);
|
||||
uint32_t epilog_size = strtoul(tokens[4], NULL, 16);
|
||||
uint32_t parameter_size = strtoul(tokens[5], NULL, 16);
|
||||
uint32_t saved_register_size = strtoul(tokens[6], NULL, 16);
|
||||
uint32_t local_size = strtoul(tokens[7], NULL, 16);
|
||||
uint32_t max_stack_size = strtoul(tokens[8], NULL, 16);
|
||||
uint32_t prolog_size = strtoul(tokens[3], NULL, 16);
|
||||
uint32_t epilog_size = strtoul(tokens[4], NULL, 16);
|
||||
uint32_t parameter_size = strtoul(tokens[5], NULL, 16);
|
||||
uint32_t saved_register_size = strtoul(tokens[6], NULL, 16);
|
||||
uint32_t local_size = strtoul(tokens[7], NULL, 16);
|
||||
uint32_t max_stack_size = strtoul(tokens[8], NULL, 16);
|
||||
int has_program_string = strtoul(tokens[9], NULL, 16);
|
||||
|
||||
const char *program_string = "";
|
||||
|
|
Загрузка…
Ссылка в новой задаче