Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1127)

Unified Diff: src/processor/stackwalker_amd64_unittest.cc

Issue 1902783002: Make x86-64 frame pointer unwinding stricter (Closed) Base URL: https://chromium.googlesource.com/breakpad/breakpad.git@master
Patch Set: Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/processor/stackwalker_amd64.cc ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/processor/stackwalker_amd64_unittest.cc
diff --git a/src/processor/stackwalker_amd64_unittest.cc b/src/processor/stackwalker_amd64_unittest.cc
index 23f38f70b4a0e2289d9eabc8ae0691efa6641ade..935bef866bcd3b5df715e4fc702de02457faad6c 100644
--- a/src/processor/stackwalker_amd64_unittest.cc
+++ b/src/processor/stackwalker_amd64_unittest.cc
@@ -72,8 +72,8 @@ class StackwalkerAMD64Fixture {
: stack_section(kLittleEndian),
// Give the two modules reasonable standard locations and names
// for tests to play with.
- module1(0x40000000c0000000ULL, 0x10000, "module1", "version1"),
- module2(0x50000000b0000000ULL, 0x10000, "module2", "version2") {
+ module1(0x00007400c0000000ULL, 0x10000, "module1", "version1"),
+ module2(0x00007500b0000000ULL, 0x10000, "module2", "version2") {
// Identify the system as a Linux system.
system_info.os = "Linux";
system_info.os_short = "linux";
@@ -149,7 +149,7 @@ TEST_F(SanityCheck, NoResolver) {
// provide any call frame information, so trying to reconstruct the
// context frame's caller should fail. So there's no need for us to
// provide stack contents.
- raw_context.rip = 0x40000000c0000200ULL;
+ raw_context.rip = 0x00007400c0000200ULL;
raw_context.rbp = 0x8000000080000000ULL;
StackFrameSymbolizer frame_symbolizer(NULL, NULL);
@@ -176,7 +176,7 @@ TEST_F(GetContextFrame, Simple) {
// provide any call frame information, so trying to reconstruct the
// context frame's caller should fail. So there's no need for us to
// provide stack contents.
- raw_context.rip = 0x40000000c0000200ULL;
+ raw_context.rip = 0x00007400c0000200ULL;
raw_context.rbp = 0x8000000080000000ULL;
StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
@@ -200,7 +200,7 @@ TEST_F(GetContextFrame, Simple) {
// The stackwalker should be able to produce the context frame even
// without stack memory present.
TEST_F(GetContextFrame, NoStackMemory) {
- raw_context.rip = 0x40000000c0000200ULL;
+ raw_context.rip = 0x00007400c0000200ULL;
raw_context.rbp = 0x8000000080000000ULL;
StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
@@ -230,23 +230,23 @@ TEST_F(GetCallerFrame, ScanWithoutSymbols) {
// Force scanning through three frames to ensure that the
// stack pointer is set properly in scan-recovered frames.
stack_section.start() = 0x8000000080000000ULL;
- uint64_t return_address1 = 0x50000000b0000100ULL;
- uint64_t return_address2 = 0x50000000b0000900ULL;
+ uint64_t return_address1 = 0x00007500b0000100ULL;
+ uint64_t return_address2 = 0x00007500b0000900ULL;
Label frame1_sp, frame2_sp, frame1_rbp;
stack_section
// frame 0
.Append(16, 0) // space
- .D64(0x40000000b0000000ULL) // junk that's not
- .D64(0x50000000d0000000ULL) // a return address
+ .D64(0x00007400b0000000ULL) // junk that's not
+ .D64(0x00007500d0000000ULL) // a return address
.D64(return_address1) // actual return address
// frame 1
.Mark(&frame1_sp)
.Append(16, 0) // space
- .D64(0x40000000b0000000ULL) // more junk
- .D64(0x50000000d0000000ULL)
+ .D64(0x00007400b0000000ULL) // more junk
+ .D64(0x00007500d0000000ULL)
.Mark(&frame1_rbp)
.D64(stack_section.start()) // This is in the right place to be
@@ -260,7 +260,7 @@ TEST_F(GetCallerFrame, ScanWithoutSymbols) {
RegionFromSection();
- raw_context.rip = 0x40000000c0000200ULL;
+ raw_context.rip = 0x00007400c0000200ULL;
raw_context.rbp = frame1_rbp.Value();
raw_context.rsp = stack_section.start().Value();
@@ -308,18 +308,18 @@ TEST_F(GetCallerFrame, ScanWithFunctionSymbols) {
// it is only considered a valid return address if it
// lies within a function's bounds.
stack_section.start() = 0x8000000080000000ULL;
- uint64_t return_address = 0x50000000b0000110ULL;
+ uint64_t return_address = 0x00007500b0000110ULL;
Label frame1_sp, frame1_rbp;
stack_section
// frame 0
.Append(16, 0) // space
- .D64(0x40000000b0000000ULL) // junk that's not
- .D64(0x50000000b0000000ULL) // a return address
+ .D64(0x00007400b0000000ULL) // junk that's not
+ .D64(0x00007500b0000000ULL) // a return address
- .D64(0x40000000c0001000ULL) // a couple of plausible addresses
- .D64(0x50000000b000aaaaULL) // that are not within functions
+ .D64(0x00007400c0001000ULL) // a couple of plausible addresses
+ .D64(0x00007500b000aaaaULL) // that are not within functions
.D64(return_address) // actual return address
// frame 1
@@ -328,7 +328,7 @@ TEST_F(GetCallerFrame, ScanWithFunctionSymbols) {
.Mark(&frame1_rbp);
RegionFromSection();
- raw_context.rip = 0x40000000c0000200ULL;
+ raw_context.rip = 0x00007400c0000200ULL;
raw_context.rbp = frame1_rbp.Value();
raw_context.rsp = stack_section.start().Value();
@@ -355,7 +355,7 @@ TEST_F(GetCallerFrame, ScanWithFunctionSymbols) {
EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
ASSERT_EQ(StackFrameAMD64::CONTEXT_VALID_ALL, frame0->context_validity);
EXPECT_EQ("platypus", frame0->function_name);
- EXPECT_EQ(0x40000000c0000100ULL, frame0->function_base);
+ EXPECT_EQ(0x00007400c0000100ULL, frame0->function_base);
StackFrameAMD64 *frame1 = static_cast<StackFrameAMD64 *>(frames->at(1));
EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust);
@@ -367,7 +367,7 @@ TEST_F(GetCallerFrame, ScanWithFunctionSymbols) {
EXPECT_EQ(frame1_sp.Value(), frame1->context.rsp);
EXPECT_EQ(frame1_rbp.Value(), frame1->context.rbp);
EXPECT_EQ("echidna", frame1->function_name);
- EXPECT_EQ(0x50000000b0000100ULL, frame1->function_base);
+ EXPECT_EQ(0x00007500b0000100ULL, frame1->function_base);
}
// StackwalkerAMD64::GetCallerByFramePointerRecovery should never return an
@@ -502,6 +502,107 @@ TEST_F(GetCallerFrame, GetCallerByFramePointerRecovery) {
}
}
+// Don't use frame pointer recovery if %rbp is not 8-byte aligned, which
+// indicates that it's not being used as a frame pointer.
+TEST_F(GetCallerFrame, FramePointerNotAligned) {
+ stack_section.start() = 0x8000000080000000ULL;
+ uint64_t return_address1 = 0x00007500b0000100ULL;
+ Label frame0_rbp, not_frame1_rbp, frame1_sp;
+ stack_section
+ // frame 0
+ .Align(8, 0)
+ .Append(2, 0) // mis-align the frame pointer
+ .Mark(&frame0_rbp)
+ .D64(not_frame1_rbp) // not the previous frame pointer
+ .D64(0x00007500b0000a00ULL) // plausible but wrong return address
+ .Align(8, 0)
+ .D64(return_address1) // return address
+ // frame 1
+ .Mark(&frame1_sp)
+ .Mark(&not_frame1_rbp)
+ .Append(32, 0); // end of stack
+
+
+ RegionFromSection();
+
+ raw_context.rip = 0x00007400c0000200ULL;
+ raw_context.rbp = frame0_rbp.Value();
+ raw_context.rsp = stack_section.start().Value();
+
+ StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
+ StackwalkerAMD64 walker(&system_info, &raw_context, &stack_region, &modules,
+ &frame_symbolizer);
+ vector<const CodeModule*> modules_without_symbols;
+ vector<const CodeModule*> modules_with_corrupt_symbols;
+ ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols,
+ &modules_with_corrupt_symbols));
+ frames = call_stack.frames();
+ ASSERT_EQ(2U, frames->size());
+
+ StackFrameAMD64 *frame0 = static_cast<StackFrameAMD64 *>(frames->at(0));
+ EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
+ ASSERT_EQ(StackFrameAMD64::CONTEXT_VALID_ALL, frame0->context_validity);
+ EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context)));
+
+ StackFrameAMD64 *frame1 = static_cast<StackFrameAMD64 *>(frames->at(1));
+ EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust);
+ ASSERT_EQ((StackFrameAMD64::CONTEXT_VALID_RIP |
+ StackFrameAMD64::CONTEXT_VALID_RSP),
+ frame1->context_validity);
+ EXPECT_EQ(return_address1, frame1->context.rip);
+ EXPECT_EQ(frame1_sp.Value(), frame1->context.rsp);
+}
+
+// Don't use frame pointer recovery if the recovered %rip is not
+// a canonical x86-64 address.
+TEST_F(GetCallerFrame, NonCanonicalInstructionPointerFromFramePointer) {
+ stack_section.start() = 0x8000000080000000ULL;
+ uint64_t return_address1 = 0x00007500b0000100ULL;
+ Label frame0_rbp, frame1_sp, not_frame1_bp;
+ stack_section
+ // frame 0
+ .Align(8, 0)
+ .Mark(&frame0_rbp)
+ .D64(not_frame1_bp) // some junk on the stack
+ .D64(0xDADADADADADADADA) // not the return address
+ .D64(return_address1) // return address
+ // frame 1
+ .Mark(&frame1_sp)
+ .Append(16, 0)
+ .Mark(&not_frame1_bp)
+ .Append(32, 0); // end of stack
+
+
+ RegionFromSection();
+
+ raw_context.rip = 0x00007400c0000200ULL;
+ raw_context.rbp = frame0_rbp.Value();
+ raw_context.rsp = stack_section.start().Value();
+
+ StackFrameSymbolizer frame_symbolizer(&supplier, &resolver);
+ StackwalkerAMD64 walker(&system_info, &raw_context, &stack_region, &modules,
+ &frame_symbolizer);
+ vector<const CodeModule*> modules_without_symbols;
+ vector<const CodeModule*> modules_with_corrupt_symbols;
+ ASSERT_TRUE(walker.Walk(&call_stack, &modules_without_symbols,
+ &modules_with_corrupt_symbols));
+ frames = call_stack.frames();
+ ASSERT_EQ(2U, frames->size());
+
+ StackFrameAMD64 *frame0 = static_cast<StackFrameAMD64 *>(frames->at(0));
+ EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
+ ASSERT_EQ(StackFrameAMD64::CONTEXT_VALID_ALL, frame0->context_validity);
+ EXPECT_EQ(0, memcmp(&raw_context, &frame0->context, sizeof(raw_context)));
+
+ StackFrameAMD64 *frame1 = static_cast<StackFrameAMD64 *>(frames->at(1));
+ EXPECT_EQ(StackFrame::FRAME_TRUST_SCAN, frame1->trust);
+ ASSERT_EQ((StackFrameAMD64::CONTEXT_VALID_RIP |
+ StackFrameAMD64::CONTEXT_VALID_RSP),
+ frame1->context_validity);
+ EXPECT_EQ(return_address1, frame1->context.rip);
+ EXPECT_EQ(frame1_sp.Value(), frame1->context.rsp);
+}
+
// Test that set_max_frames_scanned prevents using stack scanning
// to find caller frames.
TEST_F(GetCallerFrame, ScanningNotAllowed) {
@@ -509,23 +610,23 @@ TEST_F(GetCallerFrame, ScanningNotAllowed) {
// only addresses located within loaded modules are
// considered valid return addresses.
stack_section.start() = 0x8000000080000000ULL;
- uint64_t return_address1 = 0x50000000b0000100ULL;
- uint64_t return_address2 = 0x50000000b0000900ULL;
+ uint64_t return_address1 = 0x00007500b0000100ULL;
+ uint64_t return_address2 = 0x00007500b0000900ULL;
Label frame1_sp, frame2_sp, frame1_rbp;
stack_section
// frame 0
.Append(16, 0) // space
- .D64(0x40000000b0000000ULL) // junk that's not
- .D64(0x50000000d0000000ULL) // a return address
+ .D64(0x00007400b0000000ULL) // junk that's not
+ .D64(0x00007500d0000000ULL) // a return address
.D64(return_address1) // actual return address
// frame 1
.Mark(&frame1_sp)
.Append(16, 0) // space
- .D64(0x40000000b0000000ULL) // more junk
- .D64(0x50000000d0000000ULL)
+ .D64(0x00007400b0000000ULL) // more junk
+ .D64(0x00007500d0000000ULL)
.Mark(&frame1_rbp)
.D64(stack_section.start()) // This is in the right place to be
@@ -539,7 +640,7 @@ TEST_F(GetCallerFrame, ScanningNotAllowed) {
RegionFromSection();
- raw_context.rip = 0x40000000c0000200ULL;
+ raw_context.rip = 0x00007400c0000200ULL;
raw_context.rbp = frame1_rbp.Value();
raw_context.rsp = stack_section.start().Value();
@@ -570,18 +671,18 @@ TEST_F(GetCallerFrame, CallerPushedRBP) {
// %rbp directly below the return address, assume that it is indeed the
// next frame's %rbp.
stack_section.start() = 0x8000000080000000ULL;
- uint64_t return_address = 0x50000000b0000110ULL;
+ uint64_t return_address = 0x00007500b0000110ULL;
Label frame0_rbp, frame1_sp, frame1_rbp;
stack_section
// frame 0
.Append(16, 0) // space
- .D64(0x40000000b0000000ULL) // junk that's not
- .D64(0x50000000b0000000ULL) // a return address
+ .D64(0x00007400b0000000ULL) // junk that's not
+ .D64(0x00007500b0000000ULL) // a return address
- .D64(0x40000000c0001000ULL) // a couple of plausible addresses
- .D64(0x50000000b000aaaaULL) // that are not within functions
+ .D64(0x00007400c0001000ULL) // a couple of plausible addresses
+ .D64(0x00007500b000aaaaULL) // that are not within functions
.Mark(&frame0_rbp)
.D64(frame1_rbp) // caller-pushed %rbp
@@ -592,7 +693,7 @@ TEST_F(GetCallerFrame, CallerPushedRBP) {
.Mark(&frame1_rbp); // end of stack
RegionFromSection();
- raw_context.rip = 0x40000000c0000200ULL;
+ raw_context.rip = 0x00007400c0000200ULL;
raw_context.rbp = frame0_rbp.Value();
raw_context.rsp = stack_section.start().Value();
@@ -620,7 +721,7 @@ TEST_F(GetCallerFrame, CallerPushedRBP) {
ASSERT_EQ(StackFrameAMD64::CONTEXT_VALID_ALL, frame0->context_validity);
EXPECT_EQ(frame0_rbp.Value(), frame0->context.rbp);
EXPECT_EQ("sasquatch", frame0->function_name);
- EXPECT_EQ(0x40000000c0000100ULL, frame0->function_base);
+ EXPECT_EQ(0x00007400c0000100ULL, frame0->function_base);
StackFrameAMD64 *frame1 = static_cast<StackFrameAMD64 *>(frames->at(1));
EXPECT_EQ(StackFrame::FRAME_TRUST_FP, frame1->trust);
@@ -632,7 +733,7 @@ TEST_F(GetCallerFrame, CallerPushedRBP) {
EXPECT_EQ(frame1_sp.Value(), frame1->context.rsp);
EXPECT_EQ(frame1_rbp.Value(), frame1->context.rbp);
EXPECT_EQ("yeti", frame1->function_name);
- EXPECT_EQ(0x50000000b0000100ULL, frame1->function_base);
+ EXPECT_EQ(0x00007500b0000100ULL, frame1->function_base);
}
struct CFIFixture: public StackwalkerAMD64Fixture {
@@ -663,7 +764,7 @@ struct CFIFixture: public StackwalkerAMD64Fixture {
// Provide some distinctive values for the caller's registers.
expected.rsp = 0x8000000080000000ULL;
- expected.rip = 0x40000000c0005510ULL;
+ expected.rip = 0x00007400c0005510ULL;
expected.rbp = 0x68995b1de4700266ULL;
expected.rbx = 0x5a5beeb38de23be8ULL;
expected.r12 = 0xed1b02e8cc0fc79cULL;
@@ -700,7 +801,7 @@ struct CFIFixture: public StackwalkerAMD64Fixture {
EXPECT_EQ(StackFrame::FRAME_TRUST_CONTEXT, frame0->trust);
ASSERT_EQ(StackFrameAMD64::CONTEXT_VALID_ALL, frame0->context_validity);
EXPECT_EQ("enchiridion", frame0->function_name);
- EXPECT_EQ(0x40000000c0004000ULL, frame0->function_base);
+ EXPECT_EQ(0x00007400c0004000ULL, frame0->function_base);
StackFrameAMD64 *frame1 = static_cast<StackFrameAMD64 *>(frames->at(1));
EXPECT_EQ(StackFrame::FRAME_TRUST_CFI, frame1->trust);
@@ -733,9 +834,9 @@ class CFI: public CFIFixture, public Test { };
TEST_F(CFI, At4000) {
Label frame1_rsp = expected.rsp;
stack_section
- .D64(0x40000000c0005510ULL) // return address
+ .D64(0x00007400c0005510ULL) // return address
.Mark(&frame1_rsp); // This effectively sets stack_section.start().
- raw_context.rip = 0x40000000c0004000ULL;
+ raw_context.rip = 0x00007400c0004000ULL;
CheckWalk();
}
@@ -743,9 +844,9 @@ TEST_F(CFI, At4001) {
Label frame1_rsp = expected.rsp;
stack_section
.D64(0x5a5beeb38de23be8ULL) // saved %rbx
- .D64(0x40000000c0005510ULL) // return address
+ .D64(0x00007400c0005510ULL) // return address
.Mark(&frame1_rsp); // This effectively sets stack_section.start().
- raw_context.rip = 0x40000000c0004001ULL;
+ raw_context.rip = 0x00007400c0004001ULL;
raw_context.rbx = 0xbe0487d2f9eafe29ULL; // callee's (distinct) %rbx value
CheckWalk();
}
@@ -754,9 +855,9 @@ TEST_F(CFI, At4002) {
Label frame1_rsp = expected.rsp;
stack_section
.D64(0x5a5beeb38de23be8ULL) // saved %rbx
- .D64(0x40000000c0005510ULL) // return address
+ .D64(0x00007400c0005510ULL) // return address
.Mark(&frame1_rsp); // This effectively sets stack_section.start().
- raw_context.rip = 0x40000000c0004002ULL;
+ raw_context.rip = 0x00007400c0004002ULL;
raw_context.rbx = 0xed1b02e8cc0fc79cULL; // saved %r12
raw_context.r12 = 0xb0118de918a4bceaULL; // callee's (distinct) %r12 value
CheckWalk();
@@ -769,9 +870,9 @@ TEST_F(CFI, At4003) {
.D64(0x1d20ad8acacbe930ULL) // saved %r13
.D64(0x319e68b49e3ace0fULL) // garbage
.D64(0x5a5beeb38de23be8ULL) // saved %rbx
- .D64(0x40000000c0005510ULL) // return address
+ .D64(0x00007400c0005510ULL) // return address
.Mark(&frame1_rsp); // This effectively sets stack_section.start().
- raw_context.rip = 0x40000000c0004003ULL;
+ raw_context.rip = 0x00007400c0004003ULL;
raw_context.rbx = 0xed1b02e8cc0fc79cULL; // saved %r12
raw_context.r12 = 0x89d04fa804c87a43ULL; // callee's (distinct) %r12
raw_context.r13 = 0x5118e02cbdb24b03ULL; // callee's (distinct) %r13
@@ -786,9 +887,9 @@ TEST_F(CFI, At4004) {
.D64(0x1d20ad8acacbe930ULL) // saved %r13
.D64(0x319e68b49e3ace0fULL) // garbage
.D64(0x5a5beeb38de23be8ULL) // saved %rbx
- .D64(0x40000000c0005510ULL) // return address
+ .D64(0x00007400c0005510ULL) // return address
.Mark(&frame1_rsp); // This effectively sets stack_section.start().
- raw_context.rip = 0x40000000c0004004ULL;
+ raw_context.rip = 0x00007400c0004004ULL;
raw_context.rbx = 0xed1b02e8cc0fc79cULL; // saved %r12
raw_context.r12 = 0x89d04fa804c87a43ULL; // callee's (distinct) %r12
raw_context.r13 = 0x5118e02cbdb24b03ULL; // callee's (distinct) %r13
@@ -804,10 +905,10 @@ TEST_F(CFI, At4005) {
.D64(0x5a5beeb38de23be8ULL) // saved %rbx
.D64(0xaa95fa054aedfbaeULL) // garbage
.Mark(&frame1_rsp); // This effectively sets stack_section.start().
- raw_context.rip = 0x40000000c0004005ULL;
+ raw_context.rip = 0x00007400c0004005ULL;
raw_context.rbx = 0xed1b02e8cc0fc79cULL; // saved %r12
raw_context.r12 = 0x46b1b8868891b34aULL; // callee's %r12
- raw_context.r13 = 0x40000000c0005510ULL; // return address
+ raw_context.r13 = 0x00007400c0005510ULL; // return address
CheckWalk();
}
@@ -822,10 +923,10 @@ TEST_F(CFI, At4006) {
.D64(0x5a5beeb38de23be8ULL) // saved %rbx
.D64(0xf015ee516ad89eabULL) // garbage
.Mark(&frame1_rsp); // This effectively sets stack_section.start().
- raw_context.rip = 0x40000000c0004006ULL;
+ raw_context.rip = 0x00007400c0004006ULL;
raw_context.rbp = frame0_rbp.Value();
raw_context.rbx = 0xed1b02e8cc0fc79cULL; // saved %r12
raw_context.r12 = 0x26e007b341acfebdULL; // callee's %r12
- raw_context.r13 = 0x40000000c0005510ULL; // return address
+ raw_context.r13 = 0x00007400c0005510ULL; // return address
CheckWalk();
}
« no previous file with comments | « src/processor/stackwalker_amd64.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698