/src/node/deps/v8/include/v8-unwinder.h
Line | Count | Source |
1 | | // Copyright 2021 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 | | #ifndef INCLUDE_V8_UNWINDER_H_ |
6 | | #define INCLUDE_V8_UNWINDER_H_ |
7 | | |
8 | | #include <memory> |
9 | | |
10 | | #include "v8-embedder-state-scope.h" // NOLINT(build/include_directory) |
11 | | #include "v8config.h" // NOLINT(build/include_directory) |
12 | | |
13 | | namespace v8 { |
14 | | // Holds the callee saved registers needed for the stack unwinder. It is the |
15 | | // empty struct if no registers are required. Implemented in |
16 | | // include/v8-unwinder-state.h. |
17 | | struct CalleeSavedRegisters; |
18 | | |
19 | | // A RegisterState represents the current state of registers used |
20 | | // by the sampling profiler API. |
21 | | struct V8_EXPORT RegisterState { |
22 | | RegisterState(); |
23 | | ~RegisterState(); |
24 | | RegisterState(const RegisterState& other); |
25 | | RegisterState& operator=(const RegisterState& other); |
26 | | |
27 | | void* pc; // Instruction pointer. |
28 | | void* sp; // Stack pointer. |
29 | | void* fp; // Frame pointer. |
30 | | void* lr; // Link register (or nullptr on platforms without a link register). |
31 | | // Callee saved registers (or null if no callee saved registers were stored) |
32 | | std::unique_ptr<CalleeSavedRegisters> callee_saved; |
33 | | }; |
34 | | |
35 | | // A StateTag represents a possible state of the VM. |
36 | | // This enum is append-only to preserve compatibility with historical logs. |
37 | | // Add new states only at the end and do not reorder or remove existing values. |
38 | | // LINT.IfChange |
39 | | enum StateTag : uint16_t { |
40 | | JS, |
41 | | GC, |
42 | | PARSER, |
43 | | BYTECODE_COMPILER, |
44 | | COMPILER, |
45 | | OTHER, |
46 | | EXTERNAL, |
47 | | ATOMICS_WAIT, |
48 | | IDLE, |
49 | | LOGGING, |
50 | | IDLE_EXTERNAL, |
51 | | }; |
52 | | // LINT.ThenChange(../tools/profile.mjs, ../tools/tickprocessor.mjs) |
53 | | |
54 | 0 | constexpr bool IsExternal(StateTag state) { |
55 | 0 | return state == EXTERNAL || state == IDLE_EXTERNAL; |
56 | 0 | } |
57 | | |
58 | 0 | constexpr bool IsIdle(StateTag state) { |
59 | 0 | return state == IDLE || state == IDLE_EXTERNAL; |
60 | 0 | } |
61 | | |
62 | | // The output structure filled up by GetStackSample API function. |
63 | | struct SampleInfo { |
64 | | size_t frames_count; // Number of frames collected. |
65 | | void* external_callback_entry; // External callback address if VM is |
66 | | // executing an external callback. |
67 | | void* context; // Incumbent native context address. |
68 | | void* embedder_context; // Native context address for embedder state |
69 | | StateTag vm_state; // Current VM state. |
70 | | EmbedderStateTag embedder_state; // Current Embedder state |
71 | | }; |
72 | | |
73 | | struct MemoryRange { |
74 | | const void* start = nullptr; |
75 | | size_t length_in_bytes = 0; |
76 | | }; |
77 | | |
78 | | struct JSEntryStub { |
79 | | MemoryRange code; |
80 | | }; |
81 | | |
82 | | struct JSEntryStubs { |
83 | | JSEntryStub js_entry_stub; |
84 | | JSEntryStub js_construct_entry_stub; |
85 | | JSEntryStub js_run_microtasks_entry_stub; |
86 | | }; |
87 | | |
88 | | /** |
89 | | * Various helpers for skipping over V8 frames in a given stack. |
90 | | * |
91 | | * The unwinder API is only supported on the x64, ARM64 and ARM32 architectures. |
92 | | */ |
93 | | class V8_EXPORT Unwinder { |
94 | | public: |
95 | | /** |
96 | | * Attempt to unwind the stack to the most recent C++ frame. This function is |
97 | | * signal-safe and does not access any V8 state and thus doesn't require an |
98 | | * Isolate. |
99 | | * |
100 | | * The unwinder needs to know the location of the JS Entry Stub (a piece of |
101 | | * code that is run when C++ code calls into generated JS code). This is used |
102 | | * for edge cases where the current frame is being constructed or torn down |
103 | | * when the stack sample occurs. |
104 | | * |
105 | | * The unwinder also needs the virtual memory range of all possible V8 code |
106 | | * objects. There are two ranges required - the heap code range and the range |
107 | | * for code embedded in the binary. |
108 | | * |
109 | | * Available on x64, ARM64 and ARM32. |
110 | | * |
111 | | * \param code_pages A list of all of the ranges in which V8 has allocated |
112 | | * executable code. The caller should obtain this list by calling |
113 | | * Isolate::CopyCodePages() during the same interrupt/thread suspension that |
114 | | * captures the stack. |
115 | | * \param register_state The current registers. This is an in-out param that |
116 | | * will be overwritten with the register values after unwinding, on success. |
117 | | * \param stack_base The resulting stack pointer and frame pointer values are |
118 | | * bounds-checked against the stack_base and the original stack pointer value |
119 | | * to ensure that they are valid locations in the given stack. If these values |
120 | | * or any intermediate frame pointer values used during unwinding are ever out |
121 | | * of these bounds, unwinding will fail. |
122 | | * |
123 | | * \return True on success. |
124 | | */ |
125 | | static bool TryUnwindV8Frames(const JSEntryStubs& entry_stubs, |
126 | | size_t code_pages_length, |
127 | | const MemoryRange* code_pages, |
128 | | RegisterState* register_state, |
129 | | const void* stack_base); |
130 | | |
131 | | /** |
132 | | * Whether the PC is within the V8 code range represented by code_pages. |
133 | | * |
134 | | * If this returns false, then calling UnwindV8Frames() with the same PC |
135 | | * and unwind_state will always fail. If it returns true, then unwinding may |
136 | | * (but not necessarily) be successful. |
137 | | * |
138 | | * Available on x64, ARM64 and ARM32 |
139 | | */ |
140 | | static bool PCIsInV8(size_t code_pages_length, const MemoryRange* code_pages, |
141 | | void* pc); |
142 | | }; |
143 | | |
144 | | } // namespace v8 |
145 | | |
146 | | #endif // INCLUDE_V8_UNWINDER_H_ |