V8 API Reference, 7.2.502.16 (for Deno 0.2.4)
unwinder.cc
1 // Copyright 2018 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "include/v8.h"
6 #include "src/frame-constants.h"
7 #include "src/globals.h"
8 
9 namespace v8 {
10 
11 namespace {
12 
13 bool PCIsInCodeRange(const v8::MemoryRange& code_range, void* pc) {
14  // Given that the length of the memory range is in bytes and it is not
15  // necessarily aligned, we need to do the pointer arithmetic in byte* here.
16  const i::byte* pc_as_byte = reinterpret_cast<i::byte*>(pc);
17  const i::byte* start = reinterpret_cast<const i::byte*>(code_range.start);
18  const i::byte* end = start + code_range.length_in_bytes;
19  return pc_as_byte >= start && pc_as_byte < end;
20 }
21 
22 bool IsInUnsafeJSEntryRange(const v8::JSEntryStub& js_entry_stub, void* pc) {
23  return PCIsInCodeRange(js_entry_stub.code, pc);
24 
25  // TODO(petermarshall): We can be more precise by checking whether we are
26  // in the JSEntryStub but after frame setup and before frame teardown, in
27  // which case we are safe to unwind the stack. For now, we bail out if the PC
28  // is anywhere within the JSEntryStub.
29 }
30 
31 i::Address Load(i::Address address) {
32  return *reinterpret_cast<i::Address*>(address);
33 }
34 
35 void* GetReturnAddressFromFP(void* fp) {
36  return reinterpret_cast<void*>(
37  Load(reinterpret_cast<i::Address>(fp) +
38  i::CommonFrameConstants::kCallerPCOffset));
39 }
40 
41 void* GetCallerFPFromFP(void* fp) {
42  return reinterpret_cast<void*>(
43  Load(reinterpret_cast<i::Address>(fp) +
44  i::CommonFrameConstants::kCallerFPOffset));
45 }
46 
47 void* GetCallerSPFromFP(void* fp) {
48  return reinterpret_cast<void*>(reinterpret_cast<i::Address>(fp) +
49  i::CommonFrameConstants::kCallerSPOffset);
50 }
51 
52 } // namespace
53 
54 bool Unwinder::TryUnwindV8Frames(const UnwindState& unwind_state,
55  RegisterState* register_state,
56  const void* stack_base) {
57  void* pc = register_state->pc;
58  if (PCIsInV8(unwind_state, pc) &&
59  !IsInUnsafeJSEntryRange(unwind_state.js_entry_stub, pc)) {
60  void* current_fp = register_state->fp;
61 
62  // Peek at the return address that the caller pushed. If it's in V8, then we
63  // assume the caller frame is a JS frame and continue to unwind.
64  void* next_pc = GetReturnAddressFromFP(current_fp);
65  while (PCIsInV8(unwind_state, next_pc)) {
66  current_fp = GetCallerFPFromFP(current_fp);
67  next_pc = GetReturnAddressFromFP(current_fp);
68  }
69 
70  register_state->sp = GetCallerSPFromFP(current_fp);
71  register_state->fp = GetCallerFPFromFP(current_fp);
72  register_state->pc = next_pc;
73  return true;
74  }
75  return false;
76 }
77 
78 bool Unwinder::PCIsInV8(const UnwindState& unwind_state, void* pc) {
79  return pc && (PCIsInCodeRange(unwind_state.code_range, pc) ||
80  PCIsInCodeRange(unwind_state.embedded_code_range, pc));
81 }
82 
83 } // namespace v8
Definition: libplatform.h:13