Files
Joone Hur 1df1972ce6 Add StackFrame::IsScriptOpaque API
Expose whether the associated script is opaque through the public
StackFrame API. This lets embedders check whether source location
information needs redaction before exposing it to web content.

Bug: 502251640
Change-Id: I4217f71156312b2d1db98902607a1b59b11bcb05
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/8422987
Reviewed-by: Leszek Swirski <leszeks@chromium.org>
Reviewed-by: Camillo Bruni <cbruni@chromium.org>
Reviewed-by: Toon Verwaest <verwaest@chromium.org>
Commit-Queue: Joone Hur <joonehur@microsoft.com>
Cr-Commit-Position: refs/heads/main@{#110021}
2026-09-22 13:55:13 -07:00

240 lines
7.6 KiB
C++

// Copyright 2021 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.
#ifndef INCLUDE_V8_DEBUG_H_
#define INCLUDE_V8_DEBUG_H_
#include <stdint.h>
#include <span>
#include "v8-script.h" // NOLINT(build/include_directory)
#include "v8config.h" // NOLINT(build/include_directory)
namespace v8 {
class Isolate;
class String;
/**
* A single JavaScript stack frame.
*/
class V8_EXPORT StackFrame {
public:
/**
* Returns the source location, 0-based, for the associated function call.
*/
Location GetLocation() const;
/**
* Returns the number, 1-based, of the line for the associate function call.
* This method will return Message::kNoLineNumberInfo if it is unable to
* retrieve the line number, or if kLineNumber was not passed as an option
* when capturing the StackTrace.
*/
int GetLineNumber() const { return GetLocation().GetLineNumber() + 1; }
/**
* Returns the 1-based column offset on the line for the associated function
* call.
* This method will return Message::kNoColumnInfo if it is unable to retrieve
* the column number, or if kColumnOffset was not passed as an option when
* capturing the StackTrace.
*/
int GetColumn() const { return GetLocation().GetColumnNumber() + 1; }
/**
* Returns zero based source position (character offset) for the associated
* function.
*/
int GetSourcePosition() const;
/**
* Returns the id of the script for the function for this StackFrame.
* This method will return Message::kNoScriptIdInfo if it is unable to
* retrieve the script id, or if kScriptId was not passed as an option when
* capturing the StackTrace.
*/
int GetScriptId() const;
/**
* Returns the name of the resource that contains the script for the
* function for this StackFrame.
*/
Local<String> GetScriptName() const;
/**
* Returns the name of the resource that contains the script for the
* function for this StackFrame or sourceURL value if the script name
* is undefined and its source ends with //# sourceURL=... string or
* deprecated //@ sourceURL=... string.
*/
Local<String> GetScriptNameOrSourceURL() const;
/**
* Returns the source of the script for the function for this StackFrame.
*/
Local<String> GetScriptSource() const;
/**
* Returns the source mapping URL (if one is present) of the script for
* the function for this StackFrame.
*/
Local<String> GetScriptSourceMappingURL() const;
/**
* Returns the name of the function associated with this stack frame.
*/
Local<String> GetFunctionName() const;
/**
* Returns whether or not the associated function is compiled via a call to
* eval().
*/
bool IsEval() const;
/**
* Returns whether or not the associated function is called as a
* constructor via "new".
*/
bool IsConstructor() const;
/**
* Returns whether or not the associated functions is defined in wasm.
*/
bool IsWasm() const;
/**
* Returns whether or not the associated function is defined by the user.
*/
bool IsUserJavaScript() const;
/**
* Returns whether the script was compiled with resource_is_opaque set in its
* ScriptOrigin.
*/
bool IsScriptOpaque() const;
};
/**
* Representation of a JavaScript stack trace. The information collected is a
* snapshot of the execution stack and the information remains valid after
* execution continues.
*/
class V8_EXPORT StackTrace {
public:
/**
* Flags that determine what information is placed captured for each
* StackFrame when grabbing the current stack trace.
* Note: these options are deprecated and we always collect all available
* information (kDetailed).
*/
enum StackTraceOptions {
kLineNumber = 1,
kColumnOffset = 1 << 1 | kLineNumber,
kScriptName = 1 << 2,
kFunctionName = 1 << 3,
kIsEval = 1 << 4,
kIsConstructor = 1 << 5,
kScriptNameOrSourceURL = 1 << 6,
kScriptId = 1 << 7,
kExposeFramesAcrossSecurityOrigins = 1 << 8,
kOverview = kLineNumber | kColumnOffset | kScriptName | kFunctionName,
kDetailed = kOverview | kIsEval | kIsConstructor | kScriptNameOrSourceURL
};
struct ScriptIdAndContext {
int id;
v8::Local<v8::Context> context;
};
struct ScriptData {
int id;
v8::Local<v8::Function> function;
v8::Local<v8::Context> context;
};
/**
* Returns the (unique) ID of this stack trace.
*/
int GetID() const;
/**
* Returns a StackFrame at a particular index.
*/
Local<StackFrame> GetFrame(Isolate* isolate, uint32_t index) const;
/**
* Returns the number of StackFrames.
*/
int GetFrameCount() const;
/**
* Grab a snapshot of the current JavaScript execution stack.
*
* \param frame_limit The maximum number of stack frames we want to capture.
* \param options Enumerates the set of things we will capture for each
* StackFrame.
*/
static Local<StackTrace> CurrentStackTrace(
Isolate* isolate, int frame_limit, StackTraceOptions options = kDetailed);
/**
* Returns the first valid script name or source URL starting at the top of
* the JS stack. The returned string is either an empty handle if no script
* name/url was found or a non-zero-length string.
*
* This method is equivalent to calling StackTrace::CurrentStackTrace and
* walking the resulting frames from the beginning until a non-empty script
* name/url is found. The difference is that this method won't allocate
* a stack trace.
*/
static Local<String> CurrentScriptNameOrSourceURL(Isolate* isolate);
/**
* Returns the first valid script id at the top of the JS stack. The returned
* value is Message::kNoScriptIdInfo if no id was found.
*
* This method is equivalent to calling StackTrace::CurrentStackTrace and
* walking the resulting frames from the beginning until a non-empty id is
* found. The difference is that this method won't allocate a stack trace.
*/
static int CurrentScriptId(Isolate* isolate);
/**
* Writes up to the first `frame_data.size()` valid script ids and function
* contexts at the top of the JS stack into the given span. Returns a span
* sized to the number of frames worth of data written. It's similar to the
* CurrentStackTrace method but doesn't allocate a stack trace. Further, it
* skips frames that don't have valid script ids or function contexts. The
* final difference is that the script id written for evals or regexp is that
* of the script that ran eval() or regexp, not the current context.
*
*/
V8_DEPRECATE_SOON("Use CurrentScriptData instead")
static std::span<v8::StackTrace::ScriptIdAndContext>
CurrentScriptIdsAndContexts(Isolate* isolate,
std::span<ScriptIdAndContext> frame_data);
/**
* Writes up to the first `frame_data.size()` valid script ids, functions, and
* contexts at the top of the JS stack into the given span. Returns a span
* sized to the number of frames worth of data written. It's similar to the
* CurrentStackTrace method but doesn't allocate a stack trace. Further, it
* skips non-js frames and frames that don't have valid script ids or function
* contexts. The final difference is that the script id written for evals or
* regexp is that of the script that ran eval() or regexp, not the current
* context.
*
* WARNING: This is an unfinished experimental feature. Semantics and
* implementation may change frequently.
*/
static std::span<v8::StackTrace::ScriptData> CurrentScriptData(
Isolate* isolate, std::span<ScriptData> frame_data);
};
} // namespace v8
#endif // INCLUDE_V8_DEBUG_H_