summaryrefslogtreecommitdiff
path: root/deps/v8/src/unwinder.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/unwinder.cc')
-rw-r--r--deps/v8/src/unwinder.cc98
1 files changed, 98 insertions, 0 deletions
diff --git a/deps/v8/src/unwinder.cc b/deps/v8/src/unwinder.cc
new file mode 100644
index 0000000000..b0b6ee0504
--- /dev/null
+++ b/deps/v8/src/unwinder.cc
@@ -0,0 +1,98 @@
+// Copyright 2018 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.h"
+#include "src/frame-constants.h"
+#include "src/globals.h"
+
+namespace v8 {
+
+namespace {
+
+bool PCIsInCodeRange(const v8::MemoryRange& code_range, void* pc) {
+ // Given that the length of the memory range is in bytes and it is not
+ // necessarily aligned, we need to do the pointer arithmetic in byte* here.
+ const i::byte* pc_as_byte = reinterpret_cast<i::byte*>(pc);
+ const i::byte* start = reinterpret_cast<const i::byte*>(code_range.start);
+ const i::byte* end = start + code_range.length_in_bytes;
+ return pc_as_byte >= start && pc_as_byte < end;
+}
+
+bool IsInUnsafeJSEntryRange(const v8::JSEntryStub& js_entry_stub, void* pc) {
+ return PCIsInCodeRange(js_entry_stub.code, pc);
+
+ // TODO(petermarshall): We can be more precise by checking whether we are
+ // in JSEntry but after frame setup and before frame teardown, in which case
+ // we are safe to unwind the stack. For now, we bail out if the PC is anywhere
+ // within JSEntry.
+}
+
+i::Address Load(i::Address address) {
+ return *reinterpret_cast<i::Address*>(address);
+}
+
+void* GetReturnAddressFromFP(void* fp) {
+ return reinterpret_cast<void*>(
+ Load(reinterpret_cast<i::Address>(fp) +
+ i::CommonFrameConstants::kCallerPCOffset));
+}
+
+void* GetCallerFPFromFP(void* fp) {
+ return reinterpret_cast<void*>(
+ Load(reinterpret_cast<i::Address>(fp) +
+ i::CommonFrameConstants::kCallerFPOffset));
+}
+
+void* GetCallerSPFromFP(void* fp) {
+ return reinterpret_cast<void*>(reinterpret_cast<i::Address>(fp) +
+ i::CommonFrameConstants::kCallerSPOffset);
+}
+
+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 UnwindState& unwind_state,
+ RegisterState* register_state,
+ const void* stack_base) {
+ const void* stack_top = register_state->sp;
+
+ void* pc = register_state->pc;
+ if (PCIsInV8(unwind_state, pc) &&
+ !IsInUnsafeJSEntryRange(unwind_state.js_entry_stub, pc)) {
+ void* current_fp = register_state->fp;
+ if (!AddressIsInStack(current_fp, stack_base, stack_top)) return false;
+
+ // Peek at the return address that the caller pushed. If it's in V8, then we
+ // assume the caller frame is a JS frame and continue to unwind.
+ void* next_pc = GetReturnAddressFromFP(current_fp);
+ while (PCIsInV8(unwind_state, next_pc)) {
+ current_fp = GetCallerFPFromFP(current_fp);
+ if (!AddressIsInStack(current_fp, stack_base, stack_top)) return false;
+ next_pc = GetReturnAddressFromFP(current_fp);
+ }
+
+ void* final_sp = GetCallerSPFromFP(current_fp);
+ if (!AddressIsInStack(final_sp, stack_base, stack_top)) return false;
+ register_state->sp = final_sp;
+
+ void* final_fp = GetCallerFPFromFP(current_fp);
+ if (!AddressIsInStack(final_fp, stack_base, stack_top)) return false;
+ register_state->fp = final_fp;
+
+ register_state->pc = next_pc;
+ return true;
+ }
+ return false;
+}
+
+bool Unwinder::PCIsInV8(const UnwindState& unwind_state, void* pc) {
+ return pc && (PCIsInCodeRange(unwind_state.code_range, pc) ||
+ PCIsInCodeRange(unwind_state.embedded_code_range, pc));
+}
+
+} // namespace v8