aboutsummaryrefslogtreecommitdiff
path: root/src/processor
diff options
context:
space:
mode:
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());