v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
v8-debugger-script.cc
Go to the documentation of this file.
1// Copyright 2014 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
6
7#include "src/base/memory.h"
9#include "src/inspector/protocol/Debugger.h"
13#include "src/utils/sha-256.h"
14
15namespace v8_inspector {
16
17namespace {
18
19const char kGlobalDebuggerScriptHandleLabel[] = "DevTools debugger";
20
21String16 calculateHash(v8::Isolate* isolate, v8::Local<v8::String> source) {
22 uint32_t length = source->Length();
23 std::unique_ptr<UChar[]> buffer(new UChar[length]);
24 source->WriteV2(isolate, 0, length,
25 reinterpret_cast<uint16_t*>(buffer.get()));
26
27 const uint8_t* data = nullptr;
28 size_t sizeInBytes = sizeof(UChar) * length;
29 data = reinterpret_cast<const uint8_t*>(buffer.get());
30
31 uint8_t hash[kSizeOfSha256Digest];
32 v8::internal::SHA256_hash(data, sizeInBytes, hash);
33
34 String16Builder formatted_hash;
35 for (size_t i = 0; i < kSizeOfSha256Digest; i++)
36 formatted_hash.appendUnsignedAsHex(static_cast<uint8_t>(hash[i]));
37
38 return formatted_hash.toString();
39}
40
41class ActualScript : public V8DebuggerScript {
42 friend class V8DebuggerScript;
43
44 public:
45 ActualScript(v8::Isolate* isolate, v8::Local<v8::debug::Script> script,
46 bool isLiveEdit, V8DebuggerAgentImpl* agent,
47 V8InspectorClient* client)
48 : V8DebuggerScript(isolate, String16::fromInteger(script->Id()),
49 GetScriptURL(isolate, script, client),
50 GetScriptName(isolate, script, client)),
51 m_agent(agent),
52 m_isLiveEdit(isLiveEdit) {
53 Initialize(script);
54 }
55
56 bool isLiveEdit() const override { return m_isLiveEdit; }
57 bool isModule() const override { return m_isModule; }
58
59 String16 source(size_t pos, size_t len) const override {
61 v8::Local<v8::String> v8Source;
62 if (!m_scriptSource.Get(m_isolate)->JavaScriptCode().ToLocal(&v8Source)) {
63 return String16();
64 }
65 if (pos >= static_cast<size_t>(v8Source->Length())) return String16();
66 size_t substringLength =
67 std::min(len, static_cast<size_t>(v8Source->Length()) - pos);
68 std::unique_ptr<UChar[]> buffer(new UChar[substringLength]);
69 v8Source->WriteV2(m_isolate, static_cast<uint32_t>(pos),
70 static_cast<uint32_t>(substringLength),
71 reinterpret_cast<uint16_t*>(buffer.get()));
72 return String16(buffer.get(), substringLength);
73 }
74 Language getLanguage() const override { return m_language; }
75
76#if V8_ENABLE_WEBASSEMBLY
77 v8::Maybe<v8::MemorySpan<const uint8_t>> wasmBytecode() const override {
80 if (m_scriptSource.Get(m_isolate)->WasmBytecode().To(&bytecode)) {
81 return v8::Just(bytecode);
82 }
84 }
85
86 std::vector<v8::debug::WasmScript::DebugSymbols> getDebugSymbols()
87 const override {
88 auto script = this->script();
89 if (!script->IsWasm())
90 return std::vector<v8::debug::WasmScript::DebugSymbols>();
91 return v8::debug::WasmScript::Cast(*script)->GetDebugSymbols();
92 }
93
95 std::vector<int>* function_body_offsets) const override {
97 v8::Local<v8::debug::Script> script = this->script();
98 DCHECK(script->IsWasm());
99 v8::debug::WasmScript::Cast(*script)->Disassemble(collector,
100 function_body_offsets);
101 }
102#endif // V8_ENABLE_WEBASSEMBLY
103
104 int startLine() const override { return m_startLine; }
105 int startColumn() const override { return m_startColumn; }
106 int endLine() const override { return m_endLine; }
107 int endColumn() const override { return m_endColumn; }
108 int codeOffset() const override {
109#if V8_ENABLE_WEBASSEMBLY
110 if (script()->IsWasm()) {
111 return v8::debug::WasmScript::Cast(*script())->CodeOffset();
112 }
113#endif // V8_ENABLE_WEBASSEMBLY
114 return 0;
115 }
116 int length() const override {
117 return static_cast<int>(m_scriptSource.Get(m_isolate)->Length());
118 }
119
120 const String16& sourceMappingURL() const override {
121 return m_sourceMappingURL;
122 }
123
124 void setSourceMappingURL(const String16& sourceMappingURL) override {
125 m_sourceMappingURL = sourceMappingURL;
126 }
127
128 void setSource(const String16& newSource, bool preview,
129 bool allowTopFrameLiveEditing,
132 v8::Local<v8::String> v8Source = toV8String(m_isolate, newSource);
134 v8Source, preview, allowTopFrameLiveEditing, result)) {
135 result->message = scope.Escape(result->message);
136 return;
137 }
138 // NOP if preview or unchanged source (diffs.empty() in PatchScript)
139 if (preview || result->script.IsEmpty()) return;
140
141 m_hash = String16();
142 Initialize(scope.Escape(result->script));
143 }
144
145 bool getPossibleBreakpoints(
147 bool restrictToFunction,
148 std::vector<v8::debug::BreakLocation>* locations) override {
151 std::vector<v8::debug::BreakLocation> allLocations;
152 if (!script->GetPossibleBreakpoints(start, end, restrictToFunction,
153 &allLocations)) {
154 return false;
155 }
156 if (allLocations.empty()) return true;
157 v8::debug::BreakLocation current = allLocations[0];
158 for (size_t i = 1; i < allLocations.size(); ++i) {
159 if (allLocations[i].GetLineNumber() == current.GetLineNumber() &&
160 allLocations[i].GetColumnNumber() == current.GetColumnNumber()) {
161 if (allLocations[i].type() != v8::debug::kCommonBreakLocation) {
162 DCHECK(allLocations[i].type() == v8::debug::kCallBreakLocation ||
163 allLocations[i].type() == v8::debug::kReturnBreakLocation);
164 // debugger can returns more then one break location at the same
165 // source location, e.g. foo() - in this case there are two break
166 // locations before foo: for statement and for function call, we can
167 // merge them for inspector and report only one with call type.
168 current = allLocations[i];
169 }
170 } else {
171 // we assume that returned break locations are sorted.
172 DCHECK(
173 allLocations[i].GetLineNumber() > current.GetLineNumber() ||
174 (allLocations[i].GetColumnNumber() >= current.GetColumnNumber() &&
175 allLocations[i].GetLineNumber() == current.GetLineNumber()));
176 locations->push_back(current);
177 current = allLocations[i];
178 }
179 }
180 locations->push_back(current);
181 return true;
182 }
183
184 void resetBlackboxedStateCache() override {
187 }
188
189 v8::Maybe<int> offset(int lineNumber, int columnNumber) const override {
192 v8::debug::Location(lineNumber, columnNumber));
193 }
194
195 v8::debug::Location location(int offset) const override {
198 }
199
200 bool setBreakpoint(const String16& condition, v8::debug::Location* location,
201 int* id) const override {
203 return script()->SetBreakpoint(toV8String(m_isolate, condition), location,
204 id);
205 }
206
207 bool setInstrumentationBreakpoint(int* id) const override {
209 return script()->SetInstrumentationBreakpoint(id);
210 }
211
212 const String16& hash() const override {
213 if (!m_hash.isEmpty()) return m_hash;
215 v8::Local<v8::String> v8Source;
216 if (!m_scriptSource.Get(m_isolate)->JavaScriptCode().ToLocal(&v8Source)) {
217 v8Source = v8::String::Empty(m_isolate);
218 }
219 m_hash = calculateHash(m_isolate, v8Source);
220 DCHECK(!m_hash.isEmpty());
221 return m_hash;
222 }
223
224 String16 buildId() const override {
225#if V8_ENABLE_WEBASSEMBLY
226 if (m_language == Language::WebAssembly) {
227 v8::Local<v8::debug::Script> script = this->script();
228 auto maybe_build_id =
229 v8::debug::WasmScript::Cast(*script)->GetModuleBuildId();
230 if (maybe_build_id.IsJust()) {
231 v8::MemorySpan<const uint8_t> buildId = maybe_build_id.FromJust();
232 String16Builder buildIdFormatter;
233 for (size_t i = 0; i < buildId.size(); i++) {
234 buildIdFormatter.appendUnsignedAsHex(
235 static_cast<uint8_t>(buildId[i]));
236 }
237 return buildIdFormatter.toString();
238 }
239 }
240#endif // V8_ENABLE_WEBASSEMBLY
241 return {};
242 }
243
244 private:
245 static String16 GetScriptURL(v8::Isolate* isolate,
247 V8InspectorClient* client) {
248 v8::Local<v8::String> sourceURL;
249 if (script->SourceURL().ToLocal(&sourceURL) && sourceURL->Length() > 0)
250 return toProtocolString(isolate, sourceURL);
251 return GetScriptName(isolate, script, client);
252 }
253
254 static String16 GetScriptName(v8::Isolate* isolate,
256 V8InspectorClient* client) {
258 if (script->Name().ToLocal(&v8Name) && v8Name->Length() > 0) {
259 String16 name = toProtocolString(isolate, v8Name);
260 std::unique_ptr<StringBuffer> url =
261 client->resourceNameToUrl(toStringView(name));
262 return url ? toString16(url->string()) : name;
263 }
264 return String16();
265 }
266
267 v8::Local<v8::debug::Script> script() const override {
268 return m_script.Get(m_isolate);
269 }
270
271 void Initialize(v8::Local<v8::debug::Script> script) {
273 m_hasSourceURLComment =
274 script->SourceURL().ToLocal(&tmp) && tmp->Length() > 0;
275 if (script->SourceMappingURL().ToLocal(&tmp))
277 m_startLine = script->StartLine();
278 m_startColumn = script->StartColumn();
279 m_endLine = script->EndLine();
280 m_endColumn = script->EndColumn();
281
282 USE(script->ContextId().To(&m_executionContextId));
284#if V8_ENABLE_WEBASSEMBLY
285 if (script->IsWasm()) {
287 }
288#endif // V8_ENABLE_WEBASSEMBLY
289
290 m_isModule = script->IsModule();
291
292 bool hasHash = script->GetSha256Hash().ToLocal(&tmp) && tmp->Length() > 0;
293 if (hasHash) {
295 }
296
297 m_script.Reset(m_isolate, script);
298 m_script.AnnotateStrongRetainer(kGlobalDebuggerScriptHandleLabel);
299 m_scriptSource.Reset(m_isolate, script->Source());
300 m_scriptSource.AnnotateStrongRetainer(kGlobalDebuggerScriptHandleLabel);
301 }
302
303 void MakeWeak() override {
305 this,
306 [](const v8::WeakCallbackInfo<ActualScript>& data) {
307 data.GetParameter()->WeakCallback();
308 },
310 }
311
312 void WeakCallback() {
313 m_script.Reset();
314 m_agent->ScriptCollected(this);
315 }
316
317 V8DebuggerAgentImpl* m_agent;
319 Language m_language;
320 bool m_isLiveEdit = false;
321 bool m_isModule = false;
322 mutable String16 m_hash;
323 int m_startLine = 0;
325 int m_endLine = 0;
326 int m_endColumn = 0;
329};
330
331} // namespace
332
333std::unique_ptr<V8DebuggerScript> V8DebuggerScript::Create(
334 v8::Isolate* isolate, v8::Local<v8::debug::Script> scriptObj,
335 bool isLiveEdit, V8DebuggerAgentImpl* agent, V8InspectorClient* client) {
336 return std::make_unique<ActualScript>(isolate, scriptObj, isLiveEdit, agent,
337 client);
338}
339
341 String16 url, String16 embedderName)
342 : m_id(std::move(id)),
343 m_url(std::move(url)),
344 m_isolate(isolate),
345 m_embedderName(embedderName) {}
346
348
350 if (sourceURL.length() > 0) {
353 }
354}
355
356#if V8_ENABLE_WEBASSEMBLY
357void V8DebuggerScript::removeWasmBreakpoint(int id) {
359 script()->RemoveWasmBreakpoint(id);
360}
361#endif // V8_ENABLE_WEBASSEMBLY
362
363} // namespace v8_inspector
interpreter::Bytecode bytecode
Definition builtins.cc:43
SourcePosition pos
constexpr size_t size() const
V8_INLINE void AnnotateStrongRetainer(const char *label)
V8_INLINE Local< T > Get(Isolate *isolate) const
V8_INLINE void SetWeak(P *parameter, typename WeakCallbackInfo< P >::Callback callback, WeakCallbackType type)
static V8_INLINE Local< String > Empty(Isolate *isolate)
bool SetScriptSource(v8::Local< v8::String > newSource, bool preview, bool allow_top_frame_live_editing, LiveEditResult *result) const
v8::debug::Location GetSourceLocation(int offset) const
Maybe< int > GetSourceOffset(const debug::Location &location, GetSourceOffsetMode mode=GetSourceOffsetMode::kStrict) const
virtual v8::Local< v8::debug::Script > script() const =0
static std::unique_ptr< V8DebuggerScript > Create(v8::Isolate *isolate, v8::Local< v8::debug::Script > script, bool isLiveEdit, V8DebuggerAgentImpl *agent, V8InspectorClient *client)
virtual bool isLiveEdit() const =0
V8DebuggerScript(const V8DebuggerScript &)=delete
const String16 & sourceURL() const
void setSourceURL(const String16 &)
int start
int end
int32_t offset
ZoneVector< RpoNumber > & result
Register tmp
InstructionOperand source
void(*)(const LivenessBroker &, const void *) WeakCallback
Definition visitor.h:37
STL namespace.
unsigned short uint16_t
Definition unicode.cc:39
void MakeWeak(i::Address *location, void *parameter, WeakCallbackInfo< void >::Callback weak_callback, WeakCallbackType type)
Definition api.cc:644
void ResetBlackboxedStateCache(Isolate *v8_isolate, Local< Script > script)
void Disassemble(const WasmModule *module, ModuleWireBytes wire_bytes, NamesProvider *names, v8::debug::DisassemblyCollector *collector, std::vector< int > *function_body_offsets)
const uint8_t * SHA256_hash(const void *data, size_t len, uint8_t *digest)
Definition sha-256.cc:167
char16_t UChar
Definition string-16.h:22
String16 toProtocolString(v8::Isolate *isolate, v8::Local< v8::String > value)
StringView toStringView(const String16 &string)
v8::Local< v8::String > toV8String(v8::Isolate *isolate, const String16 &string)
String16 toString16(const StringView &string)
Maybe< T > Nothing()
Definition v8-maybe.h:112
Maybe< T > Just(const T &t)
Definition v8-maybe.h:117
const size_t kSizeOfSha256Digest
Definition sha-256.h:43
#define DCHECK(condition)
Definition logging.h:482
#define USE(...)
Definition macros.h:293
v8::Isolate * m_isolate
v8::Global< v8::debug::ScriptSource > m_scriptSource
String16 m_hash
String16 m_sourceMappingURL
V8DebuggerAgentImpl * m_agent
bool m_isLiveEdit
Language m_language
int m_endLine
v8::Global< v8::debug::Script > m_script
int m_endColumn
int m_startLine
int m_startColumn
bool m_isModule
wasm::ValueType type