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(¬_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(¬_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(); |
} |