Coverage Report

Created: 2025-10-31 09:06

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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_