aboutsummaryrefslogtreecommitdiff
path: root/src/processor
diff options
context:
space:
mode:
authorivan.penkov@gmail.com <ivan.penkov@gmail.com@4c0a9323-5329-0410-9bdc-e9ce6186880e>2013-07-11 01:36:06 +0000
committerivan.penkov@gmail.com <ivan.penkov@gmail.com@4c0a9323-5329-0410-9bdc-e9ce6186880e>2013-07-11 01:36:06 +0000
commit8819ab0844819aa64a670efda85f5cddf40cf186 (patch)
tree162888f824e405aa66cb7eb0b999dfb8f717fb8b /src/processor
parentLinux: Fix builds on systems without PR_SET_PTRACER in linux/prctl.h. (diff)
downloadbreakpad-8819ab0844819aa64a670efda85f5cddf40cf186.tar.xz
Detect corrupt symbol files during minidump processing. Recover from the errors and use the good data if possible.
More specifically: - Detect corrupt symbols during minidump processing and provide the list of modules with corrupt symbols in the ProcessState. This will allow listing the corrupt symbol files in the final crash report. - Skip and recover from symbol data parse errors - don't give up until 100 parse errors are seen. - In order to recover from '\0' (null terminator) in the middle of a symbol file, a couple of methods have to be updated to require both buffer pointer and length. Previously they required only a buffer pointer (char *) and the size of the buffer was evaluated using strlen which is not reliable when the data is corrupt. Most of the changes are due to these signature updates. - Added and updated unittests. Also, updated minidump_stackwalk to show a WARNING for corrupt symbols. Output looks like this: ... Loaded modules: 0x000da000 - 0x000dafff Google Chrome Canary ??? (main) 0x000e0000 - 0x0417dfff Google Chrome Framework 0.1500.0.3 (WARNING: Corrupt symbols, Google Chrome Framework, 4682A6B4136436C4BFECEB62D498020E0) 0x044a8000 - 0x04571fff IOBluetooth 0.1.0.0 ... Review URL: https://breakpad.appspot.com/613002 git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1200 4c0a9323-5329-0410-9bdc-e9ce6186880e
Diffstat (limited to 'src/processor')
-rw-r--r--src/processor/basic_source_line_resolver.cc100
-rw-r--r--src/processor/basic_source_line_resolver_types.h20
-rw-r--r--src/processor/basic_source_line_resolver_unittest.cc10
-rw-r--r--src/processor/exploitability_unittest.cc6
-rw-r--r--src/processor/fast_source_line_resolver.cc11
-rw-r--r--src/processor/fast_source_line_resolver_types.h10
-rw-r--r--src/processor/fast_source_line_resolver_unittest.cc39
-rw-r--r--src/processor/minidump_processor.cc3
-rw-r--r--src/processor/minidump_processor_unittest.cc23
-rw-r--r--src/processor/minidump_stackwalk.cc20
-rw-r--r--src/processor/module_comparer.cc10
-rw-r--r--src/processor/module_serializer.cc19
-rw-r--r--src/processor/process_state.cc5
-rw-r--r--src/processor/simple_serializer-inl.h5
-rw-r--r--src/processor/simple_symbol_supplier.cc19
-rw-r--r--src/processor/simple_symbol_supplier.h3
-rw-r--r--src/processor/source_line_resolver_base.cc52
-rw-r--r--src/processor/source_line_resolver_base_types.h10
-rw-r--r--src/processor/stack_frame_symbolizer.cc15
-rw-r--r--src/processor/stackwalker.cc79
-rw-r--r--src/processor/stackwalker_amd64_unittest.cc43
-rw-r--r--src/processor/stackwalker_arm_unittest.cc63
-rw-r--r--src/processor/stackwalker_unittest_utils.h15
-rw-r--r--src/processor/stackwalker_x86_unittest.cc144
24 files changed, 524 insertions, 200 deletions
diff --git a/src/processor/basic_source_line_resolver.cc b/src/processor/basic_source_line_resolver.cc
index 55f8f9a1..6fb47b3b 100644
--- a/src/processor/basic_source_line_resolver.cc
+++ b/src/processor/basic_source_line_resolver.cc
@@ -60,25 +60,65 @@ namespace google_breakpad {
#endif
static const char *kWhitespace = " \r\n";
+static const int kMaxErrorsPrinted = 5;
+static const int kMaxErrorsBeforeBailing = 100;
BasicSourceLineResolver::BasicSourceLineResolver() :
SourceLineResolverBase(new BasicModuleFactory) { }
-bool BasicSourceLineResolver::Module::LoadMapFromMemory(char *memory_buffer) {
+// static
+void BasicSourceLineResolver::Module::LogParseError(
+ const string &message,
+ int line_number,
+ int *num_errors) {
+ if (++(*num_errors) <= kMaxErrorsPrinted) {
+ if (line_number > 0) {
+ BPLOG(ERROR) << "Line " << line_number << ": " << message;
+ } else {
+ BPLOG(ERROR) << message;
+ }
+ }
+}
+
+bool BasicSourceLineResolver::Module::LoadMapFromMemory(
+ char *memory_buffer,
+ size_t memory_buffer_size) {
linked_ptr<Function> cur_func;
int line_number = 0;
+ int num_errors = 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) {
+ if (memory_buffer_size == 0) {
return true;
}
- if (memory_buffer[map_buffer_length - 1] == '\n') {
- memory_buffer[map_buffer_length - 1] = '\0';
+ // Make sure the last character is null terminator.
+ size_t last_null_terminator = memory_buffer_size - 1;
+ if (memory_buffer[last_null_terminator] != '\0') {
+ memory_buffer[last_null_terminator] = '\0';
+ }
+
+ // Skip any null terminators at the end of the memory buffer, and make sure
+ // there are no other null terminators in the middle of the memory buffer.
+ bool has_null_terminator_in_the_middle = false;
+ while (last_null_terminator > 0 &&
+ memory_buffer[last_null_terminator - 1] == '\0') {
+ last_null_terminator--;
+ }
+ for (size_t i = 0; i < last_null_terminator; i++) {
+ if (memory_buffer[i] == '\0') {
+ memory_buffer[i] = '_';
+ has_null_terminator_in_the_middle = true;
+ }
+ }
+ if (has_null_terminator_in_the_middle) {
+ LogParseError(
+ "Null terminator is not expected in the middle of the symbol data",
+ line_number,
+ &num_errors);
}
char *buffer;
@@ -89,35 +129,28 @@ bool BasicSourceLineResolver::Module::LoadMapFromMemory(char *memory_buffer) {
if (strncmp(buffer, "FILE ", 5) == 0) {
if (!ParseFile(buffer)) {
- BPLOG(ERROR) << "ParseFile on buffer failed at " <<
- ":" << line_number;
- return false;
+ LogParseError("ParseFile on buffer failed", line_number, &num_errors);
}
} else if (strncmp(buffer, "STACK ", 6) == 0) {
if (!ParseStackInfo(buffer)) {
- BPLOG(ERROR) << "ParseStackInfo failed at " <<
- ":" << line_number;
- return false;
+ LogParseError("ParseStackInfo failed", line_number, &num_errors);
}
} 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;
+ LogParseError("ParseFunction failed", line_number, &num_errors);
+ } else {
+ // 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);
}
- // 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;
+ LogParseError("ParsePublicSymbol failed", line_number, &num_errors);
}
} else if (strncmp(buffer, "MODULE ", 7) == 0) {
// Ignore these. They're not of any use to BasicSourceLineResolver,
@@ -132,21 +165,24 @@ bool BasicSourceLineResolver::Module::LoadMapFromMemory(char *memory_buffer) {
// 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;
+ LogParseError("Found source line data without a function",
+ line_number, &num_errors);
+ } else {
+ Line *line = ParseLine(buffer);
+ if (!line) {
+ LogParseError("ParseLine failed", line_number, &num_errors);
+ } else {
+ cur_func->lines.StoreRange(line->address, line->size,
+ linked_ptr<Line>(line));
+ }
}
- cur_func->lines.StoreRange(line->address, line->size,
- linked_ptr<Line>(line));
+ }
+ if (num_errors > kMaxErrorsBeforeBailing) {
+ break;
}
buffer = strtok_r(NULL, "\r\n", &save_ptr);
}
+ is_corrupt_ = num_errors > 0;
return true;
}
diff --git a/src/processor/basic_source_line_resolver_types.h b/src/processor/basic_source_line_resolver_types.h
index 94616dcb..a022bc0d 100644
--- a/src/processor/basic_source_line_resolver_types.h
+++ b/src/processor/basic_source_line_resolver_types.h
@@ -73,12 +73,20 @@ BasicSourceLineResolver::Function : public SourceLineResolverBase::Function {
class BasicSourceLineResolver::Module : public SourceLineResolverBase::Module {
public:
- explicit Module(const string &name) : name_(name) { }
+ explicit Module(const string &name) : name_(name), is_corrupt_(false) { }
virtual ~Module() { }
// Loads a map from the given buffer in char* type.
// Does NOT have ownership of memory_buffer.
- virtual bool LoadMapFromMemory(char *memory_buffer);
+ // The passed in |memory buffer| is of size |memory_buffer_size|. If it is
+ // not null terminated, LoadMapFromMemory() will null terminate it by
+ // modifying the passed in buffer.
+ virtual bool LoadMapFromMemory(char *memory_buffer,
+ size_t memory_buffer_size);
+
+ // Tells whether the loaded symbol data is corrupt. Return value is
+ // undefined, if the symbol data hasn't been loaded yet.
+ virtual bool IsCorrupt() const { return is_corrupt_; }
// Looks up the given relative address, and fills the StackFrame struct
// with the result.
@@ -105,6 +113,13 @@ class BasicSourceLineResolver::Module : public SourceLineResolverBase::Module {
typedef std::map<int, string> FileMap;
+ // Logs parse errors. |*num_errors| is increased every time LogParseError is
+ // called.
+ static void LogParseError(
+ const string &message,
+ int line_number,
+ int *num_errors);
+
// Parses a file declaration
bool ParseFile(char *file_line);
@@ -129,6 +144,7 @@ class BasicSourceLineResolver::Module : public SourceLineResolverBase::Module {
FileMap files_;
RangeMap< MemAddr, linked_ptr<Function> > functions_;
AddressMap< MemAddr, linked_ptr<PublicSymbol> > public_symbols_;
+ bool is_corrupt_;
// Each element in the array is a ContainedRangeMap for a type
// listed in WindowsFrameInfoTypes. These are split by type because
diff --git a/src/processor/basic_source_line_resolver_unittest.cc b/src/processor/basic_source_line_resolver_unittest.cc
index 8525e9e4..1a760bbf 100644
--- a/src/processor/basic_source_line_resolver_unittest.cc
+++ b/src/processor/basic_source_line_resolver_unittest.cc
@@ -376,13 +376,15 @@ TEST_F(TestBasicSourceLineResolver, TestLoadAndResolve)
TEST_F(TestBasicSourceLineResolver, TestInvalidLoads)
{
TestCodeModule module3("module3");
- ASSERT_FALSE(resolver.LoadModule(&module3,
+ ASSERT_TRUE(resolver.LoadModule(&module3,
testdata_dir + "/module3_bad.out"));
- ASSERT_FALSE(resolver.HasModule(&module3));
+ ASSERT_TRUE(resolver.HasModule(&module3));
+ ASSERT_TRUE(resolver.IsModuleCorrupt(&module3));
TestCodeModule module4("module4");
- ASSERT_FALSE(resolver.LoadModule(&module4,
+ ASSERT_TRUE(resolver.LoadModule(&module4,
testdata_dir + "/module4_bad.out"));
- ASSERT_FALSE(resolver.HasModule(&module4));
+ ASSERT_TRUE(resolver.HasModule(&module4));
+ ASSERT_TRUE(resolver.IsModuleCorrupt(&module4));
TestCodeModule module5("module5");
ASSERT_FALSE(resolver.LoadModule(&module5,
testdata_dir + "/invalid-filename"));
diff --git a/src/processor/exploitability_unittest.cc b/src/processor/exploitability_unittest.cc
index 1aeaa54a..ceb4ee85 100644
--- a/src/processor/exploitability_unittest.cc
+++ b/src/processor/exploitability_unittest.cc
@@ -86,7 +86,8 @@ class TestSymbolSupplier : public SymbolSupplier {
virtual SymbolResult GetCStringSymbolData(const CodeModule *module,
const SystemInfo *system_info,
string *symbol_file,
- char **symbol_data);
+ char **symbol_data,
+ size_t *symbol_data_size);
virtual void FreeSymbolData(const CodeModule *module) { }
// When set to true, causes the SymbolSupplier to return INTERRUPT
@@ -112,7 +113,8 @@ SymbolSupplier::SymbolResult TestSymbolSupplier::GetCStringSymbolData(
const CodeModule *module,
const SystemInfo *system_info,
string *symbol_file,
- char **symbol_data) {
+ char **symbol_data,
+ size_t *symbol_data_size) {
return GetSymbolFile(module, system_info, symbol_file);
}
diff --git a/src/processor/fast_source_line_resolver.cc b/src/processor/fast_source_line_resolver.cc
index 86073d2d..4a3d0007 100644
--- a/src/processor/fast_source_line_resolver.cc
+++ b/src/processor/fast_source_line_resolver.cc
@@ -47,6 +47,7 @@
#include "common/scoped_ptr.h"
#include "common/using_std_string.h"
#include "processor/module_factory.h"
+#include "processor/simple_serializer-inl.h"
using std::map;
using std::make_pair;
@@ -143,8 +144,14 @@ WindowsFrameInfo FastSourceLineResolver::CopyWFI(const char *raw) {
// Loads a map from the given buffer in char* type.
// Does NOT take ownership of mem_buffer.
// In addition, treat mem_buffer as const char*.
-bool FastSourceLineResolver::Module::LoadMapFromMemory(char *mem_buffer) {
- if (!mem_buffer) return false;
+bool FastSourceLineResolver::Module::LoadMapFromMemory(
+ char *memory_buffer,
+ size_t memory_buffer_size) {
+ if (!memory_buffer) return false;
+
+ // Read the "is_corrupt" flag.
+ const char *mem_buffer = memory_buffer;
+ mem_buffer = SimpleSerializer<bool>::Read(mem_buffer, &is_corrupt_);
const uint32_t *map_sizes = reinterpret_cast<const uint32_t*>(mem_buffer);
diff --git a/src/processor/fast_source_line_resolver_types.h b/src/processor/fast_source_line_resolver_types.h
index c4cec60f..2c010470 100644
--- a/src/processor/fast_source_line_resolver_types.h
+++ b/src/processor/fast_source_line_resolver_types.h
@@ -112,7 +112,7 @@ public SourceLineResolverBase::PublicSymbol {
class FastSourceLineResolver::Module: public SourceLineResolverBase::Module {
public:
- explicit Module(const string &name) : name_(name) { }
+ explicit Module(const string &name) : name_(name), is_corrupt_(false) { }
virtual ~Module() { }
// Looks up the given relative address, and fills the StackFrame struct
@@ -120,7 +120,12 @@ class FastSourceLineResolver::Module: public SourceLineResolverBase::Module {
virtual void LookupAddress(StackFrame *frame) const;
// Loads a map from the given buffer in char* type.
- virtual bool LoadMapFromMemory(char *memory_buffer);
+ virtual bool LoadMapFromMemory(char *memory_buffer,
+ size_t memory_buffer_size);
+
+ // Tells whether the loaded symbol data is corrupt. Return value is
+ // undefined, if the symbol data hasn't been loaded yet.
+ virtual bool IsCorrupt() const { return is_corrupt_; }
// If Windows stack walking information is available covering ADDRESS,
// return a WindowsFrameInfo structure describing it. If the information
@@ -147,6 +152,7 @@ class FastSourceLineResolver::Module: public SourceLineResolverBase::Module {
StaticMap<int, char> files_;
StaticRangeMap<MemAddr, Function> functions_;
StaticAddressMap<MemAddr, PublicSymbol> public_symbols_;
+ bool is_corrupt_;
// Each element in the array is a ContainedRangeMap for a type
// listed in WindowsFrameInfoTypes. These are split by type because
diff --git a/src/processor/fast_source_line_resolver_unittest.cc b/src/processor/fast_source_line_resolver_unittest.cc
index 26982bfc..7998fef1 100644
--- a/src/processor/fast_source_line_resolver_unittest.cc
+++ b/src/processor/fast_source_line_resolver_unittest.cc
@@ -403,28 +403,32 @@ TEST_F(TestFastSourceLineResolver, TestLoadAndResolve) {
TEST_F(TestFastSourceLineResolver, TestInvalidLoads) {
TestCodeModule module3("module3");
- ASSERT_FALSE(basic_resolver.LoadModule(&module3,
- testdata_dir + "/module3_bad.out"));
- ASSERT_FALSE(basic_resolver.HasModule(&module3));
+ ASSERT_TRUE(basic_resolver.LoadModule(&module3,
+ testdata_dir + "/module3_bad.out"));
+ ASSERT_TRUE(basic_resolver.HasModule(&module3));
+ ASSERT_TRUE(basic_resolver.IsModuleCorrupt(&module3));
// Convert module3 to fast_module:
- ASSERT_FALSE(serializer.ConvertOneModule(module3.code_file(),
- &basic_resolver,
- &fast_resolver));
- ASSERT_FALSE(fast_resolver.HasModule(&module3));
+ ASSERT_TRUE(serializer.ConvertOneModule(module3.code_file(),
+ &basic_resolver,
+ &fast_resolver));
+ ASSERT_TRUE(fast_resolver.HasModule(&module3));
+ ASSERT_TRUE(fast_resolver.IsModuleCorrupt(&module3));
TestCodeModule module4("module4");
- ASSERT_FALSE(basic_resolver.LoadModule(&module4,
- testdata_dir + "/module4_bad.out"));
- ASSERT_FALSE(basic_resolver.HasModule(&module4));
+ ASSERT_TRUE(basic_resolver.LoadModule(&module4,
+ testdata_dir + "/module4_bad.out"));
+ ASSERT_TRUE(basic_resolver.HasModule(&module4));
+ ASSERT_TRUE(basic_resolver.IsModuleCorrupt(&module4));
// Convert module4 to fast_module:
- ASSERT_FALSE(serializer.ConvertOneModule(module4.code_file(),
- &basic_resolver,
- &fast_resolver));
- ASSERT_FALSE(fast_resolver.HasModule(&module4));
+ ASSERT_TRUE(serializer.ConvertOneModule(module4.code_file(),
+ &basic_resolver,
+ &fast_resolver));
+ ASSERT_TRUE(fast_resolver.HasModule(&module4));
+ ASSERT_TRUE(fast_resolver.IsModuleCorrupt(&module4));
TestCodeModule module5("module5");
ASSERT_FALSE(fast_resolver.LoadModule(&module5,
- testdata_dir + "/invalid-filename"));
+ testdata_dir + "/invalid-filename"));
ASSERT_FALSE(fast_resolver.HasModule(&module5));
TestCodeModule invalidmodule("invalid-module");
@@ -457,6 +461,7 @@ TEST_F(TestFastSourceLineResolver, TestUnload) {
TEST_F(TestFastSourceLineResolver, CompareModule) {
char *symbol_data;
+ size_t symbol_data_size;
string symbol_data_string;
string filename;
@@ -465,8 +470,8 @@ TEST_F(TestFastSourceLineResolver, CompareModule) {
ss << testdata_dir << "/module" << module_index << ".out";
filename = ss.str();
ASSERT_TRUE(SourceLineResolverBase::ReadSymbolFile(
- &symbol_data, symbol_file(module_index)));
- symbol_data_string = symbol_data;
+ symbol_file(module_index), &symbol_data, &symbol_data_size));
+ symbol_data_string.assign(symbol_data, symbol_data_size);
delete [] symbol_data;
ASSERT_TRUE(module_comparer.Compare(symbol_data_string));
}
diff --git a/src/processor/minidump_processor.cc b/src/processor/minidump_processor.cc
index a8742cd2..51ee1164 100644
--- a/src/processor/minidump_processor.cc
+++ b/src/processor/minidump_processor.cc
@@ -247,7 +247,8 @@ ProcessResult MinidumpProcessor::Process(
scoped_ptr<CallStack> stack(new CallStack());
if (stackwalker.get()) {
if (!stackwalker->Walk(stack.get(),
- &process_state->modules_without_symbols_)) {
+ &process_state->modules_without_symbols_,
+ &process_state->modules_with_corrupt_symbols_)) {
BPLOG(INFO) << "Stackwalker interrupt (missing symbols?) at "
<< thread_string;
interrupted = true;
diff --git a/src/processor/minidump_processor_unittest.cc b/src/processor/minidump_processor_unittest.cc
index d0d8b780..9395cc2d 100644
--- a/src/processor/minidump_processor_unittest.cc
+++ b/src/processor/minidump_processor_unittest.cc
@@ -188,7 +188,8 @@ class TestSymbolSupplier : public SymbolSupplier {
virtual SymbolResult GetCStringSymbolData(const CodeModule *module,
const SystemInfo *system_info,
string *symbol_file,
- char **symbol_data);
+ char **symbol_data,
+ size_t *symbol_data_size);
virtual void FreeSymbolData(const CodeModule *module);
@@ -248,21 +249,23 @@ SymbolSupplier::SymbolResult TestSymbolSupplier::GetCStringSymbolData(
const CodeModule *module,
const SystemInfo *system_info,
string *symbol_file,
- char **symbol_data) {
+ char **symbol_data,
+ size_t *symbol_data_size) {
string symbol_data_string;
SymbolSupplier::SymbolResult s = GetSymbolFile(module,
system_info,
symbol_file,
&symbol_data_string);
if (s == FOUND) {
- unsigned int size = symbol_data_string.size() + 1;
- *symbol_data = new char[size];
+ *symbol_data_size = symbol_data_string.size() + 1;
+ *symbol_data = new char[*symbol_data_size];
if (*symbol_data == NULL) {
BPLOG(ERROR) << "Memory allocation failed for module: "
- << module->code_file() << " size: " << size;
+ << module->code_file() << " size: " << *symbol_data_size;
return INTERRUPT;
}
- strcpy(*symbol_data, symbol_data_string.c_str());
+ memcpy(*symbol_data, symbol_data_string.c_str(), symbol_data_string.size());
+ (*symbol_data)[symbol_data_string.size()] = '\0';
memory_buffers_.insert(make_pair(module->code_file(), *symbol_data));
}
@@ -348,11 +351,11 @@ TEST_F(MinidumpProcessorTest, TestSymbolSupplierLookupCounts) {
EXPECT_CALL(supplier, GetCStringSymbolData(
Property(&google_breakpad::CodeModule::code_file,
"c:\\test_app.exe"),
- _, _, _)).WillOnce(Return(SymbolSupplier::NOT_FOUND));
+ _, _, _, _)).WillOnce(Return(SymbolSupplier::NOT_FOUND));
EXPECT_CALL(supplier, GetCStringSymbolData(
Property(&google_breakpad::CodeModule::code_file,
Ne("c:\\test_app.exe")),
- _, _, _)).WillRepeatedly(Return(SymbolSupplier::NOT_FOUND));
+ _, _, _, _)).WillRepeatedly(Return(SymbolSupplier::NOT_FOUND));
// Avoid GMOCK WARNING "Uninteresting mock function call - returning
// directly" for FreeSymbolData().
EXPECT_CALL(supplier, FreeSymbolData(_)).Times(AnyNumber());
@@ -366,11 +369,11 @@ TEST_F(MinidumpProcessorTest, TestSymbolSupplierLookupCounts) {
EXPECT_CALL(supplier, GetCStringSymbolData(
Property(&google_breakpad::CodeModule::code_file,
"c:\\test_app.exe"),
- _, _, _)).WillOnce(Return(SymbolSupplier::NOT_FOUND));
+ _, _, _, _)).WillOnce(Return(SymbolSupplier::NOT_FOUND));
EXPECT_CALL(supplier, GetCStringSymbolData(
Property(&google_breakpad::CodeModule::code_file,
Ne("c:\\test_app.exe")),
- _, _, _)).WillRepeatedly(Return(SymbolSupplier::NOT_FOUND));
+ _, _, _, _)).WillRepeatedly(Return(SymbolSupplier::NOT_FOUND));
// Avoid GMOCK WARNING "Uninteresting mock function call - returning
// directly" for FreeSymbolData().
EXPECT_CALL(supplier, FreeSymbolData(_)).Times(AnyNumber());
diff --git a/src/processor/minidump_stackwalk.cc b/src/processor/minidump_stackwalk.cc
index 8bcf0dc1..756d8d0b 100644
--- a/src/processor/minidump_stackwalk.cc
+++ b/src/processor/minidump_stackwalk.cc
@@ -358,10 +358,15 @@ static bool ContainsModule(
static void PrintModule(
const CodeModule *module,
const vector<const CodeModule*> *modules_without_symbols,
+ const vector<const CodeModule*> *modules_with_corrupt_symbols,
uint64_t main_address) {
- string missing_symbols;
+ string symbol_issues;
if (ContainsModule(modules_without_symbols, module)) {
- missing_symbols = " (WARNING: No symbols, " +
+ symbol_issues = " (WARNING: No symbols, " +
+ PathnameStripper::File(module->debug_file()) + ", " +
+ module->debug_identifier() + ")";
+ } else if (ContainsModule(modules_with_corrupt_symbols, module)) {
+ symbol_issues = " (WARNING: Corrupt symbols, " +
PathnameStripper::File(module->debug_file()) + ", " +
module->debug_identifier() + ")";
}
@@ -371,7 +376,7 @@ static void PrintModule(
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());
+ symbol_issues.c_str());
}
// PrintModules prints the list of all loaded |modules| to stdout.
@@ -379,7 +384,8 @@ static void PrintModule(
// confirmed to be missing their symbols during the stack walk.
static void PrintModules(
const CodeModules *modules,
- const vector<const CodeModule*> *modules_without_symbols) {
+ const vector<const CodeModule*> *modules_without_symbols,
+ const vector<const CodeModule*> *modules_with_corrupt_symbols) {
if (!modules)
return;
@@ -397,7 +403,8 @@ static void PrintModules(
module_sequence < module_count;
++module_sequence) {
const CodeModule *module = modules->GetModuleAtSequence(module_sequence);
- PrintModule(module, modules_without_symbols, main_address);
+ PrintModule(module, modules_without_symbols, modules_with_corrupt_symbols,
+ main_address);
}
}
@@ -490,7 +497,8 @@ static void PrintProcessState(const ProcessState& process_state) {
}
PrintModules(process_state.modules(),
- process_state.modules_without_symbols());
+ process_state.modules_without_symbols(),
+ process_state.modules_with_corrupt_symbols());
}
static void PrintProcessStateMachineReadable(const ProcessState& process_state)
diff --git a/src/processor/module_comparer.cc b/src/processor/module_comparer.cc
index ba561eea..025ab883 100644
--- a/src/processor/module_comparer.cc
+++ b/src/processor/module_comparer.cc
@@ -58,8 +58,10 @@ bool ModuleComparer::Compare(const string &symbol_data) {
// Load symbol data into basic_module
scoped_array<char> buffer(new char[symbol_data.size() + 1]);
- strcpy(buffer.get(), symbol_data.c_str());
- ASSERT_TRUE(basic_module->LoadMapFromMemory(buffer.get()));
+ memcpy(buffer.get(), symbol_data.c_str(), symbol_data.size());
+ buffer.get()[symbol_data.size()] = '\0';
+ ASSERT_TRUE(basic_module->LoadMapFromMemory(buffer.get(),
+ symbol_data.size() + 1));
buffer.reset();
// Serialize BasicSourceLineResolver::Module.
@@ -70,7 +72,9 @@ bool ModuleComparer::Compare(const string &symbol_data) {
BPLOG(INFO) << "Serialized size = " << serialized_size << " Bytes";
// Load FastSourceLineResolver::Module using serialized data.
- ASSERT_TRUE(fast_module->LoadMapFromMemory(serialized_data.get()));
+ ASSERT_TRUE(fast_module->LoadMapFromMemory(serialized_data.get(),
+ serialized_size));
+ ASSERT_TRUE(fast_module->IsCorrupt() == basic_module->IsCorrupt());
// Compare FastSourceLineResolver::Module with
// BasicSourceLineResolver::Module.
diff --git a/src/processor/module_serializer.cc b/src/processor/module_serializer.cc
index cf64a7ef..6ac60c1f 100644
--- a/src/processor/module_serializer.cc
+++ b/src/processor/module_serializer.cc
@@ -51,6 +51,9 @@ SimpleSerializer<BasicSourceLineResolver::Function>::range_map_serializer_;
size_t ModuleSerializer::SizeOf(const BasicSourceLineResolver::Module &module) {
size_t total_size_alloc_ = 0;
+ // Size of the "is_corrupt" flag.
+ total_size_alloc_ += SimpleSerializer<bool>::SizeOf(module.is_corrupt_);
+
// Compute memory size for each map component in Module class.
int map_index = 0;
map_sizes_[map_index++] = files_serializer_.SizeOf(module.files_);
@@ -65,19 +68,22 @@ size_t ModuleSerializer::SizeOf(const BasicSourceLineResolver::Module &module) {
module.cfi_delta_rules_);
// Header size.
- total_size_alloc_ = kNumberMaps_ * sizeof(uint32_t);
+ total_size_alloc_ += kNumberMaps_ * sizeof(uint32_t);
- for (int i = 0; i < kNumberMaps_; ++i)
- total_size_alloc_ += map_sizes_[i];
+ for (int i = 0; i < kNumberMaps_; ++i) {
+ total_size_alloc_ += map_sizes_[i];
+ }
// Extra one byte for null terminator for C-string copy safety.
- ++total_size_alloc_;
+ total_size_alloc_ += SimpleSerializer<char>::SizeOf(0);
return total_size_alloc_;
}
char *ModuleSerializer::Write(const BasicSourceLineResolver::Module &module,
char *dest) {
+ // Write the is_corrupt flag.
+ dest = SimpleSerializer<bool>::Write(module.is_corrupt_, dest);
// Write header.
memcpy(dest, map_sizes_, kNumberMaps_ * sizeof(uint32_t));
dest += kNumberMaps_ * sizeof(uint32_t);
@@ -189,8 +195,9 @@ char* ModuleSerializer::SerializeSymbolFileData(
scoped_ptr<BasicSourceLineResolver::Module> module(
new BasicSourceLineResolver::Module("no name"));
scoped_array<char> buffer(new char[symbol_data.size() + 1]);
- strcpy(buffer.get(), symbol_data.c_str());
- if (!module->LoadMapFromMemory(buffer.get())) {
+ memcpy(buffer.get(), symbol_data.c_str(), symbol_data.size());
+ buffer.get()[symbol_data.size()] = '\0';
+ if (!module->LoadMapFromMemory(buffer.get(), symbol_data.size() + 1)) {
return NULL;
}
buffer.reset(NULL);
diff --git a/src/processor/process_state.cc b/src/processor/process_state.cc
index 6c3a6567..fae66776 100644
--- a/src/processor/process_state.cc
+++ b/src/processor/process_state.cc
@@ -57,9 +57,10 @@ 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_ and modules_with_corrupt_symbols_ DO NOT own
+ // the underlying CodeModule pointers. Just clear the vectors.
modules_without_symbols_.clear();
+ modules_with_corrupt_symbols_.clear();
delete modules_;
modules_ = NULL;
}
diff --git a/src/processor/simple_serializer-inl.h b/src/processor/simple_serializer-inl.h
index 6e5fe5d1..606bb3ce 100644
--- a/src/processor/simple_serializer-inl.h
+++ b/src/processor/simple_serializer-inl.h
@@ -60,6 +60,11 @@ class SimpleSerializer<bool> {
*dest = static_cast<char>(boolean? 255 : 0);
return ++dest;
}
+
+ static const char *Read(const char *source, bool *value) {
+ *value = ((*source) == 0 ? false : true);
+ return ++source;
+ }
};
// Specializations of SimpleSerializer: string
diff --git a/src/processor/simple_symbol_supplier.cc b/src/processor/simple_symbol_supplier.cc
index 4a3a1059..bc5ebb68 100644
--- a/src/processor/simple_symbol_supplier.cc
+++ b/src/processor/simple_symbol_supplier.cc
@@ -84,8 +84,8 @@ SymbolSupplier::SymbolResult SimpleSymbolSupplier::GetSymbolFile(
assert(symbol_data);
symbol_data->clear();
- SymbolSupplier::SymbolResult s = GetSymbolFile(module, system_info, symbol_file);
-
+ SymbolSupplier::SymbolResult s = GetSymbolFile(module, system_info,
+ symbol_file);
if (s == FOUND) {
std::ifstream in(symbol_file->c_str());
std::getline(in, *symbol_data, string::traits_type::to_char_type(
@@ -99,22 +99,25 @@ SymbolSupplier::SymbolResult SimpleSymbolSupplier::GetCStringSymbolData(
const CodeModule *module,
const SystemInfo *system_info,
string *symbol_file,
- char **symbol_data) {
+ char **symbol_data,
+ size_t *symbol_data_size) {
assert(symbol_data);
+ assert(symbol_data_size);
string symbol_data_string;
SymbolSupplier::SymbolResult s =
GetSymbolFile(module, system_info, symbol_file, &symbol_data_string);
if (s == FOUND) {
- unsigned int size = symbol_data_string.size() + 1;
- *symbol_data = new char[size];
+ *symbol_data_size = symbol_data_string.size() + 1;
+ *symbol_data = new char[*symbol_data_size];
if (*symbol_data == NULL) {
- BPLOG(ERROR) << "Memory allocation for size " << size << " failed";
+ BPLOG(ERROR) << "Memory allocation for size " << *symbol_data_size
+ << " failed";
return INTERRUPT;
}
- memcpy(*symbol_data, symbol_data_string.c_str(), size - 1);
- (*symbol_data)[size - 1] = '\0';
+ memcpy(*symbol_data, symbol_data_string.c_str(), symbol_data_string.size());
+ (*symbol_data)[symbol_data_string.size()] = '\0';
memory_buffers_.insert(make_pair(module->code_file(), *symbol_data));
}
return s;
diff --git a/src/processor/simple_symbol_supplier.h b/src/processor/simple_symbol_supplier.h
index e19b194c..0cde85cd 100644
--- a/src/processor/simple_symbol_supplier.h
+++ b/src/processor/simple_symbol_supplier.h
@@ -118,7 +118,8 @@ class SimpleSymbolSupplier : public SymbolSupplier {
virtual SymbolResult GetCStringSymbolData(const CodeModule *module,
const SystemInfo *system_info,
string *symbol_file,
- char **symbol_data);
+ char **symbol_data,
+ size_t *symbol_data_size);
// Free the data buffer allocated in the above GetCStringSymbolData();
virtual void FreeSymbolData(const CodeModule *module);
diff --git a/src/processor/source_line_resolver_base.cc b/src/processor/source_line_resolver_base.cc
index 49088c89..6eff1f99 100644
--- a/src/processor/source_line_resolver_base.cc
+++ b/src/processor/source_line_resolver_base.cc
@@ -53,6 +53,7 @@ namespace google_breakpad {
SourceLineResolverBase::SourceLineResolverBase(
ModuleFactory *module_factory)
: modules_(new ModuleMap),
+ corrupt_modules_(new ModuleSet),
memory_buffers_(new MemoryMap),
module_factory_(module_factory) {
}
@@ -66,6 +67,11 @@ SourceLineResolverBase::~SourceLineResolverBase() {
}
// Delete the map of modules.
delete modules_;
+ modules_ = NULL;
+
+ // Delete the set of corrupt modules.
+ delete corrupt_modules_;
+ corrupt_modules_ = NULL;
MemoryMap::iterator iter = memory_buffers_->begin();
for (; iter != memory_buffers_->end(); ++iter) {
@@ -73,13 +79,16 @@ SourceLineResolverBase::~SourceLineResolverBase() {
}
// Delete the map of memory buffers.
delete memory_buffers_;
+ memory_buffers_ = NULL;
delete module_factory_;
+ module_factory_ = NULL;
}
-bool SourceLineResolverBase::ReadSymbolFile(char **symbol_data,
- const string &map_file) {
- if (symbol_data == NULL) {
+bool SourceLineResolverBase::ReadSymbolFile(const string &map_file,
+ char **symbol_data,
+ size_t *symbol_data_size) {
+ if (symbol_data == NULL || symbol_data_size == NULL) {
BPLOG(ERROR) << "Could not Read file into Null memory pointer";
return false;
}
@@ -98,6 +107,7 @@ bool SourceLineResolverBase::ReadSymbolFile(char **symbol_data,
// Allocate memory for file contents, plus a null terminator
// since we may use strtok() on the contents.
+ *symbol_data_size = file_size + 1;
*symbol_data = new char[file_size + 1];
if (*symbol_data == NULL) {
@@ -154,12 +164,14 @@ bool SourceLineResolverBase::LoadModule(const CodeModule *module,
<< " from " << map_file;
char *memory_buffer;
- if (!ReadSymbolFile(&memory_buffer, map_file))
+ size_t memory_buffer_size;
+ if (!ReadSymbolFile(map_file, &memory_buffer, &memory_buffer_size))
return false;
BPLOG(INFO) << "Read symbol file " << map_file << " succeeded";
- bool load_result = LoadModuleUsingMemoryBuffer(module, memory_buffer);
+ bool load_result = LoadModuleUsingMemoryBuffer(module, memory_buffer,
+ memory_buffer_size);
if (load_result && !ShouldDeleteMemoryBufferAfterLoadModule()) {
// memory_buffer has to stay alive as long as the module.
@@ -183,7 +195,8 @@ bool SourceLineResolverBase::LoadModuleUsingMapBuffer(
return false;
}
- char *memory_buffer = new char[map_buffer.size() + 1];
+ size_t memory_buffer_size = map_buffer.size() + 1;
+ char *memory_buffer = new char[memory_buffer_size];
if (memory_buffer == NULL) {
BPLOG(ERROR) << "Could not allocate memory for " << module->code_file();
return false;
@@ -193,7 +206,8 @@ bool SourceLineResolverBase::LoadModuleUsingMapBuffer(
memcpy(memory_buffer, map_buffer.c_str(), map_buffer.size());
memory_buffer[map_buffer.size()] = '\0';
- bool load_result = LoadModuleUsingMemoryBuffer(module, memory_buffer);
+ bool load_result = LoadModuleUsingMemoryBuffer(module, memory_buffer,
+ memory_buffer_size);
if (load_result && !ShouldDeleteMemoryBufferAfterLoadModule()) {
// memory_buffer has to stay alive as long as the module.
@@ -206,7 +220,9 @@ bool SourceLineResolverBase::LoadModuleUsingMapBuffer(
}
bool SourceLineResolverBase::LoadModuleUsingMemoryBuffer(
- const CodeModule *module, char *memory_buffer) {
+ const CodeModule *module,
+ char *memory_buffer,
+ size_t memory_buffer_size) {
if (!module)
return false;
@@ -223,12 +239,19 @@ bool SourceLineResolverBase::LoadModuleUsingMemoryBuffer(
Module *basic_module = module_factory_->CreateModule(module->code_file());
// Ownership of memory is NOT transfered to Module::LoadMapFromMemory().
- if (!basic_module->LoadMapFromMemory(memory_buffer)) {
- delete basic_module;
- return false;
+ if (!basic_module->LoadMapFromMemory(memory_buffer, memory_buffer_size)) {
+ BPLOG(ERROR) << "Too many error while parsing symbol data for module "
+ << module->code_file();
+ // Returning false from here would be an indication that the symbols for
+ // this module are missing which would be wrong. Intentionally fall through
+ // and add the module to both the modules_ and the corrupt_modules_ lists.
+ assert(basic_module->IsCorrupt());
}
modules_->insert(make_pair(module->code_file(), basic_module));
+ if (basic_module->IsCorrupt()) {
+ corrupt_modules_->insert(module->code_file());
+ }
return true;
}
@@ -244,6 +267,7 @@ void SourceLineResolverBase::UnloadModule(const CodeModule *code_module) {
if (mod_iter != modules_->end()) {
Module *symbol_module = mod_iter->second;
delete symbol_module;
+ corrupt_modules_->erase(mod_iter->first);
modules_->erase(mod_iter);
}
@@ -265,6 +289,12 @@ bool SourceLineResolverBase::HasModule(const CodeModule *module) {
return modules_->find(module->code_file()) != modules_->end();
}
+bool SourceLineResolverBase::IsModuleCorrupt(const CodeModule *module) {
+ if (!module)
+ return false;
+ return corrupt_modules_->find(module->code_file()) != corrupt_modules_->end();
+}
+
void SourceLineResolverBase::FillSourceLineInfo(StackFrame *frame) {
if (frame->module) {
ModuleMap::const_iterator it = modules_->find(frame->module->code_file());
diff --git a/src/processor/source_line_resolver_base_types.h b/src/processor/source_line_resolver_base_types.h
index 1dc3d62a..4a9dfb3c 100644
--- a/src/processor/source_line_resolver_base_types.h
+++ b/src/processor/source_line_resolver_base_types.h
@@ -121,7 +121,15 @@ class SourceLineResolverBase::Module {
// Loads a map from the given buffer in char* type.
// Does NOT take ownership of memory_buffer (the caller, source line resolver,
// is the owner of memory_buffer).
- virtual bool LoadMapFromMemory(char *memory_buffer) = 0;
+ // The passed in |memory buffer| is of size |memory_buffer_size|. If it is
+ // not null terminated, LoadMapFromMemory will null terminate it by modifying
+ // the passed in buffer.
+ virtual bool LoadMapFromMemory(char *memory_buffer,
+ size_t memory_buffer_size) = 0;
+
+ // Tells whether the loaded symbol data is corrupt. Return value is
+ // undefined, if the symbol data hasn't been loaded yet.
+ virtual bool IsCorrupt() const = 0;
// Looks up the given relative address, and fills the StackFrame struct
// with the result.
diff --git a/src/processor/stack_frame_symbolizer.cc b/src/processor/stack_frame_symbolizer.cc
index 8e020c98..5c8dbe5e 100644
--- a/src/processor/stack_frame_symbolizer.cc
+++ b/src/processor/stack_frame_symbolizer.cc
@@ -74,7 +74,8 @@ StackFrameSymbolizer::SymbolizerResult StackFrameSymbolizer::FillSourceLineInfo(
// If module is already loaded, go ahead to fill source line info and return.
if (resolver_->HasModule(frame->module)) {
resolver_->FillSourceLineInfo(frame);
- return kNoError;
+ return resolver_->IsModuleCorrupt(frame->module) ?
+ kWarningCorruptSymbols : kNoError;
}
// Module needs to fetch symbol file. First check to see if supplier exists.
@@ -85,20 +86,24 @@ StackFrameSymbolizer::SymbolizerResult StackFrameSymbolizer::FillSourceLineInfo(
// Start fetching symbol from supplier.
string symbol_file;
char* symbol_data = NULL;
+ size_t symbol_data_size;
SymbolSupplier::SymbolResult symbol_result = supplier_->GetCStringSymbolData(
- module, system_info, &symbol_file, &symbol_data);
+ module, system_info, &symbol_file, &symbol_data, &symbol_data_size);
switch (symbol_result) {
case SymbolSupplier::FOUND: {
- bool load_success = resolver_->LoadModuleUsingMemoryBuffer(frame->module,
- symbol_data);
+ bool load_success = resolver_->LoadModuleUsingMemoryBuffer(
+ frame->module,
+ symbol_data,
+ symbol_data_size);
if (resolver_->ShouldDeleteMemoryBufferAfterLoadModule()) {
supplier_->FreeSymbolData(module);
}
if (load_success) {
resolver_->FillSourceLineInfo(frame);
- return kNoError;
+ return resolver_->IsModuleCorrupt(frame->module) ?
+ kWarningCorruptSymbols : kNoError;
} else {
BPLOG(ERROR) << "Failed to load symbol file in resolver.";
no_symbol_modules_.insert(module->code_file());
diff --git a/src/processor/stackwalker.cc b/src/processor/stackwalker.cc
index fff3392d..00358b26 100644
--- a/src/processor/stackwalker.cc
+++ b/src/processor/stackwalker.cc
@@ -71,16 +71,46 @@ Stackwalker::Stackwalker(const SystemInfo* system_info,
assert(frame_symbolizer_);
}
+void InsertSpecialAttentionModule(
+ StackFrameSymbolizer::SymbolizerResult symbolizer_result,
+ const CodeModule* module,
+ vector<const CodeModule*>* modules) {
+ if (!module) {
+ return;
+ }
+ assert(symbolizer_result == StackFrameSymbolizer::kError ||
+ symbolizer_result == StackFrameSymbolizer::kWarningCorruptSymbols);
+ bool found = false;
+ vector<const CodeModule*>::iterator iter;
+ for (iter = modules->begin(); iter != modules->end(); ++iter) {
+ if (*iter == module) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ BPLOG(INFO) << ((symbolizer_result == StackFrameSymbolizer::kError) ?
+ "Couldn't load symbols for: " :
+ "Detected corrupt symbols for: ")
+ << module->debug_file() << "|" << module->debug_identifier();
+ modules->push_back(module);
+ }
+}
-bool Stackwalker::Walk(CallStack* stack,
- vector<const CodeModule*>* modules_without_symbols) {
+bool Stackwalker::Walk(
+ CallStack* stack,
+ vector<const CodeModule*>* modules_without_symbols,
+ vector<const CodeModule*>* modules_with_corrupt_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|";
+ BPLOG_IF(ERROR, !modules_without_symbols) << "Stackwalker::Walk requires "
+ << "|modules_with_corrupt_symbols|";
assert(modules_without_symbols);
+ assert(modules_with_corrupt_symbols);
// Begin with the context frame, and keep getting callers until there are
// no more.
@@ -97,30 +127,24 @@ bool Stackwalker::Walk(CallStack* stack,
StackFrameSymbolizer::SymbolizerResult symbolizer_result =
frame_symbolizer_->FillSourceLineInfo(modules_, system_info_,
frame.get());
- if (symbolizer_result == StackFrameSymbolizer::kInterrupt) {
- BPLOG(INFO) << "Stack walk is interrupted.";
- 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);
- }
+ switch (symbolizer_result) {
+ case StackFrameSymbolizer::kInterrupt:
+ BPLOG(INFO) << "Stack walk is interrupted.";
+ return false;
+ break;
+ case StackFrameSymbolizer::kError:
+ InsertSpecialAttentionModule(symbolizer_result, frame->module,
+ modules_without_symbols);
+ break;
+ case StackFrameSymbolizer::kWarningCorruptSymbols:
+ InsertSpecialAttentionModule(symbolizer_result, frame->module,
+ modules_with_corrupt_symbols);
+ break;
+ case StackFrameSymbolizer::kNoError:
+ break;
+ default:
+ assert(false);
+ break;
}
// Add the frame to the call stack. Relinquish the ownership claim
@@ -222,7 +246,8 @@ bool Stackwalker::InstructionAddressSeemsValid(uint64_t address) {
return true;
}
- if (symbolizer_result != StackFrameSymbolizer::kNoError) {
+ if (symbolizer_result != StackFrameSymbolizer::kNoError &&
+ symbolizer_result != StackFrameSymbolizer::kWarningCorruptSymbols) {
// Some error occurred during symbolization, but the address is within a
// known module
return true;
diff --git a/src/processor/stackwalker_amd64_unittest.cc b/src/processor/stackwalker_amd64_unittest.cc
index a0175a9b..169316c6 100644
--- a/src/processor/stackwalker_amd64_unittest.cc
+++ b/src/processor/stackwalker_amd64_unittest.cc
@@ -89,7 +89,7 @@ class StackwalkerAMD64Fixture {
// By default, none of the modules have symbol info; call
// SetModuleSymbols to override this.
- EXPECT_CALL(supplier, GetCStringSymbolData(_, _, _, _))
+ EXPECT_CALL(supplier, GetCStringSymbolData(_, _, _, _, _))
.WillRepeatedly(Return(MockSymbolSupplier::NOT_FOUND));
// Avoid GMOCK WARNING "Uninteresting mock function call - returning
@@ -100,9 +100,11 @@ class StackwalkerAMD64Fixture {
// Set the Breakpad symbol information that supplier should return for
// MODULE to INFO.
void SetModuleSymbols(MockCodeModule *module, const string &info) {
- char *buffer = supplier.CopySymbolDataAndOwnTheCopy(info);
- EXPECT_CALL(supplier, GetCStringSymbolData(module, &system_info, _, _))
+ size_t buffer_size;
+ char *buffer = supplier.CopySymbolDataAndOwnTheCopy(info, &buffer_size);
+ EXPECT_CALL(supplier, GetCStringSymbolData(module, &system_info, _, _, _))
.WillRepeatedly(DoAll(SetArgumentPointee<3>(buffer),
+ SetArgumentPointee<4>(buffer_size),
Return(MockSymbolSupplier::FOUND)));
}
@@ -151,9 +153,12 @@ TEST_F(SanityCheck, NoResolver) {
&frame_symbolizer);
// This should succeed even without a resolver or supplier.
vector<const CodeModule*> modules_without_symbols;
- ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
+ vector<const CodeModule*> modules_with_corrupt_symbols;
+ ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols,
+ &modules_with_corrupt_symbols));
ASSERT_EQ(1U, modules_without_symbols.size());
ASSERT_EQ("module1", modules_without_symbols[0]->debug_file());
+ ASSERT_EQ(0U, modules_with_corrupt_symbols.size());
frames = call_stack.frames();
ASSERT_GE(1U, frames->size());
StackFrameAMD64 *frame = static_cast<StackFrameAMD64 *>(frames->at(0));
@@ -174,9 +179,12 @@ TEST_F(GetContextFrame, Simple) {
StackwalkerAMD64 walker(&system_info, &raw_context, &stack_region, &modules,
&frame_symbolizer);
vector<const CodeModule*> modules_without_symbols;
- ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
+ vector<const CodeModule*> modules_with_corrupt_symbols;
+ ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols,
+ &modules_with_corrupt_symbols));
ASSERT_EQ(1U, modules_without_symbols.size());
ASSERT_EQ("module1", modules_without_symbols[0]->debug_file());
+ ASSERT_EQ(0U, modules_with_corrupt_symbols.size());
frames = call_stack.frames();
ASSERT_GE(1U, frames->size());
StackFrameAMD64 *frame = static_cast<StackFrameAMD64 *>(frames->at(0));
@@ -195,9 +203,12 @@ TEST_F(GetContextFrame, NoStackMemory) {
StackwalkerAMD64 walker(&system_info, &raw_context, NULL, &modules,
&frame_symbolizer);
vector<const CodeModule*> modules_without_symbols;
- ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
+ vector<const CodeModule*> modules_with_corrupt_symbols;
+ ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols,
+ &modules_with_corrupt_symbols));
ASSERT_EQ(1U, modules_without_symbols.size());
ASSERT_EQ("module1", modules_without_symbols[0]->debug_file());
+ ASSERT_EQ(0U, modules_with_corrupt_symbols.size());
frames = call_stack.frames();
ASSERT_GE(1U, frames->size());
StackFrameAMD64 *frame = static_cast<StackFrameAMD64 *>(frames->at(0));
@@ -253,10 +264,13 @@ TEST_F(GetCallerFrame, ScanWithoutSymbols) {
StackwalkerAMD64 walker(&system_info, &raw_context, &stack_region, &modules,
&frame_symbolizer);
vector<const CodeModule*> modules_without_symbols;
- ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
+ vector<const CodeModule*> modules_with_corrupt_symbols;
+ ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols,
+ &modules_with_corrupt_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());
+ ASSERT_EQ(0U, modules_with_corrupt_symbols.size());
frames = call_stack.frames();
ASSERT_EQ(3U, frames->size());
@@ -325,8 +339,11 @@ TEST_F(GetCallerFrame, ScanWithFunctionSymbols) {
StackwalkerAMD64 walker(&system_info, &raw_context, &stack_region, &modules,
&frame_symbolizer);
vector<const CodeModule*> modules_without_symbols;
- ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
+ vector<const CodeModule*> modules_with_corrupt_symbols;
+ ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols,
+ &modules_with_corrupt_symbols));
ASSERT_EQ(0U, modules_without_symbols.size());
+ ASSERT_EQ(0U, modules_with_corrupt_symbols.size());
frames = call_stack.frames();
ASSERT_EQ(2U, frames->size());
@@ -392,8 +409,11 @@ TEST_F(GetCallerFrame, CallerPushedRBP) {
StackwalkerAMD64 walker(&system_info, &raw_context, &stack_region, &modules,
&frame_symbolizer);
vector<const CodeModule*> modules_without_symbols;
- ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
+ vector<const CodeModule*> modules_with_corrupt_symbols;
+ ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols,
+ &modules_with_corrupt_symbols));
ASSERT_EQ(0U, modules_without_symbols.size());
+ ASSERT_EQ(0U, modules_with_corrupt_symbols.size());
frames = call_stack.frames();
ASSERT_EQ(2U, frames->size());
@@ -470,8 +490,11 @@ struct CFIFixture: public StackwalkerAMD64Fixture {
StackwalkerAMD64 walker(&system_info, &raw_context, &stack_region, &modules,
&frame_symbolizer);
vector<const CodeModule*> modules_without_symbols;
- ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
+ vector<const CodeModule*> modules_with_corrupt_symbols;
+ ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols,
+ &modules_with_corrupt_symbols));
ASSERT_EQ(0U, modules_without_symbols.size());
+ ASSERT_EQ(0U, modules_with_corrupt_symbols.size());
frames = call_stack.frames();
ASSERT_EQ(2U, frames->size());
diff --git a/src/processor/stackwalker_arm_unittest.cc b/src/processor/stackwalker_arm_unittest.cc
index 29deac87..b50f4e99 100644
--- a/src/processor/stackwalker_arm_unittest.cc
+++ b/src/processor/stackwalker_arm_unittest.cc
@@ -91,7 +91,7 @@ class StackwalkerARMFixture {
// By default, none of the modules have symbol info; call
// SetModuleSymbols to override this.
- EXPECT_CALL(supplier, GetCStringSymbolData(_, _, _, _))
+ EXPECT_CALL(supplier, GetCStringSymbolData(_, _, _, _, _))
.WillRepeatedly(Return(MockSymbolSupplier::NOT_FOUND));
// Avoid GMOCK WARNING "Uninteresting mock function call - returning
@@ -102,9 +102,11 @@ class StackwalkerARMFixture {
// Set the Breakpad symbol information that supplier should return for
// MODULE to INFO.
void SetModuleSymbols(MockCodeModule *module, const string &info) {
- char *buffer = supplier.CopySymbolDataAndOwnTheCopy(info);
- EXPECT_CALL(supplier, GetCStringSymbolData(module, &system_info, _, _))
+ size_t buffer_size;
+ char *buffer = supplier.CopySymbolDataAndOwnTheCopy(info, &buffer_size);
+ EXPECT_CALL(supplier, GetCStringSymbolData(module, &system_info, _, _, _))
.WillRepeatedly(DoAll(SetArgumentPointee<3>(buffer),
+ SetArgumentPointee<4>(buffer_size),
Return(MockSymbolSupplier::FOUND)));
}
@@ -147,8 +149,11 @@ TEST_F(SanityCheck, NoResolver) {
&frame_symbolizer);
// This should succeed even without a resolver or supplier.
vector<const CodeModule*> modules_without_symbols;
- ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
+ vector<const CodeModule*> modules_with_corrupt_symbols;
+ ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols,
+ &modules_with_corrupt_symbols));
ASSERT_EQ(0U, modules_without_symbols.size());
+ ASSERT_EQ(0U, modules_with_corrupt_symbols.size());
frames = call_stack.frames();
ASSERT_EQ(1U, frames->size());
StackFrameARM *frame = static_cast<StackFrameARM *>(frames->at(0));
@@ -167,8 +172,11 @@ TEST_F(GetContextFrame, Simple) {
StackwalkerARM walker(&system_info, &raw_context, -1, &stack_region, &modules,
&frame_symbolizer);
vector<const CodeModule*> modules_without_symbols;
- ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
+ vector<const CodeModule*> modules_with_corrupt_symbols;
+ ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols,
+ &modules_with_corrupt_symbols));
ASSERT_EQ(0U, modules_without_symbols.size());
+ ASSERT_EQ(0U, modules_with_corrupt_symbols.size());
frames = call_stack.frames();
ASSERT_EQ(1U, frames->size());
StackFrameARM *frame = static_cast<StackFrameARM *>(frames->at(0));
@@ -184,8 +192,11 @@ TEST_F(GetContextFrame, NoStackMemory) {
StackwalkerARM walker(&system_info, &raw_context, -1, NULL, &modules,
&frame_symbolizer);
vector<const CodeModule*> modules_without_symbols;
- ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
+ vector<const CodeModule*> modules_with_corrupt_symbols;
+ ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols,
+ &modules_with_corrupt_symbols));
ASSERT_EQ(0U, modules_without_symbols.size());
+ ASSERT_EQ(0U, modules_with_corrupt_symbols.size());
frames = call_stack.frames();
ASSERT_EQ(1U, frames->size());
StackFrameARM *frame = static_cast<StackFrameARM *>(frames->at(0));
@@ -234,10 +245,13 @@ TEST_F(GetCallerFrame, ScanWithoutSymbols) {
StackwalkerARM walker(&system_info, &raw_context, -1, &stack_region, &modules,
&frame_symbolizer);
vector<const CodeModule*> modules_without_symbols;
- ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
+ vector<const CodeModule*> modules_with_corrupt_symbols;
+ ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols,
+ &modules_with_corrupt_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());
+ ASSERT_EQ(0U, modules_with_corrupt_symbols.size());
frames = call_stack.frames();
ASSERT_EQ(3U, frames->size());
@@ -302,8 +316,11 @@ TEST_F(GetCallerFrame, ScanWithFunctionSymbols) {
StackwalkerARM walker(&system_info, &raw_context, -1, &stack_region, &modules,
&frame_symbolizer);
vector<const CodeModule*> modules_without_symbols;
- ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
+ vector<const CodeModule*> modules_with_corrupt_symbols;
+ ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols,
+ &modules_with_corrupt_symbols));
ASSERT_EQ(0U, modules_without_symbols.size());
+ ASSERT_EQ(0U, modules_with_corrupt_symbols.size());
frames = call_stack.frames();
ASSERT_EQ(2U, frames->size());
@@ -365,10 +382,13 @@ TEST_F(GetCallerFrame, ScanFirstFrame) {
StackwalkerARM walker(&system_info, &raw_context, -1, &stack_region, &modules,
&frame_symbolizer);
vector<const CodeModule*> modules_without_symbols;
- ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
+ vector<const CodeModule*> modules_with_corrupt_symbols;
+ ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols,
+ &modules_with_corrupt_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());
+ ASSERT_EQ(0U, modules_with_corrupt_symbols.size());
frames = call_stack.frames();
ASSERT_EQ(2U, frames->size());
@@ -477,8 +497,11 @@ struct CFIFixture: public StackwalkerARMFixture {
&modules, &frame_symbolizer);
walker.SetContextFrameValidity(context_frame_validity);
vector<const CodeModule*> modules_without_symbols;
- ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
+ vector<const CodeModule*> modules_with_corrupt_symbols;
+ ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols,
+ &modules_with_corrupt_symbols));
ASSERT_EQ(0U, modules_without_symbols.size());
+ ASSERT_EQ(0U, modules_with_corrupt_symbols.size());
frames = call_stack.frames();
ASSERT_EQ(2U, frames->size());
@@ -671,8 +694,11 @@ TEST_F(CFI, RejectBackwards) {
StackwalkerARM walker(&system_info, &raw_context, -1, &stack_region, &modules,
&frame_symbolizer);
vector<const CodeModule*> modules_without_symbols;
- ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
+ vector<const CodeModule*> modules_with_corrupt_symbols;
+ ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols,
+ &modules_with_corrupt_symbols));
ASSERT_EQ(0U, modules_without_symbols.size());
+ ASSERT_EQ(0U, modules_with_corrupt_symbols.size());
frames = call_stack.frames();
ASSERT_EQ(1U, frames->size());
}
@@ -685,8 +711,11 @@ TEST_F(CFI, RejectBadExpressions) {
StackwalkerARM walker(&system_info, &raw_context, -1, &stack_region, &modules,
&frame_symbolizer);
vector<const CodeModule*> modules_without_symbols;
- ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
+ vector<const CodeModule*> modules_with_corrupt_symbols;
+ ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols,
+ &modules_with_corrupt_symbols));
ASSERT_EQ(0U, modules_without_symbols.size());
+ ASSERT_EQ(0U, modules_with_corrupt_symbols.size());
frames = call_stack.frames();
ASSERT_EQ(1U, frames->size());
}
@@ -745,10 +774,13 @@ TEST_F(GetFramesByFramePointer, OnlyFramePointer) {
&stack_region, &modules, &frame_symbolizer);
vector<const CodeModule*> modules_without_symbols;
- ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
+ vector<const CodeModule*> modules_with_corrupt_symbols;
+ ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols,
+ &modules_with_corrupt_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());
+ ASSERT_EQ(0U, modules_with_corrupt_symbols.size());
frames = call_stack.frames();
ASSERT_EQ(3U, frames->size());
@@ -839,9 +871,12 @@ TEST_F(GetFramesByFramePointer, FramePointerAndCFI) {
&stack_region, &modules, &frame_symbolizer);
vector<const CodeModule*> modules_without_symbols;
- ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
+ vector<const CodeModule*> modules_with_corrupt_symbols;
+ ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols,
+ &modules_with_corrupt_symbols));
ASSERT_EQ(1U, modules_without_symbols.size());
ASSERT_EQ("module2", modules_without_symbols[0]->debug_file());
+ ASSERT_EQ(0U, modules_with_corrupt_symbols.size());
frames = call_stack.frames();
ASSERT_EQ(3U, frames->size());
diff --git a/src/processor/stackwalker_unittest_utils.h b/src/processor/stackwalker_unittest_utils.h
index 07638661..a72b8e0d 100644
--- a/src/processor/stackwalker_unittest_utils.h
+++ b/src/processor/stackwalker_unittest_utils.h
@@ -171,18 +171,21 @@ class MockSymbolSupplier: public google_breakpad::SymbolSupplier {
const SystemInfo *system_info,
string *symbol_file,
string *symbol_data));
- MOCK_METHOD4(GetCStringSymbolData, SymbolResult(const CodeModule *module,
+ MOCK_METHOD5(GetCStringSymbolData, SymbolResult(const CodeModule *module,
const SystemInfo *system_info,
string *symbol_file,
- char **symbol_data));
+ char **symbol_data,
+ size_t *symbol_data_size));
MOCK_METHOD1(FreeSymbolData, void(const CodeModule *module));
// Copies the passed string contents into a newly allocated buffer.
// The newly allocated buffer will be freed during destruction.
- char* CopySymbolDataAndOwnTheCopy(const std::string &info) {
- unsigned int buffer_size = info.size() + 1;
- char *symbol_data = new char [buffer_size];
- strcpy(symbol_data, info.c_str());
+ char* CopySymbolDataAndOwnTheCopy(const std::string &info,
+ size_t *symbol_data_size) {
+ *symbol_data_size = info.size() + 1;
+ char *symbol_data = new char[*symbol_data_size];
+ memcpy(symbol_data, info.c_str(), info.size());
+ symbol_data[info.size()] = '\0';
symbol_data_to_free_.push_back(symbol_data);
return symbol_data;
}
diff --git a/src/processor/stackwalker_x86_unittest.cc b/src/processor/stackwalker_x86_unittest.cc
index d25a570a..03df3210 100644
--- a/src/processor/stackwalker_x86_unittest.cc
+++ b/src/processor/stackwalker_x86_unittest.cc
@@ -98,7 +98,7 @@ class StackwalkerX86Fixture {
// By default, none of the modules have symbol info; call
// SetModuleSymbols to override this.
- EXPECT_CALL(supplier, GetCStringSymbolData(_, _, _, _))
+ EXPECT_CALL(supplier, GetCStringSymbolData(_, _, _, _, _))
.WillRepeatedly(Return(MockSymbolSupplier::NOT_FOUND));
// Avoid GMOCK WARNING "Uninteresting mock function call - returning
@@ -109,9 +109,11 @@ class StackwalkerX86Fixture {
// Set the Breakpad symbol information that supplier should return for
// MODULE to INFO.
void SetModuleSymbols(MockCodeModule *module, const string &info) {
- char *buffer = supplier.CopySymbolDataAndOwnTheCopy(info);
- EXPECT_CALL(supplier, GetCStringSymbolData(module, &system_info, _, _))
+ size_t buffer_size;
+ char *buffer = supplier.CopySymbolDataAndOwnTheCopy(info, &buffer_size);
+ EXPECT_CALL(supplier, GetCStringSymbolData(module, &system_info, _, _, _))
.WillRepeatedly(DoAll(SetArgumentPointee<3>(buffer),
+ SetArgumentPointee<4>(buffer_size),
Return(MockSymbolSupplier::FOUND)));
}
@@ -161,9 +163,12 @@ TEST_F(SanityCheck, NoResolver) {
&frame_symbolizer);
// This should succeed, even without a resolver or supplier.
vector<const CodeModule*> modules_without_symbols;
- ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
+ vector<const CodeModule*> modules_with_corrupt_symbols;
+ ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols,
+ &modules_with_corrupt_symbols));
ASSERT_EQ(1U, modules_without_symbols.size());
ASSERT_EQ("module1", modules_without_symbols[0]->debug_file());
+ ASSERT_EQ(0U, modules_with_corrupt_symbols.size());
frames = call_stack.frames();
StackFrameX86 *frame = static_cast<StackFrameX86 *>(frames->at(0));
// Check that the values from the original raw context made it
@@ -184,9 +189,12 @@ TEST_F(GetContextFrame, Simple) {
StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules,
&frame_symbolizer);
vector<const CodeModule*> modules_without_symbols;
- ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
+ vector<const CodeModule*> modules_with_corrupt_symbols;
+ ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols,
+ &modules_with_corrupt_symbols));
ASSERT_EQ(1U, modules_without_symbols.size());
ASSERT_EQ("module1", modules_without_symbols[0]->debug_file());
+ ASSERT_EQ(0U, modules_with_corrupt_symbols.size());
frames = call_stack.frames();
StackFrameX86 *frame = static_cast<StackFrameX86 *>(frames->at(0));
// Check that the values from the original raw context made it
@@ -204,9 +212,12 @@ TEST_F(GetContextFrame, NoStackMemory) {
StackwalkerX86 walker(&system_info, &raw_context, NULL, &modules,
&frame_symbolizer);
vector<const CodeModule*> modules_without_symbols;
- ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
+ vector<const CodeModule*> modules_with_corrupt_symbols;
+ ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols,
+ &modules_with_corrupt_symbols));
ASSERT_EQ(1U, modules_without_symbols.size());
ASSERT_EQ("module1", modules_without_symbols[0]->debug_file());
+ ASSERT_EQ(0U, modules_with_corrupt_symbols.size());
frames = call_stack.frames();
StackFrameX86 *frame = static_cast<StackFrameX86 *>(frames->at(0));
// Check that the values from the original raw context made it
@@ -214,7 +225,10 @@ TEST_F(GetContextFrame, NoStackMemory) {
EXPECT_EQ(0, memcmp(&raw_context, &frame->context, sizeof(raw_context)));
}
-class GetCallerFrame: public StackwalkerX86Fixture, public Test { };
+class GetCallerFrame: public StackwalkerX86Fixture, public Test {
+ protected:
+ void IPAddressIsNotInKnownModuleTestImpl(bool has_corrupt_symbols);
+};
// Walk a traditional frame. A traditional frame saves the caller's
// %ebp just below the return address, and has its own %ebp pointing
@@ -240,9 +254,12 @@ TEST_F(GetCallerFrame, Traditional) {
StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules,
&frame_symbolizer);
vector<const CodeModule*> modules_without_symbols;
- ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
+ vector<const CodeModule*> modules_with_corrupt_symbols;
+ ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols,
+ &modules_with_corrupt_symbols));
ASSERT_EQ(1U, modules_without_symbols.size());
ASSERT_EQ("module1", modules_without_symbols[0]->debug_file());
+ ASSERT_EQ(0U, modules_with_corrupt_symbols.size());
frames = call_stack.frames();
ASSERT_EQ(2U, frames->size());
@@ -301,9 +318,12 @@ TEST_F(GetCallerFrame, TraditionalScan) {
StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules,
&frame_symbolizer);
vector<const CodeModule*> modules_without_symbols;
- ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
+ vector<const CodeModule*> modules_with_corrupt_symbols;
+ ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols,
+ &modules_with_corrupt_symbols));
ASSERT_EQ(1U, modules_without_symbols.size());
ASSERT_EQ("module1", modules_without_symbols[0]->debug_file());
+ ASSERT_EQ(0U, modules_with_corrupt_symbols.size());
frames = call_stack.frames();
ASSERT_EQ(2U, frames->size());
@@ -364,9 +384,12 @@ TEST_F(GetCallerFrame, TraditionalScanLongWay) {
StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules,
&frame_symbolizer);
vector<const CodeModule*> modules_without_symbols;
- ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
+ vector<const CodeModule*> modules_with_corrupt_symbols;
+ ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols,
+ &modules_with_corrupt_symbols));
ASSERT_EQ(1U, modules_without_symbols.size());
ASSERT_EQ("module1", modules_without_symbols[0]->debug_file());
+ ASSERT_EQ(0U, modules_with_corrupt_symbols.size());
frames = call_stack.frames();
ASSERT_EQ(2U, frames->size());
@@ -435,8 +458,11 @@ TEST_F(GetCallerFrame, WindowsFrameData) {
StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules,
&frame_symbolizer);
vector<const CodeModule*> modules_without_symbols;
- ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
+ vector<const CodeModule*> modules_with_corrupt_symbols;
+ ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols,
+ &modules_with_corrupt_symbols));
ASSERT_EQ(0U, modules_without_symbols.size());
+ ASSERT_EQ(0U, modules_with_corrupt_symbols.size());
frames = call_stack.frames();
ASSERT_EQ(2U, frames->size());
@@ -509,9 +535,12 @@ TEST_F(GetCallerFrame, WindowsFrameDataAligned) {
StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules,
&frame_symbolizer);
vector<const CodeModule*> modules_without_symbols;
- ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
+ vector<const CodeModule*> modules_with_corrupt_symbols;
+ ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols,
+ &modules_with_corrupt_symbols));
ASSERT_EQ(1U, modules_without_symbols.size());
ASSERT_EQ("module2", modules_without_symbols[0]->debug_file());
+ ASSERT_EQ(0U, modules_with_corrupt_symbols.size());
frames = call_stack.frames();
ASSERT_EQ(2U, frames->size());
@@ -595,8 +624,11 @@ TEST_F(GetCallerFrame, WindowsFrameDataParameterSize) {
StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules,
&frame_symbolizer);
vector<const CodeModule*> modules_without_symbols;
- ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
+ vector<const CodeModule*> modules_with_corrupt_symbols;
+ ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols,
+ &modules_with_corrupt_symbols));
ASSERT_EQ(0U, modules_without_symbols.size());
+ ASSERT_EQ(0U, modules_with_corrupt_symbols.size());
frames = call_stack.frames();
ASSERT_EQ(3U, frames->size());
@@ -692,8 +724,11 @@ TEST_F(GetCallerFrame, WindowsFrameDataScan) {
StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules,
&frame_symbolizer);
vector<const CodeModule*> modules_without_symbols;
- ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
+ vector<const CodeModule*> modules_with_corrupt_symbols;
+ ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols,
+ &modules_with_corrupt_symbols));
ASSERT_EQ(0U, modules_without_symbols.size());
+ ASSERT_EQ(0U, modules_with_corrupt_symbols.size());
frames = call_stack.frames();
ASSERT_EQ(2U, frames->size());
@@ -778,8 +813,11 @@ TEST_F(GetCallerFrame, WindowsFrameDataBadEIPScan) {
StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules,
&frame_symbolizer);
vector<const CodeModule*> modules_without_symbols;
- ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
+ vector<const CodeModule*> modules_with_corrupt_symbols;
+ ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols,
+ &modules_with_corrupt_symbols));
ASSERT_EQ(0U, modules_without_symbols.size());
+ ASSERT_EQ(0U, modules_with_corrupt_symbols.size());
frames = call_stack.frames();
ASSERT_EQ(2U, frames->size());
@@ -848,8 +886,11 @@ TEST_F(GetCallerFrame, WindowsFPOUnchangedEBP) {
StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules,
&frame_symbolizer);
vector<const CodeModule*> modules_without_symbols;
- ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
+ vector<const CodeModule*> modules_with_corrupt_symbols;
+ ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols,
+ &modules_with_corrupt_symbols));
ASSERT_EQ(0U, modules_without_symbols.size());
+ ASSERT_EQ(0U, modules_with_corrupt_symbols.size());
frames = call_stack.frames();
ASSERT_EQ(2U, frames->size());
@@ -928,8 +969,11 @@ TEST_F(GetCallerFrame, WindowsFPOUsedEBP) {
StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules,
&frame_symbolizer);
vector<const CodeModule*> modules_without_symbols;
- ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
+ vector<const CodeModule*> modules_with_corrupt_symbols;
+ ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols,
+ &modules_with_corrupt_symbols));
ASSERT_EQ(0U, modules_without_symbols.size());
+ ASSERT_EQ(0U, modules_with_corrupt_symbols.size());
frames = call_stack.frames();
ASSERT_EQ(2U, frames->size());
@@ -1068,8 +1112,11 @@ TEST_F(GetCallerFrame, WindowsFPOSystemCall) {
StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules,
&frame_symbolizer);
vector<const CodeModule*> modules_without_symbols;
- ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
+ vector<const CodeModule*> modules_with_corrupt_symbols;
+ ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols,
+ &modules_with_corrupt_symbols));
ASSERT_EQ(0U, modules_without_symbols.size());
+ ASSERT_EQ(0U, modules_with_corrupt_symbols.size());
frames = call_stack.frames();
ASSERT_EQ(4U, frames->size());
@@ -1278,8 +1325,11 @@ TEST_F(GetCallerFrame, ReturnAddressIsNotInKnownModule) {
StackwalkerX86 walker(&system_info, &raw_context, &stack_region,
&local_modules, &frame_symbolizer);
vector<const CodeModule*> modules_without_symbols;
- ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
+ vector<const CodeModule*> modules_with_corrupt_symbols;
+ ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols,
+ &modules_with_corrupt_symbols));
ASSERT_EQ(0U, modules_without_symbols.size());
+ ASSERT_EQ(0U, modules_with_corrupt_symbols.size());
frames = call_stack.frames();
ASSERT_EQ(3U, frames->size());
@@ -1361,14 +1411,16 @@ TEST_F(GetCallerFrame, ReturnAddressIsNotInKnownModule) {
// this scan is limited to 120 search words for the context frame and 30
// search words (pointers) for the other frames:
// const int kRASearchWords = 30;
-TEST_F(GetCallerFrame, IPAddressIsNotInKnownModule) {
+void GetCallerFrame::IPAddressIsNotInKnownModuleTestImpl(
+ bool has_corrupt_symbols) {
MockCodeModule remoting_core_dll(0x54080000, 0x501000, "remoting_core.dll",
"version1");
- SetModuleSymbols(&remoting_core_dll, // remoting_core.dll
- "FUNC 137214 17d 10 PK11_Verify\n"
- "FUNC 15c834 37 14 nsc_ECDSAVerifyStub\n"
- "FUNC 1611d3 91 14 NSC_Verify\n"
- "FUNC 162ff7 60 4 sftk_SessionFromHandle\n"
+ string symbols_func_section =
+ "FUNC 137214 17d 10 PK11_Verify\n"
+ "FUNC 15c834 37 14 nsc_ECDSAVerifyStub\n"
+ "FUNC 1611d3 91 14 NSC_Verify\n"
+ "FUNC 162ff7 60 4 sftk_SessionFromHandle\n";
+ string symbols_stack_section =
"STACK WIN 4 137214 17d 9 0 10 0 10 0 1 $T0 $ebp = "
"$eip $T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + =\n"
"STACK WIN 4 15c834 37 6 0 14 0 18 0 1 $T0 $ebp = "
@@ -1376,7 +1428,21 @@ TEST_F(GetCallerFrame, IPAddressIsNotInKnownModule) {
"STACK WIN 4 1611d3 91 7 0 14 0 8 0 1 $T0 $ebp = "
"$eip $T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + =\n"
"STACK WIN 4 162ff7 60 5 0 4 0 0 0 1 $T0 $ebp = "
- "$eip $T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + =\n");
+ "$eip $T0 4 + ^ = $ebp $T0 ^ = $esp $T0 8 + =\n";
+
+ string symbols = symbols_func_section;
+ if (has_corrupt_symbols) {
+ symbols.append(string(1, '\0')); // null terminator in the middle
+ symbols.append("\n");
+ symbols.append("FUNC 1234\n" // invalid FUNC records
+ "FUNNC 1234\n"
+ "STACK WIN 4 1234 234 23 " // invalid STACK record
+ "23423423 234 23 234 234 "
+ "234 23 234 23 234 234 "
+ "234 234 234\n");
+ }
+ symbols.append(symbols_stack_section);
+ SetModuleSymbols(&remoting_core_dll, symbols);
// Create some modules with some stock debugging information.
MockCodeModules local_modules;
@@ -1505,8 +1571,17 @@ TEST_F(GetCallerFrame, IPAddressIsNotInKnownModule) {
StackwalkerX86 walker(&system_info, &raw_context, &stack_region,
&local_modules, &frame_symbolizer);
vector<const CodeModule*> modules_without_symbols;
- ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
+ vector<const CodeModule*> modules_with_corrupt_symbols;
+ ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols,
+ &modules_with_corrupt_symbols));
ASSERT_EQ(0U, modules_without_symbols.size());
+ if (has_corrupt_symbols) {
+ ASSERT_EQ(1U, modules_with_corrupt_symbols.size());
+ ASSERT_EQ("remoting_core.dll",
+ modules_with_corrupt_symbols[0]->debug_file());
+ } else {
+ ASSERT_EQ(0U, modules_with_corrupt_symbols.size());
+ }
frames = call_stack.frames();
ASSERT_EQ(4U, frames->size());
@@ -1584,6 +1659,16 @@ TEST_F(GetCallerFrame, IPAddressIsNotInKnownModule) {
}
}
+// Runs IPAddressIsNotInKnownModule test with good symbols
+TEST_F(GetCallerFrame, IPAddressIsNotInKnownModule) {
+ IPAddressIsNotInKnownModuleTestImpl(false /* has_corrupt_modules */);
+}
+
+// Runs IPAddressIsNotInKnownModule test with corrupt symbols
+TEST_F(GetCallerFrame, IPAddressIsNotInKnownModule_CorruptSymbols) {
+ IPAddressIsNotInKnownModuleTestImpl(true /* has_corrupt_modules */);
+}
+
struct CFIFixture: public StackwalkerX86Fixture {
CFIFixture() {
// Provide a bunch of STACK CFI records; individual tests walk to the
@@ -1635,8 +1720,11 @@ struct CFIFixture: public StackwalkerX86Fixture {
StackwalkerX86 walker(&system_info, &raw_context, &stack_region, &modules,
&frame_symbolizer);
vector<const CodeModule*> modules_without_symbols;
- ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols));
+ vector<const CodeModule*> modules_with_corrupt_symbols;
+ ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols,
+ &modules_with_corrupt_symbols));
ASSERT_EQ(0U, modules_without_symbols.size());
+ ASSERT_EQ(0U, modules_with_corrupt_symbols.size());
frames = call_stack.frames();
ASSERT_EQ(2U, frames->size());