Populating is_multiple in google_breakpad::StackFrame from symbol files.
This is needed in order to properly detect and highlight frames that correspond to multiple functions, for example as the result of identical code folding by the linker. Bug: google-breakpad:751 Change-Id: I2ee7c147fcff6493c2454383ad5422b38269759a Reviewed-on: https://chromium-review.googlesource.com/c/breakpad/breakpad/+/3471034 Reviewed-by: Joshua Peraza <jperaza@chromium.org>
This commit is contained in:
parent
34af6bcff1
commit
fc1b9d3203
6 changed files with 35 additions and 12 deletions
|
@ -63,7 +63,8 @@ struct StackFrame {
|
||||||
source_file_name(),
|
source_file_name(),
|
||||||
source_line(0),
|
source_line(0),
|
||||||
source_line_base(),
|
source_line_base(),
|
||||||
trust(FRAME_TRUST_NONE){}
|
trust(FRAME_TRUST_NONE),
|
||||||
|
is_multiple(false) {}
|
||||||
virtual ~StackFrame() {}
|
virtual ~StackFrame() {}
|
||||||
|
|
||||||
// Return a string describing how this stack frame was found
|
// Return a string describing how this stack frame was found
|
||||||
|
@ -140,6 +141,12 @@ struct StackFrame {
|
||||||
// Amount of trust the stack walker has in the instruction pointer
|
// Amount of trust the stack walker has in the instruction pointer
|
||||||
// of this frame.
|
// of this frame.
|
||||||
FrameTrust trust;
|
FrameTrust trust;
|
||||||
|
|
||||||
|
// True if the frame corresponds to multiple functions, for example as the
|
||||||
|
// result of identical code folding by the linker. In that case the function
|
||||||
|
// name, filename, etc. information above represents the state of an arbitrary
|
||||||
|
// one of these functions.
|
||||||
|
bool is_multiple;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace google_breakpad
|
} // namespace google_breakpad
|
||||||
|
|
|
@ -319,6 +319,7 @@ void BasicSourceLineResolver::Module::LookupAddress(
|
||||||
address >= function_base && address - function_base < function_size) {
|
address >= function_base && address - function_base < function_size) {
|
||||||
frame->function_name = func->name;
|
frame->function_name = func->name;
|
||||||
frame->function_base = frame->module->base_address() + function_base;
|
frame->function_base = frame->module->base_address() + function_base;
|
||||||
|
frame->is_multiple = func->is_multiple;
|
||||||
|
|
||||||
linked_ptr<Line> line;
|
linked_ptr<Line> line;
|
||||||
MemAddr line_base;
|
MemAddr line_base;
|
||||||
|
@ -341,6 +342,7 @@ void BasicSourceLineResolver::Module::LookupAddress(
|
||||||
(!func.get() || public_address > function_base)) {
|
(!func.get() || public_address > function_base)) {
|
||||||
frame->function_name = public_symbol->name;
|
frame->function_name = public_symbol->name;
|
||||||
frame->function_base = frame->module->base_address() + public_address;
|
frame->function_base = frame->module->base_address() + public_address;
|
||||||
|
frame->is_multiple = public_symbol->is_multiple;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,7 +52,6 @@ using google_breakpad::CodeModule;
|
||||||
using google_breakpad::MemoryRegion;
|
using google_breakpad::MemoryRegion;
|
||||||
using google_breakpad::StackFrame;
|
using google_breakpad::StackFrame;
|
||||||
using google_breakpad::WindowsFrameInfo;
|
using google_breakpad::WindowsFrameInfo;
|
||||||
using google_breakpad::linked_ptr;
|
|
||||||
using google_breakpad::scoped_ptr;
|
using google_breakpad::scoped_ptr;
|
||||||
using google_breakpad::SymbolParseHelper;
|
using google_breakpad::SymbolParseHelper;
|
||||||
|
|
||||||
|
@ -93,12 +92,12 @@ class MockMemoryRegion: public MemoryRegion {
|
||||||
}
|
}
|
||||||
bool GetMemoryAtAddress(uint64_t address, uint32_t* value) const {
|
bool GetMemoryAtAddress(uint64_t address, uint32_t* value) const {
|
||||||
switch (address) {
|
switch (address) {
|
||||||
case 0x10008: *value = 0x98ecadc3; break; // saved %ebx
|
case 0x10008: *value = 0x98ecadc3; break; // saved %ebx
|
||||||
case 0x1000c: *value = 0x878f7524; break; // saved %esi
|
case 0x1000c: *value = 0x878f7524; break; // saved %esi
|
||||||
case 0x10010: *value = 0x6312f9a5; break; // saved %edi
|
case 0x10010: *value = 0x6312f9a5; break; // saved %edi
|
||||||
case 0x10014: *value = 0x10038; break; // caller's %ebp
|
case 0x10014: *value = 0x10038; break; // caller's %ebp
|
||||||
case 0x10018: *value = 0xf6438648; break; // return address
|
case 0x10018: *value = 0xf6438648; break; // return address
|
||||||
default: *value = 0xdeadbeef; break; // junk
|
default: *value = 0xdeadbeef; break; // junk
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -164,7 +163,7 @@ static void ClearSourceLineInfo(StackFrame* frame) {
|
||||||
}
|
}
|
||||||
|
|
||||||
class TestBasicSourceLineResolver : public ::testing::Test {
|
class TestBasicSourceLineResolver : public ::testing::Test {
|
||||||
public:
|
public:
|
||||||
void SetUp() {
|
void SetUp() {
|
||||||
testdata_dir = string(getenv("srcdir") ? getenv("srcdir") : ".") +
|
testdata_dir = string(getenv("srcdir") ? getenv("srcdir") : ".") +
|
||||||
"/src/processor/testdata";
|
"/src/processor/testdata";
|
||||||
|
@ -196,6 +195,7 @@ TEST_F(TestBasicSourceLineResolver, TestLoadAndResolve)
|
||||||
ASSERT_TRUE(frame.source_file_name.empty());
|
ASSERT_TRUE(frame.source_file_name.empty());
|
||||||
ASSERT_EQ(frame.source_line, 0);
|
ASSERT_EQ(frame.source_line, 0);
|
||||||
ASSERT_EQ(frame.source_line_base, 0U);
|
ASSERT_EQ(frame.source_line_base, 0U);
|
||||||
|
EXPECT_EQ(frame.is_multiple, false);
|
||||||
|
|
||||||
frame.module = &module1;
|
frame.module = &module1;
|
||||||
resolver.FillSourceLineInfo(&frame, nullptr);
|
resolver.FillSourceLineInfo(&frame, nullptr);
|
||||||
|
@ -206,6 +206,7 @@ TEST_F(TestBasicSourceLineResolver, TestLoadAndResolve)
|
||||||
ASSERT_EQ(frame.source_file_name, "file1_1.cc");
|
ASSERT_EQ(frame.source_file_name, "file1_1.cc");
|
||||||
ASSERT_EQ(frame.source_line, 44);
|
ASSERT_EQ(frame.source_line, 44);
|
||||||
ASSERT_EQ(frame.source_line_base, 0x1000U);
|
ASSERT_EQ(frame.source_line_base, 0x1000U);
|
||||||
|
EXPECT_EQ(frame.is_multiple, true);
|
||||||
windows_frame_info.reset(resolver.FindWindowsFrameInfo(&frame));
|
windows_frame_info.reset(resolver.FindWindowsFrameInfo(&frame));
|
||||||
ASSERT_TRUE(windows_frame_info.get());
|
ASSERT_TRUE(windows_frame_info.get());
|
||||||
ASSERT_EQ(windows_frame_info->type_, WindowsFrameInfo::STACK_INFO_FRAME_DATA);
|
ASSERT_EQ(windows_frame_info->type_, WindowsFrameInfo::STACK_INFO_FRAME_DATA);
|
||||||
|
@ -344,6 +345,7 @@ TEST_F(TestBasicSourceLineResolver, TestLoadAndResolve)
|
||||||
frame.module = &module1;
|
frame.module = &module1;
|
||||||
resolver.FillSourceLineInfo(&frame, nullptr);
|
resolver.FillSourceLineInfo(&frame, nullptr);
|
||||||
ASSERT_EQ(frame.function_name, string("PublicSymbol"));
|
ASSERT_EQ(frame.function_name, string("PublicSymbol"));
|
||||||
|
EXPECT_EQ(frame.is_multiple, true);
|
||||||
|
|
||||||
frame.instruction = 0x4000;
|
frame.instruction = 0x4000;
|
||||||
frame.module = &module1;
|
frame.module = &module1;
|
||||||
|
@ -360,6 +362,7 @@ TEST_F(TestBasicSourceLineResolver, TestLoadAndResolve)
|
||||||
ASSERT_EQ(frame.source_file_name, "file2_2.cc");
|
ASSERT_EQ(frame.source_file_name, "file2_2.cc");
|
||||||
ASSERT_EQ(frame.source_line, 21);
|
ASSERT_EQ(frame.source_line, 21);
|
||||||
ASSERT_EQ(frame.source_line_base, 0x2180U);
|
ASSERT_EQ(frame.source_line_base, 0x2180U);
|
||||||
|
EXPECT_EQ(frame.is_multiple, false);
|
||||||
windows_frame_info.reset(resolver.FindWindowsFrameInfo(&frame));
|
windows_frame_info.reset(resolver.FindWindowsFrameInfo(&frame));
|
||||||
ASSERT_TRUE(windows_frame_info.get());
|
ASSERT_TRUE(windows_frame_info.get());
|
||||||
ASSERT_EQ(windows_frame_info->type_, WindowsFrameInfo::STACK_INFO_FRAME_DATA);
|
ASSERT_EQ(windows_frame_info->type_, WindowsFrameInfo::STACK_INFO_FRAME_DATA);
|
||||||
|
@ -368,6 +371,7 @@ TEST_F(TestBasicSourceLineResolver, TestLoadAndResolve)
|
||||||
frame.instruction = 0x216f;
|
frame.instruction = 0x216f;
|
||||||
resolver.FillSourceLineInfo(&frame, nullptr);
|
resolver.FillSourceLineInfo(&frame, nullptr);
|
||||||
ASSERT_EQ(frame.function_name, "Public2_1");
|
ASSERT_EQ(frame.function_name, "Public2_1");
|
||||||
|
EXPECT_EQ(frame.is_multiple, false);
|
||||||
|
|
||||||
ClearSourceLineInfo(&frame);
|
ClearSourceLineInfo(&frame);
|
||||||
frame.instruction = 0x219f;
|
frame.instruction = 0x219f;
|
||||||
|
@ -431,6 +435,7 @@ TEST_F(TestBasicSourceLineResolver, TestLoadAndResolveOldInlines) {
|
||||||
ASSERT_EQ(frame.source_file_name, "linux_inline.cpp");
|
ASSERT_EQ(frame.source_file_name, "linux_inline.cpp");
|
||||||
ASSERT_EQ(frame.source_line, 42);
|
ASSERT_EQ(frame.source_line, 42);
|
||||||
ASSERT_EQ(frame.source_line_base, 0x161b6U);
|
ASSERT_EQ(frame.source_line_base, 0x161b6U);
|
||||||
|
EXPECT_EQ(frame.is_multiple, false);
|
||||||
|
|
||||||
ASSERT_EQ(inlined_frames.size(), 3UL);
|
ASSERT_EQ(inlined_frames.size(), 3UL);
|
||||||
|
|
||||||
|
@ -475,6 +480,7 @@ TEST_F(TestBasicSourceLineResolver, TestLoadAndResolveNewInlines) {
|
||||||
ASSERT_EQ(frame.source_file_name, "a.cpp");
|
ASSERT_EQ(frame.source_file_name, "a.cpp");
|
||||||
ASSERT_EQ(frame.source_line, 42);
|
ASSERT_EQ(frame.source_line, 42);
|
||||||
ASSERT_EQ(frame.source_line_base, 0x161b6U);
|
ASSERT_EQ(frame.source_line_base, 0x161b6U);
|
||||||
|
EXPECT_EQ(frame.is_multiple, false);
|
||||||
|
|
||||||
ASSERT_EQ(inlined_frames.size(), 3UL);
|
ASSERT_EQ(inlined_frames.size(), 3UL);
|
||||||
|
|
||||||
|
|
|
@ -88,6 +88,7 @@ void FastSourceLineResolver::Module::LookupAddress(
|
||||||
func->CopyFrom(func_ptr);
|
func->CopyFrom(func_ptr);
|
||||||
frame->function_name = func->name;
|
frame->function_name = func->name;
|
||||||
frame->function_base = frame->module->base_address() + function_base;
|
frame->function_base = frame->module->base_address() + function_base;
|
||||||
|
frame->is_multiple = func->is_multiple;
|
||||||
|
|
||||||
scoped_ptr<Line> line(new Line);
|
scoped_ptr<Line> line(new Line);
|
||||||
const Line* line_ptr = 0;
|
const Line* line_ptr = 0;
|
||||||
|
@ -112,6 +113,7 @@ void FastSourceLineResolver::Module::LookupAddress(
|
||||||
public_symbol->CopyFrom(public_symbol_ptr);
|
public_symbol->CopyFrom(public_symbol_ptr);
|
||||||
frame->function_name = public_symbol->name;
|
frame->function_name = public_symbol->name;
|
||||||
frame->function_base = frame->module->base_address() + public_address;
|
frame->function_base = frame->module->base_address() + public_address;
|
||||||
|
frame->is_multiple = public_symbol->is_multiple;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -64,7 +64,6 @@ using google_breakpad::CodeModule;
|
||||||
using google_breakpad::MemoryRegion;
|
using google_breakpad::MemoryRegion;
|
||||||
using google_breakpad::StackFrame;
|
using google_breakpad::StackFrame;
|
||||||
using google_breakpad::WindowsFrameInfo;
|
using google_breakpad::WindowsFrameInfo;
|
||||||
using google_breakpad::linked_ptr;
|
|
||||||
using google_breakpad::scoped_ptr;
|
using google_breakpad::scoped_ptr;
|
||||||
|
|
||||||
class TestCodeModule : public CodeModule {
|
class TestCodeModule : public CodeModule {
|
||||||
|
@ -224,6 +223,7 @@ TEST_F(TestFastSourceLineResolver, TestLoadAndResolve) {
|
||||||
ASSERT_TRUE(frame.source_file_name.empty());
|
ASSERT_TRUE(frame.source_file_name.empty());
|
||||||
ASSERT_EQ(frame.source_line, 0);
|
ASSERT_EQ(frame.source_line, 0);
|
||||||
ASSERT_EQ(frame.source_line_base, 0U);
|
ASSERT_EQ(frame.source_line_base, 0U);
|
||||||
|
ASSERT_EQ(frame.is_multiple, false);
|
||||||
|
|
||||||
frame.module = &module1;
|
frame.module = &module1;
|
||||||
fast_resolver.FillSourceLineInfo(&frame, nullptr);
|
fast_resolver.FillSourceLineInfo(&frame, nullptr);
|
||||||
|
@ -234,6 +234,7 @@ TEST_F(TestFastSourceLineResolver, TestLoadAndResolve) {
|
||||||
ASSERT_EQ(frame.source_file_name, "file1_1.cc");
|
ASSERT_EQ(frame.source_file_name, "file1_1.cc");
|
||||||
ASSERT_EQ(frame.source_line, 44);
|
ASSERT_EQ(frame.source_line, 44);
|
||||||
ASSERT_EQ(frame.source_line_base, 0x1000U);
|
ASSERT_EQ(frame.source_line_base, 0x1000U);
|
||||||
|
ASSERT_EQ(frame.is_multiple, true);
|
||||||
windows_frame_info.reset(fast_resolver.FindWindowsFrameInfo(&frame));
|
windows_frame_info.reset(fast_resolver.FindWindowsFrameInfo(&frame));
|
||||||
ASSERT_TRUE(windows_frame_info.get());
|
ASSERT_TRUE(windows_frame_info.get());
|
||||||
ASSERT_FALSE(windows_frame_info->allocates_base_pointer);
|
ASSERT_FALSE(windows_frame_info->allocates_base_pointer);
|
||||||
|
@ -371,6 +372,7 @@ TEST_F(TestFastSourceLineResolver, TestLoadAndResolve) {
|
||||||
frame.module = &module1;
|
frame.module = &module1;
|
||||||
fast_resolver.FillSourceLineInfo(&frame, nullptr);
|
fast_resolver.FillSourceLineInfo(&frame, nullptr);
|
||||||
ASSERT_EQ(frame.function_name, string("PublicSymbol"));
|
ASSERT_EQ(frame.function_name, string("PublicSymbol"));
|
||||||
|
EXPECT_EQ(frame.is_multiple, true);
|
||||||
|
|
||||||
frame.instruction = 0x4000;
|
frame.instruction = 0x4000;
|
||||||
frame.module = &module1;
|
frame.module = &module1;
|
||||||
|
@ -387,6 +389,7 @@ TEST_F(TestFastSourceLineResolver, TestLoadAndResolve) {
|
||||||
ASSERT_EQ(frame.source_file_name, "file2_2.cc");
|
ASSERT_EQ(frame.source_file_name, "file2_2.cc");
|
||||||
ASSERT_EQ(frame.source_line, 21);
|
ASSERT_EQ(frame.source_line, 21);
|
||||||
ASSERT_EQ(frame.source_line_base, 0x2180U);
|
ASSERT_EQ(frame.source_line_base, 0x2180U);
|
||||||
|
ASSERT_EQ(frame.is_multiple, false);
|
||||||
windows_frame_info.reset(fast_resolver.FindWindowsFrameInfo(&frame));
|
windows_frame_info.reset(fast_resolver.FindWindowsFrameInfo(&frame));
|
||||||
ASSERT_TRUE(windows_frame_info.get());
|
ASSERT_TRUE(windows_frame_info.get());
|
||||||
ASSERT_EQ(windows_frame_info->type_, WindowsFrameInfo::STACK_INFO_FRAME_DATA);
|
ASSERT_EQ(windows_frame_info->type_, WindowsFrameInfo::STACK_INFO_FRAME_DATA);
|
||||||
|
@ -395,6 +398,7 @@ TEST_F(TestFastSourceLineResolver, TestLoadAndResolve) {
|
||||||
frame.instruction = 0x216f;
|
frame.instruction = 0x216f;
|
||||||
fast_resolver.FillSourceLineInfo(&frame, nullptr);
|
fast_resolver.FillSourceLineInfo(&frame, nullptr);
|
||||||
ASSERT_EQ(frame.function_name, "Public2_1");
|
ASSERT_EQ(frame.function_name, "Public2_1");
|
||||||
|
EXPECT_EQ(frame.is_multiple, false);
|
||||||
|
|
||||||
ClearSourceLineInfo(&frame);
|
ClearSourceLineInfo(&frame);
|
||||||
frame.instruction = 0x219f;
|
frame.instruction = 0x219f;
|
||||||
|
@ -433,6 +437,7 @@ TEST_F(TestFastSourceLineResolver, TestLoadAndResolveOldInlines) {
|
||||||
ASSERT_EQ(frame.source_file_name, "linux_inline.cpp");
|
ASSERT_EQ(frame.source_file_name, "linux_inline.cpp");
|
||||||
ASSERT_EQ(frame.source_line, 42);
|
ASSERT_EQ(frame.source_line, 42);
|
||||||
ASSERT_EQ(frame.source_line_base, 0x161b6U);
|
ASSERT_EQ(frame.source_line_base, 0x161b6U);
|
||||||
|
ASSERT_EQ(frame.is_multiple, false);
|
||||||
|
|
||||||
ASSERT_EQ(inlined_frames.size(), 3UL);
|
ASSERT_EQ(inlined_frames.size(), 3UL);
|
||||||
|
|
||||||
|
@ -484,6 +489,7 @@ TEST_F(TestFastSourceLineResolver, TestLoadAndResolveNewInlines) {
|
||||||
ASSERT_EQ(frame.source_file_name, "a.cpp");
|
ASSERT_EQ(frame.source_file_name, "a.cpp");
|
||||||
ASSERT_EQ(frame.source_line, 42);
|
ASSERT_EQ(frame.source_line, 42);
|
||||||
ASSERT_EQ(frame.source_line_base, 0x161b6U);
|
ASSERT_EQ(frame.source_line_base, 0x161b6U);
|
||||||
|
ASSERT_EQ(frame.is_multiple, false);
|
||||||
|
|
||||||
ASSERT_EQ(inlined_frames.size(), 3UL);
|
ASSERT_EQ(inlined_frames.size(), 3UL);
|
||||||
|
|
||||||
|
|
4
src/processor/testdata/module1.out
vendored
4
src/processor/testdata/module1.out
vendored
|
@ -3,7 +3,7 @@ INFO CODE_ID FFFFFFFF module1.exe
|
||||||
FILE 1 file1_1.cc
|
FILE 1 file1_1.cc
|
||||||
FILE 2 file1_2.cc
|
FILE 2 file1_2.cc
|
||||||
FILE 3 file1_3.cc
|
FILE 3 file1_3.cc
|
||||||
FUNC 1000 c 0 Function1_1
|
FUNC m 1000 c 0 Function1_1
|
||||||
1000 4 44 1
|
1000 4 44 1
|
||||||
1004 4 45 1
|
1004 4 45 1
|
||||||
1008 4 46 1
|
1008 4 46 1
|
||||||
|
@ -14,7 +14,7 @@ FUNC 1200 100 8 Function1_3
|
||||||
FUNC 1300 100 c Function1_4
|
FUNC 1300 100 c Function1_4
|
||||||
FUNC 2000 0 0 Test_Zero_Size_Function_Is_Ignored
|
FUNC 2000 0 0 Test_Zero_Size_Function_Is_Ignored
|
||||||
2000 4 88 2
|
2000 4 88 2
|
||||||
PUBLIC 2800 0 PublicSymbol
|
PUBLIC m 2800 0 PublicSymbol
|
||||||
FUNC 3000 7000 42 LargeFunction
|
FUNC 3000 7000 42 LargeFunction
|
||||||
3000 7000 4098359 3
|
3000 7000 4098359 3
|
||||||
STACK WIN 4 1000 c 1 0 0 0 0 0 1 $eip 4 + ^ = $esp $ebp 8 + = $ebp $ebp ^ =
|
STACK WIN 4 1000 c 1 0 0 0 0 0 1 $eip 4 + ^ = $esp $ebp 8 + = $ebp $ebp ^ =
|
||||||
|
|
Loading…
Reference in a new issue