mirror of
https://github.com/yuzu-emu/breakpad.git
synced 2024-12-23 00:55:41 +00:00
Add logging to minidump processor (#82). Part 2: add messages to the rest of
the processor. r=ted.mielczarek http://groups.google.com/group/google-breakpad-dev/browse_thread/thread/cf56b767383a5d4b git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@172 4c0a9323-5329-0410-9bdc-e9ce6186880e
This commit is contained in:
parent
08c8c4ddcf
commit
65571f17ed
16
Makefile.am
16
Makefile.am
|
@ -128,14 +128,22 @@ TESTS_ENVIRONMENT =
|
||||||
|
|
||||||
src_processor_address_map_unittest_SOURCES = \
|
src_processor_address_map_unittest_SOURCES = \
|
||||||
src/processor/address_map_unittest.cc
|
src/processor/address_map_unittest.cc
|
||||||
|
src_processor_address_map_unittest_LDADD = \
|
||||||
|
src/processor/logging.lo \
|
||||||
|
src/processor/pathname_stripper.lo
|
||||||
|
|
||||||
src_processor_basic_source_line_resolver_unittest_SOURCES = \
|
src_processor_basic_source_line_resolver_unittest_SOURCES = \
|
||||||
src/processor/basic_source_line_resolver_unittest.cc
|
src/processor/basic_source_line_resolver_unittest.cc
|
||||||
src_processor_basic_source_line_resolver_unittest_LDADD = \
|
src_processor_basic_source_line_resolver_unittest_LDADD = \
|
||||||
src/processor/basic_source_line_resolver.lo
|
src/processor/basic_source_line_resolver.lo \
|
||||||
|
src/processor/pathname_stripper.lo \
|
||||||
|
src/processor/logging.lo
|
||||||
|
|
||||||
src_processor_contained_range_map_unittest_SOURCES = \
|
src_processor_contained_range_map_unittest_SOURCES = \
|
||||||
src/processor/contained_range_map_unittest.cc
|
src/processor/contained_range_map_unittest.cc
|
||||||
|
src_processor_contained_range_map_unittest_LDADD = \
|
||||||
|
src/processor/logging.lo \
|
||||||
|
src/processor/pathname_stripper.lo
|
||||||
|
|
||||||
src_processor_minidump_processor_unittest_SOURCES = \
|
src_processor_minidump_processor_unittest_SOURCES = \
|
||||||
src/processor/minidump_processor_unittest.cc
|
src/processor/minidump_processor_unittest.cc
|
||||||
|
@ -159,9 +167,15 @@ src_processor_pathname_stripper_unittest_LDADD = \
|
||||||
|
|
||||||
src_processor_postfix_evaluator_unittest_SOURCES = \
|
src_processor_postfix_evaluator_unittest_SOURCES = \
|
||||||
src/processor/postfix_evaluator_unittest.cc
|
src/processor/postfix_evaluator_unittest.cc
|
||||||
|
src_processor_postfix_evaluator_unittest_LDADD = \
|
||||||
|
src/processor/logging.lo \
|
||||||
|
src/processor/pathname_stripper.lo
|
||||||
|
|
||||||
src_processor_range_map_unittest_SOURCES = \
|
src_processor_range_map_unittest_SOURCES = \
|
||||||
src/processor/range_map_unittest.cc
|
src/processor/range_map_unittest.cc
|
||||||
|
src_processor_range_map_unittest_LDADD = \
|
||||||
|
src/processor/logging.lo \
|
||||||
|
src/processor/pathname_stripper.lo
|
||||||
|
|
||||||
src_processor_stackwalker_selftest_SOURCES = \
|
src_processor_stackwalker_selftest_SOURCES = \
|
||||||
src/processor/stackwalker_selftest.cc
|
src/processor/stackwalker_selftest.cc
|
||||||
|
|
35
Makefile.in
35
Makefile.in
|
@ -123,17 +123,20 @@ am_src_processor_address_map_unittest_OBJECTS = \
|
||||||
src/processor/address_map_unittest.$(OBJEXT)
|
src/processor/address_map_unittest.$(OBJEXT)
|
||||||
src_processor_address_map_unittest_OBJECTS = \
|
src_processor_address_map_unittest_OBJECTS = \
|
||||||
$(am_src_processor_address_map_unittest_OBJECTS)
|
$(am_src_processor_address_map_unittest_OBJECTS)
|
||||||
src_processor_address_map_unittest_LDADD = $(LDADD)
|
src_processor_address_map_unittest_DEPENDENCIES = \
|
||||||
|
src/processor/logging.lo src/processor/pathname_stripper.lo
|
||||||
am_src_processor_basic_source_line_resolver_unittest_OBJECTS = \
|
am_src_processor_basic_source_line_resolver_unittest_OBJECTS = \
|
||||||
src/processor/basic_source_line_resolver_unittest.$(OBJEXT)
|
src/processor/basic_source_line_resolver_unittest.$(OBJEXT)
|
||||||
src_processor_basic_source_line_resolver_unittest_OBJECTS = $(am_src_processor_basic_source_line_resolver_unittest_OBJECTS)
|
src_processor_basic_source_line_resolver_unittest_OBJECTS = $(am_src_processor_basic_source_line_resolver_unittest_OBJECTS)
|
||||||
src_processor_basic_source_line_resolver_unittest_DEPENDENCIES = \
|
src_processor_basic_source_line_resolver_unittest_DEPENDENCIES = \
|
||||||
src/processor/basic_source_line_resolver.lo
|
src/processor/basic_source_line_resolver.lo \
|
||||||
|
src/processor/pathname_stripper.lo src/processor/logging.lo
|
||||||
am_src_processor_contained_range_map_unittest_OBJECTS = \
|
am_src_processor_contained_range_map_unittest_OBJECTS = \
|
||||||
src/processor/contained_range_map_unittest.$(OBJEXT)
|
src/processor/contained_range_map_unittest.$(OBJEXT)
|
||||||
src_processor_contained_range_map_unittest_OBJECTS = \
|
src_processor_contained_range_map_unittest_OBJECTS = \
|
||||||
$(am_src_processor_contained_range_map_unittest_OBJECTS)
|
$(am_src_processor_contained_range_map_unittest_OBJECTS)
|
||||||
src_processor_contained_range_map_unittest_LDADD = $(LDADD)
|
src_processor_contained_range_map_unittest_DEPENDENCIES = \
|
||||||
|
src/processor/logging.lo src/processor/pathname_stripper.lo
|
||||||
am_src_processor_minidump_dump_OBJECTS = \
|
am_src_processor_minidump_dump_OBJECTS = \
|
||||||
src/processor/minidump_dump.$(OBJEXT)
|
src/processor/minidump_dump.$(OBJEXT)
|
||||||
src_processor_minidump_dump_OBJECTS = \
|
src_processor_minidump_dump_OBJECTS = \
|
||||||
|
@ -178,12 +181,14 @@ am_src_processor_postfix_evaluator_unittest_OBJECTS = \
|
||||||
src/processor/postfix_evaluator_unittest.$(OBJEXT)
|
src/processor/postfix_evaluator_unittest.$(OBJEXT)
|
||||||
src_processor_postfix_evaluator_unittest_OBJECTS = \
|
src_processor_postfix_evaluator_unittest_OBJECTS = \
|
||||||
$(am_src_processor_postfix_evaluator_unittest_OBJECTS)
|
$(am_src_processor_postfix_evaluator_unittest_OBJECTS)
|
||||||
src_processor_postfix_evaluator_unittest_LDADD = $(LDADD)
|
src_processor_postfix_evaluator_unittest_DEPENDENCIES = \
|
||||||
|
src/processor/logging.lo src/processor/pathname_stripper.lo
|
||||||
am_src_processor_range_map_unittest_OBJECTS = \
|
am_src_processor_range_map_unittest_OBJECTS = \
|
||||||
src/processor/range_map_unittest.$(OBJEXT)
|
src/processor/range_map_unittest.$(OBJEXT)
|
||||||
src_processor_range_map_unittest_OBJECTS = \
|
src_processor_range_map_unittest_OBJECTS = \
|
||||||
$(am_src_processor_range_map_unittest_OBJECTS)
|
$(am_src_processor_range_map_unittest_OBJECTS)
|
||||||
src_processor_range_map_unittest_LDADD = $(LDADD)
|
src_processor_range_map_unittest_DEPENDENCIES = \
|
||||||
|
src/processor/logging.lo src/processor/pathname_stripper.lo
|
||||||
am_src_processor_stackwalker_selftest_OBJECTS = \
|
am_src_processor_stackwalker_selftest_OBJECTS = \
|
||||||
src/processor/stackwalker_selftest.$(OBJEXT)
|
src/processor/stackwalker_selftest.$(OBJEXT)
|
||||||
src_processor_stackwalker_selftest_OBJECTS = \
|
src_processor_stackwalker_selftest_OBJECTS = \
|
||||||
|
@ -429,15 +434,25 @@ TESTS_ENVIRONMENT =
|
||||||
src_processor_address_map_unittest_SOURCES = \
|
src_processor_address_map_unittest_SOURCES = \
|
||||||
src/processor/address_map_unittest.cc
|
src/processor/address_map_unittest.cc
|
||||||
|
|
||||||
|
src_processor_address_map_unittest_LDADD = \
|
||||||
|
src/processor/logging.lo \
|
||||||
|
src/processor/pathname_stripper.lo
|
||||||
|
|
||||||
src_processor_basic_source_line_resolver_unittest_SOURCES = \
|
src_processor_basic_source_line_resolver_unittest_SOURCES = \
|
||||||
src/processor/basic_source_line_resolver_unittest.cc
|
src/processor/basic_source_line_resolver_unittest.cc
|
||||||
|
|
||||||
src_processor_basic_source_line_resolver_unittest_LDADD = \
|
src_processor_basic_source_line_resolver_unittest_LDADD = \
|
||||||
src/processor/basic_source_line_resolver.lo
|
src/processor/basic_source_line_resolver.lo \
|
||||||
|
src/processor/pathname_stripper.lo \
|
||||||
|
src/processor/logging.lo
|
||||||
|
|
||||||
src_processor_contained_range_map_unittest_SOURCES = \
|
src_processor_contained_range_map_unittest_SOURCES = \
|
||||||
src/processor/contained_range_map_unittest.cc
|
src/processor/contained_range_map_unittest.cc
|
||||||
|
|
||||||
|
src_processor_contained_range_map_unittest_LDADD = \
|
||||||
|
src/processor/logging.lo \
|
||||||
|
src/processor/pathname_stripper.lo
|
||||||
|
|
||||||
src_processor_minidump_processor_unittest_SOURCES = \
|
src_processor_minidump_processor_unittest_SOURCES = \
|
||||||
src/processor/minidump_processor_unittest.cc
|
src/processor/minidump_processor_unittest.cc
|
||||||
|
|
||||||
|
@ -463,9 +478,17 @@ src_processor_pathname_stripper_unittest_LDADD = \
|
||||||
src_processor_postfix_evaluator_unittest_SOURCES = \
|
src_processor_postfix_evaluator_unittest_SOURCES = \
|
||||||
src/processor/postfix_evaluator_unittest.cc
|
src/processor/postfix_evaluator_unittest.cc
|
||||||
|
|
||||||
|
src_processor_postfix_evaluator_unittest_LDADD = \
|
||||||
|
src/processor/logging.lo \
|
||||||
|
src/processor/pathname_stripper.lo
|
||||||
|
|
||||||
src_processor_range_map_unittest_SOURCES = \
|
src_processor_range_map_unittest_SOURCES = \
|
||||||
src/processor/range_map_unittest.cc
|
src/processor/range_map_unittest.cc
|
||||||
|
|
||||||
|
src_processor_range_map_unittest_LDADD = \
|
||||||
|
src/processor/logging.lo \
|
||||||
|
src/processor/pathname_stripper.lo
|
||||||
|
|
||||||
src_processor_stackwalker_selftest_SOURCES = \
|
src_processor_stackwalker_selftest_SOURCES = \
|
||||||
src/processor/stackwalker_selftest.cc
|
src/processor/stackwalker_selftest.cc
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,10 @@
|
||||||
#ifndef PROCESSOR_ADDRESS_MAP_INL_H__
|
#ifndef PROCESSOR_ADDRESS_MAP_INL_H__
|
||||||
#define PROCESSOR_ADDRESS_MAP_INL_H__
|
#define PROCESSOR_ADDRESS_MAP_INL_H__
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
#include "processor/address_map.h"
|
#include "processor/address_map.h"
|
||||||
|
#include "processor/logging.h"
|
||||||
|
|
||||||
namespace google_breakpad {
|
namespace google_breakpad {
|
||||||
|
|
||||||
|
@ -45,8 +48,11 @@ bool AddressMap<AddressType, EntryType>::Store(const AddressType &address,
|
||||||
const EntryType &entry) {
|
const EntryType &entry) {
|
||||||
// Ensure that the specified address doesn't conflict with something already
|
// Ensure that the specified address doesn't conflict with something already
|
||||||
// in the map.
|
// in the map.
|
||||||
if (map_.find(address) != map_.end())
|
if (map_.find(address) != map_.end()) {
|
||||||
|
BPLOG(INFO) << "Store failed, address " << HexString(address) <<
|
||||||
|
" is already present";
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
map_.insert(MapValue(address, entry));
|
map_.insert(MapValue(address, entry));
|
||||||
return true;
|
return true;
|
||||||
|
@ -56,8 +62,8 @@ template<typename AddressType, typename EntryType>
|
||||||
bool AddressMap<AddressType, EntryType>::Retrieve(
|
bool AddressMap<AddressType, EntryType>::Retrieve(
|
||||||
const AddressType &address,
|
const AddressType &address,
|
||||||
EntryType *entry, AddressType *entry_address) const {
|
EntryType *entry, AddressType *entry_address) const {
|
||||||
if (!entry)
|
BPLOG_IF(ERROR, !entry) << "AddressMap::Retrieve requires |entry|";
|
||||||
return false;
|
assert(entry);
|
||||||
|
|
||||||
// upper_bound gives the first element whose key is greater than address,
|
// upper_bound gives the first element whose key is greater than address,
|
||||||
// but we want the first element whose key is less than or equal to address.
|
// but we want the first element whose key is less than or equal to address.
|
||||||
|
|
|
@ -53,8 +53,8 @@ class AddressMap {
|
||||||
bool Store(const AddressType &address, const EntryType &entry);
|
bool Store(const AddressType &address, const EntryType &entry);
|
||||||
|
|
||||||
// Locates the entry stored at the highest address less than or equal to
|
// Locates the entry stored at the highest address less than or equal to
|
||||||
// the address argument. If there is no such range, or if there is a
|
// the address argument. If there is no such range, returns false. The
|
||||||
// parameter error, returns false. The entry is returned in entry. If
|
// entry is returned in entry, which is a required argument. If
|
||||||
// entry_address is not NULL, it will be set to the address that the entry
|
// entry_address is not NULL, it will be set to the address that the entry
|
||||||
// was stored at.
|
// was stored at.
|
||||||
bool Retrieve(const AddressType &address,
|
bool Retrieve(const AddressType &address,
|
||||||
|
|
|
@ -107,7 +107,6 @@ static bool DoAddressMapTest() {
|
||||||
ASSERT_EQ(entry->id(), 1);
|
ASSERT_EQ(entry->id(), 1);
|
||||||
ASSERT_EQ(address, 10);
|
ASSERT_EQ(address, 10);
|
||||||
ASSERT_TRUE(test_map.Retrieve(11, &entry, &address));
|
ASSERT_TRUE(test_map.Retrieve(11, &entry, &address));
|
||||||
ASSERT_FALSE(test_map.Retrieve(11, NULL, &address)); // parameter error
|
|
||||||
ASSERT_TRUE(test_map.Retrieve(11, &entry, NULL)); // NULL ok here
|
ASSERT_TRUE(test_map.Retrieve(11, &entry, NULL)); // NULL ok here
|
||||||
|
|
||||||
// Add some more elements.
|
// Add some more elements.
|
||||||
|
|
|
@ -39,6 +39,7 @@
|
||||||
#include "processor/basic_code_modules.h"
|
#include "processor/basic_code_modules.h"
|
||||||
#include "google_breakpad/processor/code_module.h"
|
#include "google_breakpad/processor/code_module.h"
|
||||||
#include "processor/linked_ptr.h"
|
#include "processor/linked_ptr.h"
|
||||||
|
#include "processor/logging.h"
|
||||||
#include "processor/range_map-inl.h"
|
#include "processor/range_map-inl.h"
|
||||||
|
|
||||||
namespace google_breakpad {
|
namespace google_breakpad {
|
||||||
|
@ -46,6 +47,8 @@ namespace google_breakpad {
|
||||||
BasicCodeModules::BasicCodeModules(const CodeModules *that)
|
BasicCodeModules::BasicCodeModules(const CodeModules *that)
|
||||||
: main_address_(0),
|
: main_address_(0),
|
||||||
map_(new RangeMap<u_int64_t, linked_ptr<const CodeModule> >()) {
|
map_(new RangeMap<u_int64_t, linked_ptr<const CodeModule> >()) {
|
||||||
|
BPLOG_IF(ERROR, !that) << "BasicCodeModules::BasicCodeModules requires "
|
||||||
|
"|that|";
|
||||||
assert(that);
|
assert(that);
|
||||||
|
|
||||||
const CodeModule *main_module = that->GetMainModule();
|
const CodeModule *main_module = that->GetMainModule();
|
||||||
|
@ -61,8 +64,11 @@ BasicCodeModules::BasicCodeModules(const CodeModules *that)
|
||||||
// entire list, and GetModuleAtIndex may be faster than
|
// entire list, and GetModuleAtIndex may be faster than
|
||||||
// GetModuleAtSequence.
|
// GetModuleAtSequence.
|
||||||
const CodeModule *module = that->GetModuleAtIndex(module_sequence)->Copy();
|
const CodeModule *module = that->GetModuleAtIndex(module_sequence)->Copy();
|
||||||
map_->StoreRange(module->base_address(), module->size(),
|
if (!map_->StoreRange(module->base_address(), module->size(),
|
||||||
linked_ptr<const CodeModule>(module));
|
linked_ptr<const CodeModule>(module))) {
|
||||||
|
BPLOG(ERROR) << "Module " << module->code_file() <<
|
||||||
|
" could not be stored";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,8 +83,10 @@ unsigned int BasicCodeModules::module_count() const {
|
||||||
const CodeModule* BasicCodeModules::GetModuleForAddress(
|
const CodeModule* BasicCodeModules::GetModuleForAddress(
|
||||||
u_int64_t address) const {
|
u_int64_t address) const {
|
||||||
linked_ptr<const CodeModule> module;
|
linked_ptr<const CodeModule> module;
|
||||||
if (!map_->RetrieveRange(address, &module, NULL, NULL))
|
if (!map_->RetrieveRange(address, &module, NULL, NULL)) {
|
||||||
|
BPLOG(INFO) << "No module at " << HexString(address);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
return module.get();
|
return module.get();
|
||||||
}
|
}
|
||||||
|
@ -90,8 +98,10 @@ const CodeModule* BasicCodeModules::GetMainModule() const {
|
||||||
const CodeModule* BasicCodeModules::GetModuleAtSequence(
|
const CodeModule* BasicCodeModules::GetModuleAtSequence(
|
||||||
unsigned int sequence) const {
|
unsigned int sequence) const {
|
||||||
linked_ptr<const CodeModule> module;
|
linked_ptr<const CodeModule> module;
|
||||||
if (!map_->RetrieveRangeAtIndex(sequence, &module, NULL, NULL))
|
if (!map_->RetrieveRangeAtIndex(sequence, &module, NULL, NULL)) {
|
||||||
|
BPLOG(ERROR) << "RetrieveRangeAtIndex failed for sequence " << sequence;
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
return module.get();
|
return module.get();
|
||||||
}
|
}
|
||||||
|
|
|
@ -145,7 +145,7 @@ class BasicSourceLineResolver::Module {
|
||||||
static bool Tokenize(char *line, int max_tokens, vector<char*> *tokens);
|
static bool Tokenize(char *line, int max_tokens, vector<char*> *tokens);
|
||||||
|
|
||||||
// Parses a file declaration
|
// Parses a file declaration
|
||||||
void ParseFile(char *file_line);
|
bool ParseFile(char *file_line);
|
||||||
|
|
||||||
// Parses a function declaration, returning a new Function object.
|
// Parses a function declaration, returning a new Function object.
|
||||||
Function* ParseFunction(char *function_line);
|
Function* ParseFunction(char *function_line);
|
||||||
|
@ -188,9 +188,13 @@ bool BasicSourceLineResolver::LoadModule(const string &module_name,
|
||||||
const string &map_file) {
|
const string &map_file) {
|
||||||
// Make sure we don't already have a module with the given name.
|
// Make sure we don't already have a module with the given name.
|
||||||
if (modules_->find(module_name) != modules_->end()) {
|
if (modules_->find(module_name) != modules_->end()) {
|
||||||
|
BPLOG(INFO) << "Symbols for module " << module_name << " already loaded";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BPLOG(INFO) << "Loading symbols for module " << module_name << " from " <<
|
||||||
|
map_file;
|
||||||
|
|
||||||
Module *module = new Module(module_name);
|
Module *module = new Module(module_name);
|
||||||
if (!module->LoadMap(map_file)) {
|
if (!module->LoadMap(map_file)) {
|
||||||
delete module;
|
delete module;
|
||||||
|
@ -216,28 +220,56 @@ StackFrameInfo* BasicSourceLineResolver::FillSourceLineInfo(
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class AutoFileCloser {
|
||||||
|
public:
|
||||||
|
AutoFileCloser(FILE *file) : file_(file) {}
|
||||||
|
~AutoFileCloser() {
|
||||||
|
if (file_)
|
||||||
|
fclose(file_);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
FILE *file_;
|
||||||
|
};
|
||||||
|
|
||||||
bool BasicSourceLineResolver::Module::LoadMap(const string &map_file) {
|
bool BasicSourceLineResolver::Module::LoadMap(const string &map_file) {
|
||||||
FILE *f = fopen(map_file.c_str(), "r");
|
FILE *f = fopen(map_file.c_str(), "r");
|
||||||
if (!f) {
|
if (!f) {
|
||||||
|
string error_string;
|
||||||
|
int error_code = ErrnoString(&error_string);
|
||||||
|
BPLOG(ERROR) << "Could not open " << map_file <<
|
||||||
|
", error " << error_code << ": " << error_string;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AutoFileCloser closer(f);
|
||||||
|
|
||||||
// TODO(mmentovai): this might not be large enough to handle really long
|
// TODO(mmentovai): this might not be large enough to handle really long
|
||||||
// lines, which might be present for FUNC lines of highly-templatized
|
// lines, which might be present for FUNC lines of highly-templatized
|
||||||
// code.
|
// code.
|
||||||
char buffer[8192];
|
char buffer[8192];
|
||||||
linked_ptr<Function> cur_func;
|
linked_ptr<Function> cur_func;
|
||||||
|
|
||||||
|
int line_number = 0;
|
||||||
while (fgets(buffer, sizeof(buffer), f)) {
|
while (fgets(buffer, sizeof(buffer), f)) {
|
||||||
|
++line_number;
|
||||||
if (strncmp(buffer, "FILE ", 5) == 0) {
|
if (strncmp(buffer, "FILE ", 5) == 0) {
|
||||||
ParseFile(buffer);
|
if (!ParseFile(buffer)) {
|
||||||
|
BPLOG(ERROR) << "ParseFile failed at " <<
|
||||||
|
map_file << ":" << line_number;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
} else if (strncmp(buffer, "STACK ", 6) == 0) {
|
} else if (strncmp(buffer, "STACK ", 6) == 0) {
|
||||||
if (!ParseStackInfo(buffer)) {
|
if (!ParseStackInfo(buffer)) {
|
||||||
|
BPLOG(ERROR) << "ParseStackInfo failed at " <<
|
||||||
|
map_file << ":" << line_number;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (strncmp(buffer, "FUNC ", 5) == 0) {
|
} else if (strncmp(buffer, "FUNC ", 5) == 0) {
|
||||||
cur_func.reset(ParseFunction(buffer));
|
cur_func.reset(ParseFunction(buffer));
|
||||||
if (!cur_func.get()) {
|
if (!cur_func.get()) {
|
||||||
|
BPLOG(ERROR) << "ParseFunction failed at " <<
|
||||||
|
map_file << ":" << line_number;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// StoreRange will fail if the function has an invalid address or size.
|
// StoreRange will fail if the function has an invalid address or size.
|
||||||
|
@ -249,6 +281,8 @@ bool BasicSourceLineResolver::Module::LoadMap(const string &map_file) {
|
||||||
cur_func.reset();
|
cur_func.reset();
|
||||||
|
|
||||||
if (!ParsePublicSymbol(buffer)) {
|
if (!ParsePublicSymbol(buffer)) {
|
||||||
|
BPLOG(ERROR) << "ParsePublicSymbol failed at " <<
|
||||||
|
map_file << ":" << line_number;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else if (strncmp(buffer, "MODULE ", 7) == 0) {
|
} else if (strncmp(buffer, "MODULE ", 7) == 0) {
|
||||||
|
@ -260,10 +294,14 @@ bool BasicSourceLineResolver::Module::LoadMap(const string &map_file) {
|
||||||
// MODULE <guid> <age> <filename>
|
// MODULE <guid> <age> <filename>
|
||||||
} else {
|
} else {
|
||||||
if (!cur_func.get()) {
|
if (!cur_func.get()) {
|
||||||
|
BPLOG(ERROR) << "Found source line data without a function at " <<
|
||||||
|
map_file << ":" << line_number;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Line *line = ParseLine(buffer);
|
Line *line = ParseLine(buffer);
|
||||||
if (!line) {
|
if (!line) {
|
||||||
|
BPLOG(ERROR) << "ParseLine failed at " <<
|
||||||
|
map_file << ":" << line_number;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
cur_func->lines.StoreRange(line->address, line->size,
|
cur_func->lines.StoreRange(line->address, line->size,
|
||||||
|
@ -271,7 +309,6 @@ bool BasicSourceLineResolver::Module::LoadMap(const string &map_file) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fclose(f);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -387,24 +424,27 @@ bool BasicSourceLineResolver::Module::Tokenize(char *line, int max_tokens,
|
||||||
return tokens->size() == static_cast<unsigned int>(max_tokens);
|
return tokens->size() == static_cast<unsigned int>(max_tokens);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BasicSourceLineResolver::Module::ParseFile(char *file_line) {
|
bool BasicSourceLineResolver::Module::ParseFile(char *file_line) {
|
||||||
// FILE <id> <filename>
|
// FILE <id> <filename>
|
||||||
file_line += 5; // skip prefix
|
file_line += 5; // skip prefix
|
||||||
|
|
||||||
vector<char*> tokens;
|
vector<char*> tokens;
|
||||||
if (!Tokenize(file_line, 2, &tokens)) {
|
if (!Tokenize(file_line, 2, &tokens)) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int index = atoi(tokens[0]);
|
int index = atoi(tokens[0]);
|
||||||
if (index < 0) {
|
if (index < 0) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *filename = tokens[1];
|
char *filename = tokens[1];
|
||||||
if (filename) {
|
if (!filename) {
|
||||||
files_.insert(make_pair(index, string(filename)));
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
files_.insert(make_pair(index, string(filename)));
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
BasicSourceLineResolver::Function*
|
BasicSourceLineResolver::Function*
|
||||||
|
|
|
@ -37,7 +37,10 @@
|
||||||
#define PROCESSOR_CONTAINED_RANGE_MAP_INL_H__
|
#define PROCESSOR_CONTAINED_RANGE_MAP_INL_H__
|
||||||
|
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
#include "processor/contained_range_map.h"
|
#include "processor/contained_range_map.h"
|
||||||
|
#include "processor/logging.h"
|
||||||
|
|
||||||
|
|
||||||
namespace google_breakpad {
|
namespace google_breakpad {
|
||||||
|
@ -56,8 +59,11 @@ bool ContainedRangeMap<AddressType, EntryType>::StoreRange(
|
||||||
AddressType high = base + size - 1;
|
AddressType high = base + size - 1;
|
||||||
|
|
||||||
// Check for undersize or overflow.
|
// Check for undersize or overflow.
|
||||||
if (size <= 0 || high < base)
|
if (size <= 0 || high < base) {
|
||||||
|
BPLOG(INFO) << "StoreRange failed, " << HexString(base) << "+" <<
|
||||||
|
HexString(size) << ", " << HexString(high);
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!map_)
|
if (!map_)
|
||||||
map_ = new AddressToRangeMap();
|
map_ = new AddressToRangeMap();
|
||||||
|
@ -74,8 +80,11 @@ bool ContainedRangeMap<AddressType, EntryType>::StoreRange(
|
||||||
// range's, it violates the containment rules, and an attempt to store
|
// range's, it violates the containment rules, and an attempt to store
|
||||||
// it must fail. iterator_base->first contains the key, which was the
|
// it must fail. iterator_base->first contains the key, which was the
|
||||||
// containing child's high address.
|
// containing child's high address.
|
||||||
if (iterator_base->second->base_ == base && iterator_base->first == high)
|
if (iterator_base->second->base_ == base && iterator_base->first == high) {
|
||||||
|
BPLOG(INFO) << "StoreRange failed, identical range is already "
|
||||||
|
"present: " << HexString(base) << "+" << HexString(size);
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Pass the new range on to the child to attempt to store.
|
// Pass the new range on to the child to attempt to store.
|
||||||
return iterator_base->second->StoreRange(base, size, entry);
|
return iterator_base->second->StoreRange(base, size, entry);
|
||||||
|
@ -92,6 +101,12 @@ bool ContainedRangeMap<AddressType, EntryType>::StoreRange(
|
||||||
// fully. Partial containment isn't allowed.
|
// fully. Partial containment isn't allowed.
|
||||||
if ((iterator_base != iterator_end && base > iterator_base->second->base_) ||
|
if ((iterator_base != iterator_end && base > iterator_base->second->base_) ||
|
||||||
(contains_high && high < iterator_high->first)) {
|
(contains_high && high < iterator_high->first)) {
|
||||||
|
// TODO(mmentovai): Some symbol files will trip this check frequently
|
||||||
|
// on STACK lines. Too many messages will be produced. These are more
|
||||||
|
// suitable for a DEBUG channel than an INFO channel.
|
||||||
|
// BPLOG(INFO) << "StoreRange failed, new range partially contains "
|
||||||
|
// "existing range: " << HexString(base) << "+" <<
|
||||||
|
// HexString(size);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,7 +145,12 @@ bool ContainedRangeMap<AddressType, EntryType>::StoreRange(
|
||||||
template<typename AddressType, typename EntryType>
|
template<typename AddressType, typename EntryType>
|
||||||
bool ContainedRangeMap<AddressType, EntryType>::RetrieveRange(
|
bool ContainedRangeMap<AddressType, EntryType>::RetrieveRange(
|
||||||
const AddressType &address, EntryType *entry) const {
|
const AddressType &address, EntryType *entry) const {
|
||||||
if (!entry || !map_)
|
BPLOG_IF(ERROR, !entry) << "ContainedRangeMap::RetrieveRange requires "
|
||||||
|
"|entry|";
|
||||||
|
assert(entry);
|
||||||
|
|
||||||
|
// If nothing was ever stored, then there's nothing to retrieve.
|
||||||
|
if (!map_)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Get an iterator to the child range whose high address is equal to or
|
// Get an iterator to the child range whose high address is equal to or
|
||||||
|
|
|
@ -92,8 +92,7 @@ class ContainedRangeMap {
|
||||||
// the specified address. This method will only return entries held by
|
// the specified address. This method will only return entries held by
|
||||||
// child ranges, and not the entry contained by |this|. This is necessary
|
// child ranges, and not the entry contained by |this|. This is necessary
|
||||||
// to support a sparsely-populated root range. If no descendant range
|
// to support a sparsely-populated root range. If no descendant range
|
||||||
// encompasses the address, or if there is a parameter error, returns
|
// encompasses the address, returns false.
|
||||||
// false.
|
|
||||||
bool RetrieveRange(const AddressType &address, EntryType *entry) const;
|
bool RetrieveRange(const AddressType &address, EntryType *entry) const;
|
||||||
|
|
||||||
// Removes all children. Note that Clear only removes descendants,
|
// Removes all children. Note that Clear only removes descendants,
|
||||||
|
|
|
@ -2650,9 +2650,9 @@ bool MinidumpMiscInfo::Read(u_int32_t expected_size) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (misc_info_.size_of_info != expected_size) {
|
if (expected_size != misc_info_.size_of_info) {
|
||||||
BPLOG(ERROR) << "MinidumpMiscInfo size mismatch, " <<
|
BPLOG(ERROR) << "MinidumpMiscInfo size mismatch, " <<
|
||||||
misc_info_.size_of_info << " != " << expected_size;
|
expected_size << " != " << misc_info_.size_of_info;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
|
|
||||||
#include "processor/postfix_evaluator.h"
|
#include "processor/postfix_evaluator.h"
|
||||||
#include "google_breakpad/processor/memory_region.h"
|
#include "google_breakpad/processor/memory_region.h"
|
||||||
|
#include "processor/logging.h"
|
||||||
|
|
||||||
namespace google_breakpad {
|
namespace google_breakpad {
|
||||||
|
|
||||||
|
@ -83,8 +84,11 @@ bool PostfixEvaluator<ValueType>::Evaluate(const string &expression,
|
||||||
if (operation != BINARY_OP_NONE) {
|
if (operation != BINARY_OP_NONE) {
|
||||||
// Get the operands.
|
// Get the operands.
|
||||||
ValueType operand1, operand2;
|
ValueType operand1, operand2;
|
||||||
if (!PopValues(&operand1, &operand2))
|
if (!PopValues(&operand1, &operand2)) {
|
||||||
|
BPLOG(ERROR) << "Could not PopValues to get two values for binary "
|
||||||
|
"operation " << token << ": " << expression;
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Perform the operation.
|
// Perform the operation.
|
||||||
ValueType result;
|
ValueType result;
|
||||||
|
@ -107,6 +111,7 @@ bool PostfixEvaluator<ValueType>::Evaluate(const string &expression,
|
||||||
case BINARY_OP_NONE:
|
case BINARY_OP_NONE:
|
||||||
// This will not happen, but compilers will want a default or
|
// This will not happen, but compilers will want a default or
|
||||||
// BINARY_OP_NONE case.
|
// BINARY_OP_NONE case.
|
||||||
|
BPLOG(ERROR) << "Not reached!";
|
||||||
return false;
|
return false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -115,32 +120,51 @@ bool PostfixEvaluator<ValueType>::Evaluate(const string &expression,
|
||||||
PushValue(result);
|
PushValue(result);
|
||||||
} else if (token == "^") {
|
} else if (token == "^") {
|
||||||
// ^ for unary dereference. Can't dereference without memory.
|
// ^ for unary dereference. Can't dereference without memory.
|
||||||
if (!memory_)
|
if (!memory_) {
|
||||||
|
BPLOG(ERROR) << "Attempt to dereference without memory: " <<
|
||||||
|
expression;
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
ValueType address;
|
ValueType address;
|
||||||
if (!PopValue(&address))
|
if (!PopValue(&address)) {
|
||||||
|
BPLOG(ERROR) << "Could not PopValue to get value to derefence: " <<
|
||||||
|
expression;
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
ValueType value;
|
ValueType value;
|
||||||
if (!memory_->GetMemoryAtAddress(address, &value))
|
if (!memory_->GetMemoryAtAddress(address, &value)) {
|
||||||
|
BPLOG(ERROR) << "Could not dereference memory at address " <<
|
||||||
|
HexString(address) << ": " << expression;
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
PushValue(value);
|
PushValue(value);
|
||||||
} else if (token == "=") {
|
} else if (token == "=") {
|
||||||
// = for assignment.
|
// = for assignment.
|
||||||
ValueType value;
|
ValueType value;
|
||||||
if (!PopValue(&value))
|
if (!PopValue(&value)) {
|
||||||
|
BPLOG(ERROR) << "Could not PopValue to get value to assign: " <<
|
||||||
|
expression;
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Assignment is only meaningful when assigning into an identifier.
|
// Assignment is only meaningful when assigning into an identifier.
|
||||||
// The identifier must name a variable, not a constant. Variables
|
// The identifier must name a variable, not a constant. Variables
|
||||||
// begin with '$'.
|
// begin with '$'.
|
||||||
string identifier;
|
string identifier;
|
||||||
if (PopValueOrIdentifier(NULL, &identifier) != POP_RESULT_IDENTIFIER)
|
if (PopValueOrIdentifier(NULL, &identifier) != POP_RESULT_IDENTIFIER) {
|
||||||
|
BPLOG(ERROR) << "PopValueOrIdentifier returned a value, but an "
|
||||||
|
"identifier is needed to assign " <<
|
||||||
|
HexString(value) << ": " << expression;
|
||||||
return false;
|
return false;
|
||||||
if (identifier.empty() || identifier[0] != '$')
|
}
|
||||||
|
if (identifier.empty() || identifier[0] != '$') {
|
||||||
|
BPLOG(ERROR) << "Can't assign " << HexString(value) << " to " <<
|
||||||
|
identifier << ": " << expression;
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
(*dictionary_)[identifier] = value;
|
(*dictionary_)[identifier] = value;
|
||||||
if (assigned)
|
if (assigned)
|
||||||
|
@ -157,6 +181,7 @@ bool PostfixEvaluator<ValueType>::Evaluate(const string &expression,
|
||||||
// If there's anything left on the stack, it indicates incomplete execution.
|
// If there's anything left on the stack, it indicates incomplete execution.
|
||||||
// This is a failure case. If the stack is empty, evalution was complete
|
// This is a failure case. If the stack is empty, evalution was complete
|
||||||
// and successful.
|
// and successful.
|
||||||
|
BPLOG_IF(ERROR, !stack_.empty()) << "Incomplete execution: " << expression;
|
||||||
return stack_.empty();
|
return stack_.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -210,6 +235,7 @@ bool PostfixEvaluator<ValueType>::PopValue(ValueType *value) {
|
||||||
if (iterator == dictionary_->end()) {
|
if (iterator == dictionary_->end()) {
|
||||||
// The identifier wasn't found in the dictionary. Don't imply any
|
// The identifier wasn't found in the dictionary. Don't imply any
|
||||||
// default value, just fail.
|
// default value, just fail.
|
||||||
|
BPLOG(ERROR) << "Identifier " << token << " not in dictionary";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,7 @@
|
||||||
|
|
||||||
|
|
||||||
#include "processor/range_map.h"
|
#include "processor/range_map.h"
|
||||||
|
#include "processor/logging.h"
|
||||||
|
|
||||||
|
|
||||||
namespace google_breakpad {
|
namespace google_breakpad {
|
||||||
|
@ -50,8 +51,15 @@ bool RangeMap<AddressType, EntryType>::StoreRange(const AddressType &base,
|
||||||
AddressType high = base + size - 1;
|
AddressType high = base + size - 1;
|
||||||
|
|
||||||
// Check for undersize or overflow.
|
// Check for undersize or overflow.
|
||||||
if (size <= 0 || high < base)
|
if (size <= 0 || high < base) {
|
||||||
|
// The processor will hit this case too frequently with common symbol
|
||||||
|
// files in the size == 0 case, which is more suited to a DEBUG channel.
|
||||||
|
// Filter those out since there's no DEBUG channel at the moment.
|
||||||
|
BPLOG_IF(INFO, size != 0) << "StoreRange failed, " << HexString(base) <<
|
||||||
|
"+" << HexString(size) << ", " <<
|
||||||
|
HexString(high);
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Ensure that this range does not overlap with another one already in the
|
// Ensure that this range does not overlap with another one already in the
|
||||||
// map.
|
// map.
|
||||||
|
@ -62,14 +70,27 @@ bool RangeMap<AddressType, EntryType>::StoreRange(const AddressType &base,
|
||||||
// Some other range begins in the space used by this range. It may be
|
// Some other range begins in the space used by this range. It may be
|
||||||
// contained within the space used by this range, or it may extend lower.
|
// contained within the space used by this range, or it may extend lower.
|
||||||
// Regardless, it is an error.
|
// Regardless, it is an error.
|
||||||
|
AddressType other_base = iterator_base->second.base();
|
||||||
|
AddressType other_size = iterator_base->first - other_base + 1;
|
||||||
|
BPLOG(INFO) << "StoreRange failed, an existing range is contained by or "
|
||||||
|
"extends lower than the new range: new " <<
|
||||||
|
HexString(base) << "+" << HexString(size) << ", existing " <<
|
||||||
|
HexString(other_base) << "+" << HexString(other_size);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (iterator_high != map_.end()) {
|
if (iterator_high != map_.end()) {
|
||||||
if (iterator_high->second.base() <= high) {
|
if (iterator_high->second.base() <= high) {
|
||||||
// The range above this one overlaps with this one. It may fully
|
// The range above this one overlaps with this one. It may fully
|
||||||
// contain this range, or it may begin within this range and extend
|
// contain this range, or it may begin within this range and extend
|
||||||
// higher. Regardless, it's an error.
|
// higher. Regardless, it's an error.
|
||||||
|
AddressType other_base = iterator_high->second.base();
|
||||||
|
AddressType other_size = iterator_high->first - other_base + 1;
|
||||||
|
BPLOG(INFO) << "StoreRange failed, an existing range contains or "
|
||||||
|
"extends higher than the new range: new " <<
|
||||||
|
HexString(base) << "+" << HexString(size) <<
|
||||||
|
", existing " <<
|
||||||
|
HexString(other_base) << "+" << HexString(other_size);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -85,8 +106,8 @@ template<typename AddressType, typename EntryType>
|
||||||
bool RangeMap<AddressType, EntryType>::RetrieveRange(
|
bool RangeMap<AddressType, EntryType>::RetrieveRange(
|
||||||
const AddressType &address, EntryType *entry,
|
const AddressType &address, EntryType *entry,
|
||||||
AddressType *entry_base, AddressType *entry_size) const {
|
AddressType *entry_base, AddressType *entry_size) const {
|
||||||
if (!entry)
|
BPLOG_IF(ERROR, !entry) << "RangeMap::RetrieveRange requires |entry|";
|
||||||
return false;
|
assert(entry);
|
||||||
|
|
||||||
MapConstIterator iterator = map_.lower_bound(address);
|
MapConstIterator iterator = map_.lower_bound(address);
|
||||||
if (iterator == map_.end())
|
if (iterator == map_.end())
|
||||||
|
@ -114,8 +135,8 @@ template<typename AddressType, typename EntryType>
|
||||||
bool RangeMap<AddressType, EntryType>::RetrieveNearestRange(
|
bool RangeMap<AddressType, EntryType>::RetrieveNearestRange(
|
||||||
const AddressType &address, EntryType *entry,
|
const AddressType &address, EntryType *entry,
|
||||||
AddressType *entry_base, AddressType *entry_size) const {
|
AddressType *entry_base, AddressType *entry_size) const {
|
||||||
if (!entry)
|
BPLOG_IF(ERROR, !entry) << "RangeMap::RetrieveNearestRange requires |entry|";
|
||||||
return false;
|
assert(entry);
|
||||||
|
|
||||||
// If address is within a range, RetrieveRange can handle it.
|
// If address is within a range, RetrieveRange can handle it.
|
||||||
if (RetrieveRange(address, entry, entry_base, entry_size))
|
if (RetrieveRange(address, entry, entry_base, entry_size))
|
||||||
|
@ -145,8 +166,13 @@ template<typename AddressType, typename EntryType>
|
||||||
bool RangeMap<AddressType, EntryType>::RetrieveRangeAtIndex(
|
bool RangeMap<AddressType, EntryType>::RetrieveRangeAtIndex(
|
||||||
int index, EntryType *entry,
|
int index, EntryType *entry,
|
||||||
AddressType *entry_base, AddressType *entry_size) const {
|
AddressType *entry_base, AddressType *entry_size) const {
|
||||||
if (!entry || index >= GetCount())
|
BPLOG_IF(ERROR, !entry) << "RangeMap::RetrieveRangeAtIndex requires |entry|";
|
||||||
|
assert(entry);
|
||||||
|
|
||||||
|
if (index >= GetCount()) {
|
||||||
|
BPLOG(ERROR) << "Index out of range: " << index << "/" << GetCount();
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Walk through the map. Although it's ordered, it's not a vector, so it
|
// Walk through the map. Although it's ordered, it's not a vector, so it
|
||||||
// can't be addressed directly by index.
|
// can't be addressed directly by index.
|
||||||
|
|
|
@ -60,9 +60,8 @@ class RangeMap {
|
||||||
const EntryType &entry);
|
const EntryType &entry);
|
||||||
|
|
||||||
// Locates the range encompassing the supplied address. If there is
|
// Locates the range encompassing the supplied address. If there is
|
||||||
// no such range, or if there is a parameter error, returns false.
|
// no such range, returns false. entry_base and entry_size, if non-NULL,
|
||||||
// entry_base and entry_size, if non-NULL, are set to the base and size
|
// are set to the base and size of the entry's range.
|
||||||
// of the entry's range.
|
|
||||||
bool RetrieveRange(const AddressType &address, EntryType *entry,
|
bool RetrieveRange(const AddressType &address, EntryType *entry,
|
||||||
AddressType *entry_base, AddressType *entry_size) const;
|
AddressType *entry_base, AddressType *entry_size) const;
|
||||||
|
|
||||||
|
@ -77,9 +76,9 @@ class RangeMap {
|
||||||
|
|
||||||
// Treating all ranges as a list ordered by the address spaces that they
|
// Treating all ranges as a list ordered by the address spaces that they
|
||||||
// occupy, locates the range at the index specified by index. Returns
|
// occupy, locates the range at the index specified by index. Returns
|
||||||
// false if index is larger than the number of ranges stored, or if another
|
// false if index is larger than the number of ranges stored. entry_base
|
||||||
// parameter error occurs. entry_base and entry_size, if non-NULL, are set
|
// and entry_size, if non-NULL, are set to the base and size of the entry's
|
||||||
// to the base and size of the entry's range.
|
// range.
|
||||||
//
|
//
|
||||||
// RetrieveRangeAtIndex is not optimized for speedy operation.
|
// RetrieveRangeAtIndex is not optimized for speedy operation.
|
||||||
bool RetrieveRangeAtIndex(int index, EntryType *entry,
|
bool RetrieveRangeAtIndex(int index, EntryType *entry,
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
#include "processor/simple_symbol_supplier.h"
|
#include "processor/simple_symbol_supplier.h"
|
||||||
#include "google_breakpad/processor/code_module.h"
|
#include "google_breakpad/processor/code_module.h"
|
||||||
#include "google_breakpad/processor/system_info.h"
|
#include "google_breakpad/processor/system_info.h"
|
||||||
|
#include "processor/logging.h"
|
||||||
#include "processor/pathname_stripper.h"
|
#include "processor/pathname_stripper.h"
|
||||||
|
|
||||||
namespace google_breakpad {
|
namespace google_breakpad {
|
||||||
|
@ -53,7 +54,11 @@ static bool file_exists(const string &file_name) {
|
||||||
SymbolSupplier::SymbolResult SimpleSymbolSupplier::GetSymbolFile(
|
SymbolSupplier::SymbolResult SimpleSymbolSupplier::GetSymbolFile(
|
||||||
const CodeModule *module, const SystemInfo *system_info,
|
const CodeModule *module, const SystemInfo *system_info,
|
||||||
string *symbol_file) {
|
string *symbol_file) {
|
||||||
|
BPLOG_IF(ERROR, !symbol_file) << "SimpleSymbolSupplier::GetSymbolFile "
|
||||||
|
"requires |symbol_file|";
|
||||||
assert(symbol_file);
|
assert(symbol_file);
|
||||||
|
symbol_file->clear();
|
||||||
|
|
||||||
for (unsigned int path_index = 0; path_index < paths_.size(); ++path_index) {
|
for (unsigned int path_index = 0; path_index < paths_.size(); ++path_index) {
|
||||||
SymbolResult result;
|
SymbolResult result;
|
||||||
if ((result = GetSymbolFileAtPath(module, system_info, paths_[path_index],
|
if ((result = GetSymbolFileAtPath(module, system_info, paths_[path_index],
|
||||||
|
@ -67,7 +72,11 @@ SymbolSupplier::SymbolResult SimpleSymbolSupplier::GetSymbolFile(
|
||||||
SymbolSupplier::SymbolResult SimpleSymbolSupplier::GetSymbolFileAtPath(
|
SymbolSupplier::SymbolResult SimpleSymbolSupplier::GetSymbolFileAtPath(
|
||||||
const CodeModule *module, const SystemInfo *system_info,
|
const CodeModule *module, const SystemInfo *system_info,
|
||||||
const string &root_path, string *symbol_file) {
|
const string &root_path, string *symbol_file) {
|
||||||
|
BPLOG_IF(ERROR, !symbol_file) << "SimpleSymbolSupplier::GetSymbolFileAtPath "
|
||||||
|
"requires |symbol_file|";
|
||||||
assert(symbol_file);
|
assert(symbol_file);
|
||||||
|
symbol_file->clear();
|
||||||
|
|
||||||
if (!module)
|
if (!module)
|
||||||
return NOT_FOUND;
|
return NOT_FOUND;
|
||||||
|
|
||||||
|
@ -77,15 +86,24 @@ SymbolSupplier::SymbolResult SimpleSymbolSupplier::GetSymbolFileAtPath(
|
||||||
// Append the debug (pdb) file name as a directory name.
|
// Append the debug (pdb) file name as a directory name.
|
||||||
path.append("/");
|
path.append("/");
|
||||||
string debug_file_name = PathnameStripper::File(module->debug_file());
|
string debug_file_name = PathnameStripper::File(module->debug_file());
|
||||||
if (debug_file_name.empty())
|
if (debug_file_name.empty()) {
|
||||||
|
BPLOG(ERROR) << "Can't construct symbol file path without debug_file "
|
||||||
|
"(code_file = " <<
|
||||||
|
PathnameStripper::File(module->code_file()) << ")";
|
||||||
return NOT_FOUND;
|
return NOT_FOUND;
|
||||||
|
}
|
||||||
path.append(debug_file_name);
|
path.append(debug_file_name);
|
||||||
|
|
||||||
// Append the identifier as a directory name.
|
// Append the identifier as a directory name.
|
||||||
path.append("/");
|
path.append("/");
|
||||||
string identifier = module->debug_identifier();
|
string identifier = module->debug_identifier();
|
||||||
if (identifier.empty())
|
if (identifier.empty()) {
|
||||||
|
BPLOG(ERROR) << "Can't construct symbol file path without debug_identifier "
|
||||||
|
"(code_file = " <<
|
||||||
|
PathnameStripper::File(module->code_file()) <<
|
||||||
|
", debug_file = " << debug_file_name << ")";
|
||||||
return NOT_FOUND;
|
return NOT_FOUND;
|
||||||
|
}
|
||||||
path.append(identifier);
|
path.append(identifier);
|
||||||
|
|
||||||
// Transform the debug file name into one ending in .sym. If the existing
|
// Transform the debug file name into one ending in .sym. If the existing
|
||||||
|
@ -103,8 +121,10 @@ SymbolSupplier::SymbolResult SimpleSymbolSupplier::GetSymbolFileAtPath(
|
||||||
}
|
}
|
||||||
path.append(".sym");
|
path.append(".sym");
|
||||||
|
|
||||||
if (!file_exists(path))
|
if (!file_exists(path)) {
|
||||||
|
BPLOG(INFO) << "No symbol file at " << path;
|
||||||
return NOT_FOUND;
|
return NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
*symbol_file = path;
|
*symbol_file = path;
|
||||||
return FOUND;
|
return FOUND;
|
||||||
|
|
|
@ -45,6 +45,7 @@
|
||||||
#include "google_breakpad/processor/stack_frame.h"
|
#include "google_breakpad/processor/stack_frame.h"
|
||||||
#include "google_breakpad/processor/symbol_supplier.h"
|
#include "google_breakpad/processor/symbol_supplier.h"
|
||||||
#include "processor/linked_ptr.h"
|
#include "processor/linked_ptr.h"
|
||||||
|
#include "processor/logging.h"
|
||||||
#include "processor/scoped_ptr.h"
|
#include "processor/scoped_ptr.h"
|
||||||
#include "processor/stack_frame_info.h"
|
#include "processor/stack_frame_info.h"
|
||||||
#include "processor/stackwalker_ppc.h"
|
#include "processor/stackwalker_ppc.h"
|
||||||
|
@ -67,6 +68,7 @@ Stackwalker::Stackwalker(const SystemInfo *system_info,
|
||||||
|
|
||||||
|
|
||||||
bool Stackwalker::Walk(CallStack *stack) {
|
bool Stackwalker::Walk(CallStack *stack) {
|
||||||
|
BPLOG_IF(ERROR, !stack) << "Stackwalker::Walk requires |stack|";
|
||||||
assert(stack);
|
assert(stack);
|
||||||
stack->Clear();
|
stack->Clear();
|
||||||
|
|
||||||
|
@ -139,8 +141,10 @@ Stackwalker* Stackwalker::StackwalkerForCPU(
|
||||||
const CodeModules *modules,
|
const CodeModules *modules,
|
||||||
SymbolSupplier *supplier,
|
SymbolSupplier *supplier,
|
||||||
SourceLineResolverInterface *resolver) {
|
SourceLineResolverInterface *resolver) {
|
||||||
if (!context)
|
if (!context) {
|
||||||
|
BPLOG(ERROR) << "Can't choose a stackwalker implementation without context";
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
Stackwalker *cpu_stackwalker = NULL;
|
Stackwalker *cpu_stackwalker = NULL;
|
||||||
|
|
||||||
|
@ -161,6 +165,9 @@ Stackwalker* Stackwalker::StackwalkerForCPU(
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BPLOG_IF(ERROR, !cpu_stackwalker) << "Unknown CPU type " << HexString(cpu) <<
|
||||||
|
", can't choose a stackwalker "
|
||||||
|
"implementation";
|
||||||
return cpu_stackwalker;
|
return cpu_stackwalker;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,7 @@
|
||||||
#include "google_breakpad/processor/call_stack.h"
|
#include "google_breakpad/processor/call_stack.h"
|
||||||
#include "google_breakpad/processor/memory_region.h"
|
#include "google_breakpad/processor/memory_region.h"
|
||||||
#include "google_breakpad/processor/stack_frame_cpu.h"
|
#include "google_breakpad/processor/stack_frame_cpu.h"
|
||||||
|
#include "processor/logging.h"
|
||||||
|
|
||||||
namespace google_breakpad {
|
namespace google_breakpad {
|
||||||
|
|
||||||
|
@ -54,14 +55,19 @@ StackwalkerPPC::StackwalkerPPC(const SystemInfo *system_info,
|
||||||
// This implementation only covers 32-bit ppc CPUs. The limits of the
|
// This implementation only covers 32-bit ppc CPUs. The limits of the
|
||||||
// supplied stack are invalid. Mark memory_ = NULL, which will cause
|
// supplied stack are invalid. Mark memory_ = NULL, which will cause
|
||||||
// stackwalking to fail.
|
// stackwalking to fail.
|
||||||
|
BPLOG(ERROR) << "Memory out of range for stackwalking: " <<
|
||||||
|
HexString(memory_->GetBase()) << "+" <<
|
||||||
|
HexString(memory_->GetSize());
|
||||||
memory_ = NULL;
|
memory_ = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
StackFrame* StackwalkerPPC::GetContextFrame() {
|
StackFrame* StackwalkerPPC::GetContextFrame() {
|
||||||
if (!context_ || !memory_)
|
if (!context_ || !memory_) {
|
||||||
|
BPLOG(ERROR) << "Can't get context frame without context or memory";
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
StackFramePPC *frame = new StackFramePPC();
|
StackFramePPC *frame = new StackFramePPC();
|
||||||
|
|
||||||
|
@ -78,8 +84,10 @@ StackFrame* StackwalkerPPC::GetContextFrame() {
|
||||||
StackFrame* StackwalkerPPC::GetCallerFrame(
|
StackFrame* StackwalkerPPC::GetCallerFrame(
|
||||||
const CallStack *stack,
|
const CallStack *stack,
|
||||||
const vector< linked_ptr<StackFrameInfo> > &stack_frame_info) {
|
const vector< linked_ptr<StackFrameInfo> > &stack_frame_info) {
|
||||||
if (!memory_ || !stack)
|
if (!memory_ || !stack) {
|
||||||
|
BPLOG(ERROR) << "Can't get caller frame without memory or stack";
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
// The instruction pointers for previous frames are saved on the stack.
|
// The instruction pointers for previous frames are saved on the stack.
|
||||||
// The typical ppc calling convention is for the called procedure to store
|
// The typical ppc calling convention is for the called procedure to store
|
||||||
|
|
|
@ -42,6 +42,7 @@
|
||||||
#include "google_breakpad/processor/memory_region.h"
|
#include "google_breakpad/processor/memory_region.h"
|
||||||
#include "google_breakpad/processor/stack_frame_cpu.h"
|
#include "google_breakpad/processor/stack_frame_cpu.h"
|
||||||
#include "processor/linked_ptr.h"
|
#include "processor/linked_ptr.h"
|
||||||
|
#include "processor/logging.h"
|
||||||
#include "processor/stack_frame_info.h"
|
#include "processor/stack_frame_info.h"
|
||||||
|
|
||||||
namespace google_breakpad {
|
namespace google_breakpad {
|
||||||
|
@ -58,14 +59,19 @@ StackwalkerX86::StackwalkerX86(const SystemInfo *system_info,
|
||||||
if (memory_->GetBase() + memory_->GetSize() - 1 > 0xffffffff) {
|
if (memory_->GetBase() + memory_->GetSize() - 1 > 0xffffffff) {
|
||||||
// The x86 is a 32-bit CPU, the limits of the supplied stack are invalid.
|
// The x86 is a 32-bit CPU, the limits of the supplied stack are invalid.
|
||||||
// Mark memory_ = NULL, which will cause stackwalking to fail.
|
// Mark memory_ = NULL, which will cause stackwalking to fail.
|
||||||
|
BPLOG(ERROR) << "Memory out of range for stackwalking: " <<
|
||||||
|
HexString(memory_->GetBase()) << "+" <<
|
||||||
|
HexString(memory_->GetSize());
|
||||||
memory_ = NULL;
|
memory_ = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
StackFrame* StackwalkerX86::GetContextFrame() {
|
StackFrame* StackwalkerX86::GetContextFrame() {
|
||||||
if (!context_ || !memory_)
|
if (!context_ || !memory_) {
|
||||||
|
BPLOG(ERROR) << "Can't get context frame without context or memory";
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
StackFrameX86 *frame = new StackFrameX86();
|
StackFrameX86 *frame = new StackFrameX86();
|
||||||
|
|
||||||
|
@ -82,8 +88,10 @@ StackFrame* StackwalkerX86::GetContextFrame() {
|
||||||
StackFrame* StackwalkerX86::GetCallerFrame(
|
StackFrame* StackwalkerX86::GetCallerFrame(
|
||||||
const CallStack *stack,
|
const CallStack *stack,
|
||||||
const vector< linked_ptr<StackFrameInfo> > &stack_frame_info) {
|
const vector< linked_ptr<StackFrameInfo> > &stack_frame_info) {
|
||||||
if (!memory_ || !stack)
|
if (!memory_ || !stack) {
|
||||||
|
BPLOG(ERROR) << "Can't get caller frame without memory or stack";
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
StackFrameX86 *last_frame = static_cast<StackFrameX86*>(
|
StackFrameX86 *last_frame = static_cast<StackFrameX86*>(
|
||||||
stack->frames()->back());
|
stack->frames()->back());
|
||||||
|
|
Loading…
Reference in a new issue