[unwinder] Clean up existing tests

Mostly a cleanup for x64.

Also enable two tests for Arm and Arm64 since they do not make use of
JSEntry frames.

Bug: v8:10833
Change-Id: Id6adadf582bdca0076460842ffe4ec856ca99393
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2381455
Commit-Queue: Santiago Aboy Solanes <solanes@chromium.org>
Reviewed-by: Ross McIlroy <rmcilroy@chromium.org>
Reviewed-by: Peter Marshall <petermarshall@chromium.org>
Cr-Commit-Position: refs/heads/master@{#69634}
This commit is contained in:
Santiago Aboy Solanes 2020-09-01 09:39:21 +01:00 committed by Commit Bot
parent 0ab923b8c0
commit 5d471ee6df
2 changed files with 68 additions and 44 deletions

View File

@ -473,8 +473,6 @@
# Arm. They are disabled because the stack is not being set up the way it does
# in the wild.
['arch == arm64 or arch == arm', {
'test-unwinder-code-pages/Unwind_BuiltinPCInMiddle_Success_CodePagesAPI': [SKIP],
'test-unwinder-code-pages/Unwind_BuiltinPCAtStart_Success_CodePagesAPI': [SKIP],
'test-unwinder-code-pages/Unwind_CodeObjectPCInMiddle_Success_CodePagesAPI': [SKIP],
'test-unwinder-code-pages/Unwind_JSEntryBeforeFrame_Fail_CodePagesAPI': [SKIP],
'test-unwinder-code-pages/Unwind_OneJSFrame_Success_CodePagesAPI': [SKIP],

View File

@ -17,6 +17,9 @@ namespace test_unwinder_code_pages {
static const void* fake_stack_base = nullptr;
#define CHECK_EQ_STACK_REGISTER(stack_value, register_value) \
CHECK_EQ(reinterpret_cast<void*>(stack_value), register_value)
TEST(Unwind_BadState_Fail_CodePagesAPI) {
JSEntryStubs entry_stubs; // Fields are intialized to nullptr.
RegisterState register_state;
@ -32,6 +35,7 @@ TEST(Unwind_BadState_Fail_CodePagesAPI) {
CHECK_NULL(register_state.pc);
}
// Unwind a middle JS frame (i.e not the JSEntry one).
TEST(Unwind_BuiltinPCInMiddle_Success_CodePagesAPI) {
LocalContext env;
v8::Isolate* isolate = env->GetIsolate();
@ -44,11 +48,16 @@ TEST(Unwind_BuiltinPCInMiddle_Success_CodePagesAPI) {
CHECK_LE(pages_length, arraysize(code_pages));
RegisterState register_state;
// {stack} here mocks the stack, where the top of the stack (i.e the lowest
// addresses) are represented by lower indices.
uintptr_t stack[3];
void* stack_base = stack + arraysize(stack);
stack[0] = reinterpret_cast<uintptr_t>(stack + 2); // saved FP (rbp).
// Index on the stack for the topmost fp (i.e the one right before the C++
// frame).
const int topmost_fp_index = 0;
stack[0] = reinterpret_cast<uintptr_t>(stack + 2); // saved FP.
stack[1] = 202; // Return address into C++ code.
stack[2] = 303; // The SP points here in the caller's frame.
stack[2] = reinterpret_cast<uintptr_t>(stack + 2); // saved SP.
register_state.sp = stack;
register_state.fp = stack;
@ -63,9 +72,9 @@ TEST(Unwind_BuiltinPCInMiddle_Success_CodePagesAPI) {
bool unwound = v8::Unwinder::TryUnwindV8Frames(
entry_stubs, pages_length, code_pages, &register_state, stack_base);
CHECK(unwound);
CHECK_EQ(reinterpret_cast<void*>(stack + 2), register_state.fp);
CHECK_EQ(reinterpret_cast<void*>(stack + 2), register_state.sp);
CHECK_EQ(reinterpret_cast<void*>(202), register_state.pc);
CHECK_EQ_STACK_REGISTER(stack[topmost_fp_index], register_state.fp);
CHECK_EQ_STACK_REGISTER(stack[topmost_fp_index + 1], register_state.pc);
CHECK_EQ_STACK_REGISTER(stack[topmost_fp_index + 2], register_state.sp);
}
// The unwinder should be able to unwind even if we haven't properly set up the
@ -98,9 +107,12 @@ TEST(Unwind_BuiltinPCAtStart_Success_CodePagesAPI) {
// Return address into JS code. It doesn't matter that this is not actually in
// JSEntry, because we only check that for the top frame.
stack[1] = reinterpret_cast<uintptr_t>(code + 10);
stack[2] = reinterpret_cast<uintptr_t>(stack + 5); // saved FP (rbp).
// Index on the stack for the topmost fp (i.e the one right before the C++
// frame).
const int topmost_fp_index = 2;
stack[2] = reinterpret_cast<uintptr_t>(stack + 5); // saved FP.
stack[3] = 303; // Return address into C++ code.
stack[4] = 404;
stack[4] = reinterpret_cast<uintptr_t>(stack + 4);
stack[5] = 505;
register_state.sp = stack;
@ -115,9 +127,9 @@ TEST(Unwind_BuiltinPCAtStart_Success_CodePagesAPI) {
entry_stubs, pages_length, code_pages, &register_state, stack_base);
CHECK(unwound);
CHECK_EQ(reinterpret_cast<void*>(stack + 5), register_state.fp);
CHECK_EQ(reinterpret_cast<void*>(stack + 4), register_state.sp);
CHECK_EQ(reinterpret_cast<void*>(303), register_state.pc);
CHECK_EQ_STACK_REGISTER(stack[topmost_fp_index], register_state.fp);
CHECK_EQ_STACK_REGISTER(stack[topmost_fp_index + 1], register_state.pc);
CHECK_EQ_STACK_REGISTER(stack[topmost_fp_index + 2], register_state.sp);
}
const char* foo_source = R"(
@ -160,9 +172,12 @@ TEST(Unwind_CodeObjectPCInMiddle_Success_CodePagesAPI) {
uintptr_t stack[3];
void* stack_base = stack + arraysize(stack);
stack[0] = reinterpret_cast<uintptr_t>(stack + 2); // saved FP (rbp).
// Index on the stack for the topmost fp (i.e the one right before the C++
// frame).
const int topmost_fp_index = 0;
stack[0] = reinterpret_cast<uintptr_t>(stack + 2); // saved FP.
stack[1] = 202; // Return address into C++ code.
stack[2] = 303; // The SP points here in the caller's frame.
stack[2] = reinterpret_cast<uintptr_t>(stack + 2); // saved SP.
register_state.sp = stack;
register_state.fp = stack;
@ -200,9 +215,9 @@ TEST(Unwind_CodeObjectPCInMiddle_Success_CodePagesAPI) {
bool unwound = v8::Unwinder::TryUnwindV8Frames(
entry_stubs, pages_length, code_pages, &register_state, stack_base);
CHECK(unwound);
CHECK_EQ(reinterpret_cast<void*>(stack + 2), register_state.fp);
CHECK_EQ(reinterpret_cast<void*>(stack + 2), register_state.sp);
CHECK_EQ(reinterpret_cast<void*>(202), register_state.pc);
CHECK_EQ_STACK_REGISTER(stack[topmost_fp_index], register_state.fp);
CHECK_EQ_STACK_REGISTER(stack[topmost_fp_index + 1], register_state.pc);
CHECK_EQ_STACK_REGISTER(stack[topmost_fp_index + 2], register_state.sp);
}
// If the PC is within JSEntry but we haven't set up the frame yet, then we
@ -232,36 +247,39 @@ TEST(Unwind_JSEntryBeforeFrame_Fail_CodePagesAPI) {
stack[2] = 121;
stack[3] = 131;
stack[4] = 141;
stack[5] = 151;
stack[5] = 151; // Here's where the saved fp would be. We are not going to be
// unwinding so we do not need to set it up correctly.
stack[6] = 100; // Return address into C++ code.
stack[7] = 303; // The SP points here in the caller's frame.
stack[7] = 303; // Here's where the saved SP would be.
stack[8] = 404;
stack[9] = 505;
register_state.sp = stack + 5;
register_state.fp = stack + 9;
register_state.sp = &stack[5];
register_state.fp = &stack[9];
// Put the current PC inside of JSEntry, before the frame is set up.
register_state.pc = code + 12;
uintptr_t* jsentry_pc_value = code + 12;
register_state.pc = jsentry_pc_value;
bool unwound = v8::Unwinder::TryUnwindV8Frames(
entry_stubs, pages_length, code_pages, &register_state, stack_base);
CHECK(!unwound);
// The register state should not change when unwinding fails.
CHECK_EQ(reinterpret_cast<void*>(stack + 9), register_state.fp);
CHECK_EQ(reinterpret_cast<void*>(stack + 5), register_state.sp);
CHECK_EQ(code + 12, register_state.pc);
CHECK_EQ_STACK_REGISTER(&stack[9], register_state.fp);
CHECK_EQ_STACK_REGISTER(&stack[5], register_state.sp);
CHECK_EQ(jsentry_pc_value, register_state.pc);
// Change the PC to a few instructions later, after the frame is set up.
register_state.pc = code + 16;
jsentry_pc_value = code + 16;
register_state.pc = jsentry_pc_value;
unwound = v8::Unwinder::TryUnwindV8Frames(
entry_stubs, pages_length, code_pages, &register_state, stack_base);
// TODO(petermarshall): More precisely check position within JSEntry rather
// than just assuming the frame is unreadable.
CHECK(!unwound);
// The register state should not change when unwinding fails.
CHECK_EQ(reinterpret_cast<void*>(stack + 9), register_state.fp);
CHECK_EQ(reinterpret_cast<void*>(stack + 5), register_state.sp);
CHECK_EQ(code + 16, register_state.pc);
CHECK_EQ_STACK_REGISTER(&stack[9], register_state.fp);
CHECK_EQ_STACK_REGISTER(&stack[5], register_state.sp);
CHECK_EQ(jsentry_pc_value, register_state.pc);
}
TEST(Unwind_OneJSFrame_Success_CodePagesAPI) {
@ -288,9 +306,12 @@ TEST(Unwind_OneJSFrame_Success_CodePagesAPI) {
stack[2] = 121;
stack[3] = 131;
stack[4] = 141;
stack[5] = reinterpret_cast<uintptr_t>(stack + 9); // saved FP (rbp).
// Index on the stack for the topmost fp (i.e the one right before the C++
// frame).
const int topmost_fp_index = 5;
stack[5] = reinterpret_cast<uintptr_t>(stack + 9); // saved FP.
stack[6] = 100; // Return address into C++ code.
stack[7] = 303; // The SP points here in the caller's frame.
stack[7] = reinterpret_cast<uintptr_t>(stack + 7); // saved SP.
stack[8] = 404;
stack[9] = 505;
@ -304,9 +325,9 @@ TEST(Unwind_OneJSFrame_Success_CodePagesAPI) {
entry_stubs, pages_length, code_pages, &register_state, stack_base);
CHECK(unwound);
CHECK_EQ(reinterpret_cast<void*>(stack + 9), register_state.fp);
CHECK_EQ(reinterpret_cast<void*>(stack + 7), register_state.sp);
CHECK_EQ(reinterpret_cast<void*>(100), register_state.pc);
CHECK_EQ_STACK_REGISTER(stack[topmost_fp_index], register_state.fp);
CHECK_EQ_STACK_REGISTER(stack[topmost_fp_index + 1], register_state.pc);
CHECK_EQ_STACK_REGISTER(stack[topmost_fp_index + 2], register_state.sp);
}
// Creates a fake stack with two JS frames on top of a C++ frame and checks that
@ -333,13 +354,16 @@ TEST(Unwind_TwoJSFrames_Success_CodePagesAPI) {
void* stack_base = stack + arraysize(stack);
stack[0] = 101;
stack[1] = 111;
stack[2] = reinterpret_cast<uintptr_t>(stack + 5); // saved FP (rbp).
stack[2] = reinterpret_cast<uintptr_t>(stack + 5); // saved FP.
// The fake return address is in the JS code range.
stack[3] = reinterpret_cast<uintptr_t>(code + 10);
stack[4] = 141;
stack[5] = reinterpret_cast<uintptr_t>(stack + 9); // saved FP (rbp).
// Index on the stack for the topmost fp (i.e the one right before the C++
// frame).
const int topmost_fp_index = 5;
stack[5] = reinterpret_cast<uintptr_t>(stack + 9); // saved FP.
stack[6] = 100; // Return address into C++ code.
stack[7] = 303; // The SP points here in the caller's frame.
stack[7] = reinterpret_cast<uintptr_t>(stack + 7); // saved SP.
stack[8] = 404;
stack[9] = 505;
@ -353,9 +377,9 @@ TEST(Unwind_TwoJSFrames_Success_CodePagesAPI) {
entry_stubs, pages_length, code_pages, &register_state, stack_base);
CHECK(unwound);
CHECK_EQ(reinterpret_cast<void*>(stack + 9), register_state.fp);
CHECK_EQ(reinterpret_cast<void*>(stack + 7), register_state.sp);
CHECK_EQ(reinterpret_cast<void*>(100), register_state.pc);
CHECK_EQ_STACK_REGISTER(stack[topmost_fp_index], register_state.fp);
CHECK_EQ_STACK_REGISTER(stack[topmost_fp_index + 1], register_state.pc);
CHECK_EQ_STACK_REGISTER(stack[topmost_fp_index + 2], register_state.sp);
}
// If the PC is in JSEntry then the frame might not be set up correctly, meaning
@ -400,9 +424,9 @@ TEST(Unwind_StackBounds_Basic_CodePagesAPI) {
code_pages[0].length_in_bytes = code_length * sizeof(uintptr_t);
uintptr_t stack[3];
stack[0] = reinterpret_cast<uintptr_t>(stack + 2); // saved FP (rbp).
stack[0] = reinterpret_cast<uintptr_t>(stack + 2); // saved FP.
stack[1] = 202; // Return address into C++ code.
stack[2] = 303; // The SP points here in the caller's frame.
stack[2] = 303; // saved SP.
register_state.sp = stack;
register_state.fp = stack;
@ -446,9 +470,9 @@ TEST(Unwind_StackBounds_WithUnwinding_CodePagesAPI) {
stack[2] = 121;
stack[3] = 131;
stack[4] = 141;
stack[5] = reinterpret_cast<uintptr_t>(stack + 9); // saved FP (rbp).
stack[5] = reinterpret_cast<uintptr_t>(stack + 9); // saved FP.
stack[6] = reinterpret_cast<uintptr_t>(code + 20); // JS code.
stack[7] = 303; // The SP points here in the caller's frame.
stack[7] = 303; // saved SP.
stack[8] = 404;
stack[9] = reinterpret_cast<uintptr_t>(stack) +
(12 * sizeof(uintptr_t)); // saved FP (OOB).
@ -665,6 +689,8 @@ TEST(Unwind_TwoNestedFunctions_CodePagesAPI) {
UnwinderTestHelper helper(test_script);
}
#endif
#undef CHECK_EQ_STACK_REGISTER
} // namespace test_unwinder_code_pages
} // namespace internal
} // namespace v8