[unwinder] Restore callee saved registers after unwinding in arm32
Bug: v8:10799 Change-Id: Id912520b6a27e439e204bac47c0723a8f613be4b Fixed: v8:10799 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2472000 Commit-Queue: Santiago Aboy Solanes <solanes@chromium.org> Reviewed-by: Ulan Degenbaev <ulan@chromium.org> Reviewed-by: Ross McIlroy <rmcilroy@chromium.org> Cr-Commit-Position: refs/heads/master@{#70656}
This commit is contained in:
parent
fbfa9bf4ec
commit
d6c586f756
6
BUILD.gn
6
BUILD.gn
@ -2290,6 +2290,7 @@ v8_source_set("v8_base_without_compiler") {
|
||||
"include/v8-metrics.h",
|
||||
"include/v8-platform.h",
|
||||
"include/v8-profiler.h",
|
||||
"include/v8-unwinder-state.h",
|
||||
"include/v8-util.h",
|
||||
"include/v8-wasm-trap-handler-posix.h",
|
||||
"include/v8.h",
|
||||
@ -2496,6 +2497,7 @@ v8_source_set("v8_base_without_compiler") {
|
||||
"src/diagnostics/perf-jit.cc",
|
||||
"src/diagnostics/perf-jit.h",
|
||||
"src/diagnostics/unwinder.cc",
|
||||
"src/diagnostics/unwinder.h",
|
||||
"src/execution/arguments-inl.h",
|
||||
"src/execution/arguments.cc",
|
||||
"src/execution/arguments.h",
|
||||
@ -3473,6 +3475,7 @@ v8_source_set("v8_base_without_compiler") {
|
||||
"src/debug/ia32/debug-ia32.cc",
|
||||
"src/deoptimizer/ia32/deoptimizer-ia32.cc",
|
||||
"src/diagnostics/ia32/disasm-ia32.cc",
|
||||
"src/diagnostics/ia32/unwinder-ia32.cc",
|
||||
"src/execution/ia32/frame-constants-ia32.cc",
|
||||
"src/execution/ia32/frame-constants-ia32.h",
|
||||
"src/regexp/ia32/regexp-macro-assembler-ia32.cc",
|
||||
@ -3502,6 +3505,7 @@ v8_source_set("v8_base_without_compiler") {
|
||||
"src/deoptimizer/x64/deoptimizer-x64.cc",
|
||||
"src/diagnostics/x64/disasm-x64.cc",
|
||||
"src/diagnostics/x64/eh-frame-x64.cc",
|
||||
"src/diagnostics/x64/unwinder-x64.cc",
|
||||
"src/execution/x64/frame-constants-x64.cc",
|
||||
"src/execution/x64/frame-constants-x64.h",
|
||||
"src/regexp/x64/regexp-macro-assembler-x64.cc",
|
||||
@ -3550,6 +3554,7 @@ v8_source_set("v8_base_without_compiler") {
|
||||
"src/deoptimizer/arm/deoptimizer-arm.cc",
|
||||
"src/diagnostics/arm/disasm-arm.cc",
|
||||
"src/diagnostics/arm/eh-frame-arm.cc",
|
||||
"src/diagnostics/arm/unwinder-arm.cc",
|
||||
"src/execution/arm/frame-constants-arm.cc",
|
||||
"src/execution/arm/frame-constants-arm.h",
|
||||
"src/execution/arm/simulator-arm.cc",
|
||||
@ -3590,6 +3595,7 @@ v8_source_set("v8_base_without_compiler") {
|
||||
"src/diagnostics/arm64/disasm-arm64.cc",
|
||||
"src/diagnostics/arm64/disasm-arm64.h",
|
||||
"src/diagnostics/arm64/eh-frame-arm64.cc",
|
||||
"src/diagnostics/arm64/unwinder-arm64.cc",
|
||||
"src/execution/arm64/frame-constants-arm64.cc",
|
||||
"src/execution/arm64/frame-constants-arm64.h",
|
||||
"src/execution/arm64/pointer-auth-arm64.cc",
|
||||
|
30
include/v8-unwinder-state.h
Normal file
30
include/v8-unwinder-state.h
Normal file
@ -0,0 +1,30 @@
|
||||
// Copyright 2020 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef INCLUDE_V8_UNWINDER_STATE_H_
|
||||
#define INCLUDE_V8_UNWINDER_STATE_H_
|
||||
|
||||
namespace v8 {
|
||||
|
||||
#ifdef V8_TARGET_ARCH_ARM
|
||||
struct CalleeSavedRegisters {
|
||||
void* arm_r4;
|
||||
void* arm_r5;
|
||||
void* arm_r6;
|
||||
void* arm_r7;
|
||||
void* arm_r8;
|
||||
void* arm_r9;
|
||||
void* arm_r10;
|
||||
};
|
||||
#elif V8_TARGET_ARCH_X64 || V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_ARM64 || \
|
||||
V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_PPC || \
|
||||
V8_TARGET_ARCH_PPC64 || V8_TARGET_ARCH_S390
|
||||
struct CalleeSavedRegisters {};
|
||||
#else
|
||||
#error Target architecture was not detected as supported by v8
|
||||
#endif
|
||||
|
||||
} // namespace v8
|
||||
|
||||
#endif // INCLUDE_V8_UNWINDER _STATE_H_
|
15
include/v8.h
15
include/v8.h
@ -2272,14 +2272,25 @@ enum StateTag {
|
||||
IDLE
|
||||
};
|
||||
|
||||
// Holds the callee saved registers needed for the stack unwinder. It is the
|
||||
// empty struct if no registers are required. Implemented in
|
||||
// include/v8-unwinder-state.h.
|
||||
struct CalleeSavedRegisters;
|
||||
|
||||
// A RegisterState represents the current state of registers used
|
||||
// by the sampling profiler API.
|
||||
struct RegisterState {
|
||||
RegisterState() : pc(nullptr), sp(nullptr), fp(nullptr), lr(nullptr) {}
|
||||
struct V8_EXPORT RegisterState {
|
||||
RegisterState();
|
||||
~RegisterState();
|
||||
RegisterState(const RegisterState& other);
|
||||
RegisterState& operator=(const RegisterState& other);
|
||||
|
||||
void* pc; // Instruction pointer.
|
||||
void* sp; // Stack pointer.
|
||||
void* fp; // Frame pointer.
|
||||
void* lr; // Link register (or nullptr on platforms without a link register).
|
||||
// Callee saved registers (or null if no callee saved registers were stored)
|
||||
std::unique_ptr<CalleeSavedRegisters> callee_saved;
|
||||
};
|
||||
|
||||
// The output structure filled up by GetStackSample API function.
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "include/v8-cppgc.h"
|
||||
#include "include/v8-fast-api-calls.h"
|
||||
#include "include/v8-profiler.h"
|
||||
#include "include/v8-unwinder-state.h"
|
||||
#include "include/v8-util.h"
|
||||
#include "src/api/api-inl.h"
|
||||
#include "src/api/api-natives.h"
|
||||
@ -11148,6 +11149,36 @@ CFunction::CFunction(const void* address, const CFunctionInfo* type_info)
|
||||
}
|
||||
}
|
||||
|
||||
RegisterState::RegisterState()
|
||||
: pc(nullptr), sp(nullptr), fp(nullptr), lr(nullptr) {}
|
||||
RegisterState::~RegisterState() = default;
|
||||
|
||||
RegisterState::RegisterState(const RegisterState& other) V8_NOEXCEPT {
|
||||
pc = other.pc;
|
||||
sp = other.sp;
|
||||
fp = other.fp;
|
||||
lr = other.lr;
|
||||
if (other.callee_saved) {
|
||||
callee_saved =
|
||||
std::make_unique<CalleeSavedRegisters>(*(other.callee_saved));
|
||||
}
|
||||
}
|
||||
|
||||
RegisterState& RegisterState::operator=(const RegisterState& other)
|
||||
V8_NOEXCEPT {
|
||||
if (&other != this) {
|
||||
pc = other.pc;
|
||||
sp = other.sp;
|
||||
fp = other.fp;
|
||||
lr = other.lr;
|
||||
if (other.callee_saved) {
|
||||
callee_saved =
|
||||
std::make_unique<CalleeSavedRegisters>(*(other.callee_saved));
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
namespace internal {
|
||||
|
||||
const size_t HandleScopeImplementer::kEnteredContextsOffset =
|
||||
|
37
src/diagnostics/arm/unwinder-arm.cc
Normal file
37
src/diagnostics/arm/unwinder-arm.cc
Normal file
@ -0,0 +1,37 @@
|
||||
// Copyright 2020 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "include/v8-unwinder-state.h"
|
||||
#include "src/diagnostics/unwinder.h"
|
||||
#include "src/execution/frame-constants.h"
|
||||
|
||||
namespace v8 {
|
||||
|
||||
void GetCalleeSavedRegistersFromEntryFrame(void* fp,
|
||||
RegisterState* register_state) {
|
||||
const i::Address base_addr =
|
||||
reinterpret_cast<i::Address>(fp) +
|
||||
i::EntryFrameConstants::kDirectCallerRRegistersOffset;
|
||||
|
||||
if (!register_state->callee_saved) {
|
||||
register_state->callee_saved = std::make_unique<CalleeSavedRegisters>();
|
||||
}
|
||||
|
||||
register_state->callee_saved->arm_r4 =
|
||||
reinterpret_cast<void*>(Load(base_addr + 0 * i::kSystemPointerSize));
|
||||
register_state->callee_saved->arm_r5 =
|
||||
reinterpret_cast<void*>(Load(base_addr + 1 * i::kSystemPointerSize));
|
||||
register_state->callee_saved->arm_r6 =
|
||||
reinterpret_cast<void*>(Load(base_addr + 2 * i::kSystemPointerSize));
|
||||
register_state->callee_saved->arm_r7 =
|
||||
reinterpret_cast<void*>(Load(base_addr + 3 * i::kSystemPointerSize));
|
||||
register_state->callee_saved->arm_r8 =
|
||||
reinterpret_cast<void*>(Load(base_addr + 4 * i::kSystemPointerSize));
|
||||
register_state->callee_saved->arm_r9 =
|
||||
reinterpret_cast<void*>(Load(base_addr + 5 * i::kSystemPointerSize));
|
||||
register_state->callee_saved->arm_r10 =
|
||||
reinterpret_cast<void*>(Load(base_addr + 6 * i::kSystemPointerSize));
|
||||
}
|
||||
|
||||
} // namespace v8
|
12
src/diagnostics/arm64/unwinder-arm64.cc
Normal file
12
src/diagnostics/arm64/unwinder-arm64.cc
Normal file
@ -0,0 +1,12 @@
|
||||
// Copyright 2020 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "src/diagnostics/unwinder.h"
|
||||
|
||||
namespace v8 {
|
||||
|
||||
void GetCalleeSavedRegistersFromEntryFrame(void* fp,
|
||||
RegisterState* register_state) {}
|
||||
|
||||
} // namespace v8
|
12
src/diagnostics/ia32/unwinder-ia32.cc
Normal file
12
src/diagnostics/ia32/unwinder-ia32.cc
Normal file
@ -0,0 +1,12 @@
|
||||
// Copyright 2020 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "src/diagnostics/unwinder.h"
|
||||
|
||||
namespace v8 {
|
||||
|
||||
void GetCalleeSavedRegistersFromEntryFrame(void* fp,
|
||||
RegisterState* register_state) {}
|
||||
|
||||
} // namespace v8
|
@ -2,15 +2,22 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "src/diagnostics/unwinder.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "include/v8.h"
|
||||
#include "src/common/globals.h"
|
||||
#include "src/execution/frame-constants.h"
|
||||
#include "src/execution/pointer-authentication.h"
|
||||
|
||||
namespace v8 {
|
||||
|
||||
// Architecture specific. Implemented in unwinder-<arch>.cc.
|
||||
void GetCalleeSavedRegistersFromEntryFrame(void* fp,
|
||||
RegisterState* register_state);
|
||||
|
||||
i::Address Load(i::Address address) {
|
||||
return *reinterpret_cast<i::Address*>(address);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
const i::byte* CalculateEnd(const void* start, size_t length_in_bytes) {
|
||||
@ -61,13 +68,15 @@ bool IsInUnsafeJSEntryRange(const JSEntryStubs& entry_stubs, void* pc) {
|
||||
// within JSEntry.
|
||||
}
|
||||
|
||||
i::Address Load(i::Address address) {
|
||||
return *reinterpret_cast<i::Address*>(address);
|
||||
bool AddressIsInStack(const void* address, const void* stack_base,
|
||||
const void* stack_top) {
|
||||
return address <= stack_base && address >= stack_top;
|
||||
}
|
||||
|
||||
void* GetReturnAddressFromFP(void* fp, void* pc,
|
||||
const JSEntryStubs& entry_stubs) {
|
||||
int caller_pc_offset = i::CommonFrameConstants::kCallerPCOffset;
|
||||
// TODO(solanes): Implement the JSEntry range case also for x64 here and below.
|
||||
#if V8_TARGET_ARCH_ARM64 || V8_TARGET_ARCH_ARM
|
||||
if (IsInJSEntryRange(entry_stubs, pc)) {
|
||||
caller_pc_offset = i::EntryFrameConstants::kDirectCallerPCOffset;
|
||||
@ -100,11 +109,6 @@ void* GetCallerSPFromFP(void* fp, void* pc, const JSEntryStubs& entry_stubs) {
|
||||
caller_sp_offset);
|
||||
}
|
||||
|
||||
bool AddressIsInStack(const void* address, const void* stack_base,
|
||||
const void* stack_top) {
|
||||
return address <= stack_base && address >= stack_top;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool Unwinder::TryUnwindV8Frames(const JSEntryStubs& entry_stubs,
|
||||
@ -145,6 +149,10 @@ bool Unwinder::TryUnwindV8Frames(const JSEntryStubs& entry_stubs,
|
||||
|
||||
// Link register no longer valid after unwinding.
|
||||
register_state->lr = nullptr;
|
||||
|
||||
if (IsInJSEntryRange(entry_stubs, pc)) {
|
||||
GetCalleeSavedRegistersFromEntryFrame(current_fp, register_state);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
17
src/diagnostics/unwinder.h
Normal file
17
src/diagnostics/unwinder.h
Normal file
@ -0,0 +1,17 @@
|
||||
// Copyright 2020 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef V8_DIAGNOSTICS_UNWINDER_H_
|
||||
#define V8_DIAGNOSTICS_UNWINDER_H_
|
||||
|
||||
#include "include/v8.h"
|
||||
#include "src/common/globals.h"
|
||||
|
||||
namespace v8 {
|
||||
|
||||
i::Address Load(i::Address address);
|
||||
|
||||
} // namespace v8
|
||||
|
||||
#endif // V8_DIAGNOSTICS_UNWINDER_H_
|
12
src/diagnostics/x64/unwinder-x64.cc
Normal file
12
src/diagnostics/x64/unwinder-x64.cc
Normal file
@ -0,0 +1,12 @@
|
||||
// Copyright 2020 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "src/diagnostics/unwinder.h"
|
||||
|
||||
namespace v8 {
|
||||
|
||||
void GetCalleeSavedRegistersFromEntryFrame(void* fp,
|
||||
RegisterState* register_state) {}
|
||||
|
||||
} // namespace v8
|
@ -43,12 +43,14 @@ class EntryFrameConstants : public AllStatic {
|
||||
static constexpr int kArgvOffset = +1 * kSystemPointerSize;
|
||||
|
||||
// These offsets refer to the immediate caller (i.e a native frame).
|
||||
static constexpr int kDirectCallerFPOffset =
|
||||
static constexpr int kDirectCallerRRegistersOffset =
|
||||
/* bad frame pointer (-1) */
|
||||
kPointerSize +
|
||||
/* d8...d15 */
|
||||
kNumDoubleCalleeSaved * kDoubleSize +
|
||||
/* r4...r10 (i.e callee saved without fp) */
|
||||
kNumDoubleCalleeSaved * kDoubleSize;
|
||||
static constexpr int kDirectCallerFPOffset =
|
||||
kDirectCallerRRegistersOffset +
|
||||
/* r4...r10 (i.e. callee saved without fp) */
|
||||
(kNumCalleeSaved - 1) * kPointerSize;
|
||||
static constexpr int kDirectCallerPCOffset =
|
||||
kDirectCallerFPOffset + 1 * kSystemPointerSize;
|
||||
|
@ -2,8 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "include/v8-unwinder-state.h"
|
||||
#include "include/v8.h"
|
||||
|
||||
#include "src/api/api-inl.h"
|
||||
#include "src/builtins/builtins.h"
|
||||
#include "src/execution/isolate.h"
|
||||
@ -17,6 +17,9 @@ namespace test_unwinder_code_pages {
|
||||
|
||||
namespace {
|
||||
|
||||
#define CHECK_EQ_VALUE_REGISTER(uiuntptr_value, register_value) \
|
||||
CHECK_EQ(reinterpret_cast<void*>(uiuntptr_value), register_value)
|
||||
|
||||
#ifdef V8_TARGET_ARCH_X64
|
||||
// How much the JSEntry frame occupies in the stack.
|
||||
constexpr int kJSEntryFrameSpace = 3;
|
||||
@ -33,6 +36,10 @@ void BuildJSEntryStack(uintptr_t* stack) {
|
||||
stack[1] = 100; // Return address into C++ code.
|
||||
stack[2] = reinterpret_cast<uintptr_t>(stack + 2); // saved SP.
|
||||
}
|
||||
|
||||
// Dummy method since we don't save callee saved registers in x64.
|
||||
void CheckCalleeSavedRegisters(const RegisterState& register_state) {}
|
||||
|
||||
#elif V8_TARGET_ARCH_ARM
|
||||
// How much the JSEntry frame occupies in the stack.
|
||||
constexpr int kJSEntryFrameSpace = 27;
|
||||
@ -59,6 +66,19 @@ void BuildJSEntryStack(uintptr_t* stack) {
|
||||
stack[25] = 100; // Return address into C++ code (i.e lr/pc)
|
||||
stack[26] = reinterpret_cast<uintptr_t>(stack + 26); // saved SP.
|
||||
}
|
||||
|
||||
// Checks that the values in the calee saved registers are the same as the ones
|
||||
// we saved in BuildJSEntryStack.
|
||||
void CheckCalleeSavedRegisters(const RegisterState& register_state) {
|
||||
CHECK_EQ_VALUE_REGISTER(160, register_state.callee_saved->arm_r4);
|
||||
CHECK_EQ_VALUE_REGISTER(161, register_state.callee_saved->arm_r5);
|
||||
CHECK_EQ_VALUE_REGISTER(162, register_state.callee_saved->arm_r6);
|
||||
CHECK_EQ_VALUE_REGISTER(163, register_state.callee_saved->arm_r7);
|
||||
CHECK_EQ_VALUE_REGISTER(164, register_state.callee_saved->arm_r8);
|
||||
CHECK_EQ_VALUE_REGISTER(165, register_state.callee_saved->arm_r9);
|
||||
CHECK_EQ_VALUE_REGISTER(166, register_state.callee_saved->arm_r10);
|
||||
}
|
||||
|
||||
#elif V8_TARGET_ARCH_ARM64
|
||||
// How much the JSEntry frame occupies in the stack.
|
||||
constexpr int kJSEntryFrameSpace = 22;
|
||||
@ -83,6 +103,10 @@ void BuildJSEntryStack(uintptr_t* stack) {
|
||||
}
|
||||
stack[21] = reinterpret_cast<uintptr_t>(stack + 21); // saved SP.
|
||||
}
|
||||
|
||||
// Dummy method since we don't save callee saved registers in arm64.
|
||||
void CheckCalleeSavedRegisters(const RegisterState& register_state) {}
|
||||
|
||||
#else
|
||||
// Dummy constants for the rest of the archs which are not supported.
|
||||
constexpr int kJSEntryFrameSpace = 1;
|
||||
@ -90,17 +114,17 @@ constexpr int kFPOffset = 0;
|
||||
constexpr int kPCOffset = 0;
|
||||
constexpr int kSPOffset = 0;
|
||||
|
||||
// Dummy function to be able to compile.
|
||||
// Dummy methods to be able to compile.
|
||||
void BuildJSEntryStack(uintptr_t* stack) { UNREACHABLE(); }
|
||||
void CheckCalleeSavedRegisters(const RegisterState& register_state) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
#endif // V8_TARGET_ARCH_X64
|
||||
|
||||
} // namespace
|
||||
|
||||
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;
|
||||
@ -153,9 +177,9 @@ TEST(Unwind_BuiltinPCInMiddle_Success_CodePagesAPI) {
|
||||
bool unwound = v8::Unwinder::TryUnwindV8Frames(
|
||||
entry_stubs, pages_length, code_pages, ®ister_state, stack_base);
|
||||
CHECK(unwound);
|
||||
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);
|
||||
CHECK_EQ_VALUE_REGISTER(stack[topmost_fp_index], register_state.fp);
|
||||
CHECK_EQ_VALUE_REGISTER(stack[topmost_fp_index + 1], register_state.pc);
|
||||
CHECK_EQ_VALUE_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
|
||||
@ -208,9 +232,9 @@ TEST(Unwind_BuiltinPCAtStart_Success_CodePagesAPI) {
|
||||
entry_stubs, pages_length, code_pages, ®ister_state, stack_base);
|
||||
|
||||
CHECK(unwound);
|
||||
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);
|
||||
CHECK_EQ_VALUE_REGISTER(stack[topmost_fp_index], register_state.fp);
|
||||
CHECK_EQ_VALUE_REGISTER(stack[topmost_fp_index + 1], register_state.pc);
|
||||
CHECK_EQ_VALUE_REGISTER(stack[topmost_fp_index + 2], register_state.sp);
|
||||
}
|
||||
|
||||
const char* foo_source = R"(
|
||||
@ -296,9 +320,9 @@ TEST(Unwind_CodeObjectPCInMiddle_Success_CodePagesAPI) {
|
||||
bool unwound = v8::Unwinder::TryUnwindV8Frames(
|
||||
entry_stubs, pages_length, code_pages, ®ister_state, stack_base);
|
||||
CHECK(unwound);
|
||||
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);
|
||||
CHECK_EQ_VALUE_REGISTER(stack[topmost_fp_index], register_state.fp);
|
||||
CHECK_EQ_VALUE_REGISTER(stack[topmost_fp_index + 1], register_state.pc);
|
||||
CHECK_EQ_VALUE_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
|
||||
@ -345,8 +369,8 @@ TEST(Unwind_JSEntryBeforeFrame_Fail_CodePagesAPI) {
|
||||
entry_stubs, pages_length, code_pages, ®ister_state, stack_base);
|
||||
CHECK(!unwound);
|
||||
// The register state should not change when unwinding fails.
|
||||
CHECK_EQ_STACK_REGISTER(&stack[9], register_state.fp);
|
||||
CHECK_EQ_STACK_REGISTER(&stack[5], register_state.sp);
|
||||
CHECK_EQ_VALUE_REGISTER(&stack[9], register_state.fp);
|
||||
CHECK_EQ_VALUE_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.
|
||||
@ -358,8 +382,8 @@ TEST(Unwind_JSEntryBeforeFrame_Fail_CodePagesAPI) {
|
||||
// than just assuming the frame is unreadable.
|
||||
CHECK(!unwound);
|
||||
// The register state should not change when unwinding fails.
|
||||
CHECK_EQ_STACK_REGISTER(&stack[9], register_state.fp);
|
||||
CHECK_EQ_STACK_REGISTER(&stack[5], register_state.sp);
|
||||
CHECK_EQ_VALUE_REGISTER(&stack[9], register_state.fp);
|
||||
CHECK_EQ_VALUE_REGISTER(&stack[5], register_state.sp);
|
||||
CHECK_EQ(jsentry_pc_value, register_state.pc);
|
||||
}
|
||||
|
||||
@ -409,12 +433,13 @@ TEST(Unwind_TwoJSFrames_Success_CodePagesAPI) {
|
||||
entry_stubs, pages_length, code_pages, ®ister_state, stack_base);
|
||||
|
||||
CHECK(unwound);
|
||||
CHECK_EQ_STACK_REGISTER(stack[top_of_js_entry + kFPOffset],
|
||||
CHECK_EQ_VALUE_REGISTER(stack[top_of_js_entry + kFPOffset],
|
||||
register_state.fp);
|
||||
CHECK_EQ_STACK_REGISTER(stack[top_of_js_entry + kPCOffset],
|
||||
CHECK_EQ_VALUE_REGISTER(stack[top_of_js_entry + kPCOffset],
|
||||
register_state.pc);
|
||||
CHECK_EQ_STACK_REGISTER(stack[top_of_js_entry + kSPOffset],
|
||||
CHECK_EQ_VALUE_REGISTER(stack[top_of_js_entry + kSPOffset],
|
||||
register_state.sp);
|
||||
CheckCalleeSavedRegisters(register_state);
|
||||
}
|
||||
|
||||
// If the PC is in JSEntry then the frame might not be set up correctly, meaning
|
||||
@ -543,6 +568,7 @@ TEST(Unwind_StackBounds_WithUnwinding_CodePagesAPI) {
|
||||
unwound = v8::Unwinder::TryUnwindV8Frames(
|
||||
entry_stubs, pages_length, code_pages, ®ister_state, stack_base);
|
||||
CHECK(unwound);
|
||||
CheckCalleeSavedRegisters(register_state);
|
||||
}
|
||||
|
||||
TEST(PCIsInV8_BadState_Fail_CodePagesAPI) {
|
||||
@ -737,7 +763,7 @@ TEST(Unwind_TwoNestedFunctions_CodePagesAPI) {
|
||||
}
|
||||
#endif
|
||||
|
||||
#undef CHECK_EQ_STACK_REGISTER
|
||||
#undef CHECK_EQ_VALUE_REGISTER
|
||||
} // namespace test_unwinder_code_pages
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
Loading…
Reference in New Issue
Block a user