• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 enum StateTag : int {
37   JS,
38   GC,
39   PARSER,
40   BYTECODE_COMPILER,
41   COMPILER,
42   OTHER,
43   EXTERNAL,
44   ATOMICS_WAIT,
45   IDLE
46 };
47 
48 // The output structure filled up by GetStackSample API function.
49 struct SampleInfo {
50   size_t frames_count;              // Number of frames collected.
51   void* external_callback_entry;    // External callback address if VM is
52                                     // executing an external callback.
53   void* context;                    // Incumbent native context address.
54   void* embedder_context;           // Native context address for embedder state
55   StateTag vm_state;                // Current VM state.
56   EmbedderStateTag embedder_state;  // Current Embedder state
57 };
58 
59 struct MemoryRange {
60   const void* start = nullptr;
61   size_t length_in_bytes = 0;
62 };
63 
64 struct JSEntryStub {
65   MemoryRange code;
66 };
67 
68 struct JSEntryStubs {
69   JSEntryStub js_entry_stub;
70   JSEntryStub js_construct_entry_stub;
71   JSEntryStub js_run_microtasks_entry_stub;
72 };
73 
74 /**
75  * Various helpers for skipping over V8 frames in a given stack.
76  *
77  * The unwinder API is only supported on the x64, ARM64 and ARM32 architectures.
78  */
79 class V8_EXPORT Unwinder {
80  public:
81   /**
82    * Attempt to unwind the stack to the most recent C++ frame. This function is
83    * signal-safe and does not access any V8 state and thus doesn't require an
84    * Isolate.
85    *
86    * The unwinder needs to know the location of the JS Entry Stub (a piece of
87    * code that is run when C++ code calls into generated JS code). This is used
88    * for edge cases where the current frame is being constructed or torn down
89    * when the stack sample occurs.
90    *
91    * The unwinder also needs the virtual memory range of all possible V8 code
92    * objects. There are two ranges required - the heap code range and the range
93    * for code embedded in the binary.
94    *
95    * Available on x64, ARM64 and ARM32.
96    *
97    * \param code_pages A list of all of the ranges in which V8 has allocated
98    * executable code. The caller should obtain this list by calling
99    * Isolate::CopyCodePages() during the same interrupt/thread suspension that
100    * captures the stack.
101    * \param register_state The current registers. This is an in-out param that
102    * will be overwritten with the register values after unwinding, on success.
103    * \param stack_base The resulting stack pointer and frame pointer values are
104    * bounds-checked against the stack_base and the original stack pointer value
105    * to ensure that they are valid locations in the given stack. If these values
106    * or any intermediate frame pointer values used during unwinding are ever out
107    * of these bounds, unwinding will fail.
108    *
109    * \return True on success.
110    */
111   static bool TryUnwindV8Frames(const JSEntryStubs& entry_stubs,
112                                 size_t code_pages_length,
113                                 const MemoryRange* code_pages,
114                                 RegisterState* register_state,
115                                 const void* stack_base);
116 
117   /**
118    * Whether the PC is within the V8 code range represented by code_pages.
119    *
120    * If this returns false, then calling UnwindV8Frames() with the same PC
121    * and unwind_state will always fail. If it returns true, then unwinding may
122    * (but not necessarily) be successful.
123    *
124    * Available on x64, ARM64 and ARM32
125    */
126   static bool PCIsInV8(size_t code_pages_length, const MemoryRange* code_pages,
127                        void* pc);
128 };
129 
130 }  // namespace v8
131 
132 #endif  // INCLUDE_V8_UNWINDER_H_
133