Line data Source code
1 : // Copyright 2015 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 : #include "src/inspector/v8-injected-script-host.h"
6 :
7 : #include "src/base/macros.h"
8 : #include "src/inspector/injected-script.h"
9 : #include "src/inspector/string-util.h"
10 : #include "src/inspector/v8-debugger.h"
11 : #include "src/inspector/v8-inspector-impl.h"
12 : #include "src/inspector/v8-internal-value-type.h"
13 : #include "src/inspector/v8-value-utils.h"
14 :
15 : #include "include/v8-inspector.h"
16 :
17 : namespace v8_inspector {
18 :
19 : namespace {
20 :
21 26496 : void setFunctionProperty(v8::Local<v8::Context> context,
22 : v8::Local<v8::Object> obj, const char* name,
23 : v8::FunctionCallback callback,
24 : v8::Local<v8::External> external) {
25 : v8::Local<v8::String> funcName =
26 26496 : toV8StringInternalized(context->GetIsolate(), name);
27 : v8::Local<v8::Function> func;
28 26496 : if (!v8::Function::New(context, callback, external, 0,
29 26496 : v8::ConstructorBehavior::kThrow)
30 26496 : .ToLocal(&func))
31 0 : return;
32 26496 : func->SetName(funcName);
33 26496 : createDataProperty(context, obj, funcName, func);
34 : }
35 :
36 : V8InspectorImpl* unwrapInspector(
37 6853083 : const v8::FunctionCallbackInfo<v8::Value>& info) {
38 : DCHECK(!info.Data().IsEmpty());
39 : DCHECK(info.Data()->IsExternal());
40 : V8InspectorImpl* inspector =
41 6853083 : static_cast<V8InspectorImpl*>(info.Data().As<v8::External>()->Value());
42 : DCHECK(inspector);
43 : return inspector;
44 : }
45 :
46 : } // namespace
47 :
48 2944 : v8::Local<v8::Object> V8InjectedScriptHost::create(
49 2944 : v8::Local<v8::Context> context, V8InspectorImpl* inspector) {
50 : v8::Isolate* isolate = inspector->isolate();
51 2944 : v8::Local<v8::Object> injectedScriptHost = v8::Object::New(isolate);
52 2944 : bool success = injectedScriptHost->SetPrototype(context, v8::Null(isolate))
53 2944 : .FromMaybe(false);
54 : DCHECK(success);
55 : USE(success);
56 : v8::Local<v8::External> debuggerExternal =
57 2944 : v8::External::New(isolate, inspector);
58 : setFunctionProperty(context, injectedScriptHost, "nullifyPrototype",
59 : V8InjectedScriptHost::nullifyPrototypeCallback,
60 2944 : debuggerExternal);
61 : setFunctionProperty(context, injectedScriptHost, "getProperty",
62 : V8InjectedScriptHost::getPropertyCallback,
63 2944 : debuggerExternal);
64 : setFunctionProperty(context, injectedScriptHost, "internalConstructorName",
65 : V8InjectedScriptHost::internalConstructorNameCallback,
66 2944 : debuggerExternal);
67 : setFunctionProperty(
68 : context, injectedScriptHost, "formatAccessorsAsProperties",
69 2944 : V8InjectedScriptHost::formatAccessorsAsProperties, debuggerExternal);
70 : setFunctionProperty(context, injectedScriptHost, "subtype",
71 2944 : V8InjectedScriptHost::subtypeCallback, debuggerExternal);
72 : setFunctionProperty(context, injectedScriptHost, "getInternalProperties",
73 : V8InjectedScriptHost::getInternalPropertiesCallback,
74 2944 : debuggerExternal);
75 : setFunctionProperty(context, injectedScriptHost, "objectHasOwnProperty",
76 : V8InjectedScriptHost::objectHasOwnPropertyCallback,
77 2944 : debuggerExternal);
78 : setFunctionProperty(context, injectedScriptHost, "bind",
79 2944 : V8InjectedScriptHost::bindCallback, debuggerExternal);
80 : setFunctionProperty(context, injectedScriptHost, "proxyTargetValue",
81 : V8InjectedScriptHost::proxyTargetValueCallback,
82 2944 : debuggerExternal);
83 : createDataProperty(context, injectedScriptHost,
84 : toV8StringInternalized(isolate, "keys"),
85 8832 : v8::debug::GetBuiltin(isolate, v8::debug::kObjectKeys));
86 : createDataProperty(
87 : context, injectedScriptHost,
88 : toV8StringInternalized(isolate, "getPrototypeOf"),
89 8832 : v8::debug::GetBuiltin(isolate, v8::debug::kObjectGetPrototypeOf));
90 : createDataProperty(
91 : context, injectedScriptHost,
92 : toV8StringInternalized(isolate, "getOwnPropertyDescriptor"),
93 : v8::debug::GetBuiltin(isolate,
94 8832 : v8::debug::kObjectGetOwnPropertyDescriptor));
95 : createDataProperty(
96 : context, injectedScriptHost,
97 : toV8StringInternalized(isolate, "getOwnPropertyNames"),
98 8832 : v8::debug::GetBuiltin(isolate, v8::debug::kObjectGetOwnPropertyNames));
99 : createDataProperty(
100 : context, injectedScriptHost,
101 : toV8StringInternalized(isolate, "getOwnPropertySymbols"),
102 8832 : v8::debug::GetBuiltin(isolate, v8::debug::kObjectGetOwnPropertySymbols));
103 2944 : return injectedScriptHost;
104 : }
105 :
106 2441489 : void V8InjectedScriptHost::nullifyPrototypeCallback(
107 4882978 : const v8::FunctionCallbackInfo<v8::Value>& info) {
108 2441489 : CHECK_EQ(1, info.Length());
109 : DCHECK(info[0]->IsObject());
110 4882978 : if (!info[0]->IsObject()) return;
111 : v8::Isolate* isolate = info.GetIsolate();
112 : info[0]
113 : .As<v8::Object>()
114 4882978 : ->SetPrototype(isolate->GetCurrentContext(), v8::Null(isolate))
115 4882978 : .ToChecked();
116 : }
117 :
118 1540492 : void V8InjectedScriptHost::getPropertyCallback(
119 4620906 : const v8::FunctionCallbackInfo<v8::Value>& info) {
120 3080984 : CHECK(info.Length() == 2 && info[1]->IsString());
121 1540492 : if (!info[0]->IsObject()) return;
122 : v8::Isolate* isolate = info.GetIsolate();
123 1540492 : v8::Local<v8::Context> context = isolate->GetCurrentContext();
124 1540492 : v8::TryCatch tryCatch(isolate);
125 : v8::Isolate::DisallowJavascriptExecutionScope throwJs(
126 3080984 : isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
127 : v8::Local<v8::Value> property;
128 1540492 : if (info[0]
129 : .As<v8::Object>()
130 1540492 : ->Get(context, v8::Local<v8::String>::Cast(info[1]))
131 1540492 : .ToLocal(&property)) {
132 : info.GetReturnValue().Set(property);
133 1540492 : }
134 : }
135 :
136 5108772 : void V8InjectedScriptHost::internalConstructorNameCallback(
137 10162552 : const v8::FunctionCallbackInfo<v8::Value>& info) {
138 15326316 : if (info.Length() < 1 || !info[0]->IsObject()) return;
139 :
140 : v8::Local<v8::Object> object = info[0].As<v8::Object>();
141 5053780 : info.GetReturnValue().Set(object->GetConstructorName());
142 : }
143 :
144 18525 : void V8InjectedScriptHost::formatAccessorsAsProperties(
145 18645 : const v8::FunctionCallbackInfo<v8::Value>& info) {
146 : DCHECK_EQ(info.Length(), 2);
147 : info.GetReturnValue().Set(false);
148 18525 : if (!info[1]->IsFunction()) return;
149 : // Check that function is user-defined.
150 18510 : if (info[1].As<v8::Function>()->ScriptId() != v8::UnboundScript::kNoScriptId)
151 : return;
152 : info.GetReturnValue().Set(
153 240 : unwrapInspector(info)->client()->formatAccessorsAsProperties(info[0]));
154 : }
155 :
156 7034295 : void V8InjectedScriptHost::subtypeCallback(
157 14250007 : const v8::FunctionCallbackInfo<v8::Value>& info) {
158 7215712 : if (info.Length() < 1) return;
159 :
160 : v8::Isolate* isolate = info.GetIsolate();
161 : v8::Local<v8::Value> value = info[0];
162 7034295 : if (value->IsObject()) {
163 : v8::Local<v8::Value> internalType = v8InternalValueTypeFrom(
164 6848943 : isolate->GetCurrentContext(), v8::Local<v8::Object>::Cast(value));
165 6848943 : if (internalType->IsString()) {
166 : info.GetReturnValue().Set(internalType);
167 1050 : return;
168 : }
169 : }
170 7033245 : if (value->IsArray() || value->IsArgumentsObject()) {
171 155462 : info.GetReturnValue().Set(toV8StringInternalized(isolate, "array"));
172 : return;
173 : }
174 6877783 : if (value->IsTypedArray()) {
175 105 : info.GetReturnValue().Set(toV8StringInternalized(isolate, "typedarray"));
176 : return;
177 : }
178 6877678 : if (value->IsDate()) {
179 63 : info.GetReturnValue().Set(toV8StringInternalized(isolate, "date"));
180 : return;
181 : }
182 6877615 : if (value->IsRegExp()) {
183 30 : info.GetReturnValue().Set(toV8StringInternalized(isolate, "regexp"));
184 : return;
185 : }
186 6877585 : if (value->IsMap()) {
187 283 : info.GetReturnValue().Set(toV8StringInternalized(isolate, "map"));
188 : return;
189 : }
190 6877302 : if (value->IsWeakMap()) {
191 150 : info.GetReturnValue().Set(toV8StringInternalized(isolate, "weakmap"));
192 : return;
193 : }
194 6877152 : if (value->IsSet()) {
195 305 : info.GetReturnValue().Set(toV8StringInternalized(isolate, "set"));
196 : return;
197 : }
198 6876847 : if (value->IsWeakSet()) {
199 150 : info.GetReturnValue().Set(toV8StringInternalized(isolate, "weakset"));
200 : return;
201 : }
202 6876697 : if (value->IsMapIterator() || value->IsSetIterator()) {
203 766 : info.GetReturnValue().Set(toV8StringInternalized(isolate, "iterator"));
204 : return;
205 : }
206 6875931 : if (value->IsGeneratorObject()) {
207 375 : info.GetReturnValue().Set(toV8StringInternalized(isolate, "generator"));
208 : return;
209 : }
210 6875556 : if (value->IsNativeError()) {
211 20140 : info.GetReturnValue().Set(toV8StringInternalized(isolate, "error"));
212 : return;
213 : }
214 6855416 : if (value->IsProxy()) {
215 15 : info.GetReturnValue().Set(toV8StringInternalized(isolate, "proxy"));
216 : return;
217 : }
218 6855401 : if (value->IsPromise()) {
219 2373 : info.GetReturnValue().Set(toV8StringInternalized(isolate, "promise"));
220 : return;
221 : }
222 6853028 : if (value->IsArrayBuffer() || value->IsSharedArrayBuffer()) {
223 100 : info.GetReturnValue().Set(toV8StringInternalized(isolate, "arraybuffer"));
224 : return;
225 : }
226 6852928 : if (value->IsDataView()) {
227 50 : info.GetReturnValue().Set(toV8StringInternalized(isolate, "dataview"));
228 : return;
229 : }
230 : std::unique_ptr<StringBuffer> subtype =
231 6852878 : unwrapInspector(info)->client()->valueSubtype(value);
232 6852878 : if (subtype) {
233 0 : info.GetReturnValue().Set(toV8String(isolate, subtype->string()));
234 : return;
235 : }
236 : }
237 :
238 390 : void V8InjectedScriptHost::getInternalPropertiesCallback(
239 560 : const v8::FunctionCallbackInfo<v8::Value>& info) {
240 695 : if (info.Length() < 1) return;
241 :
242 390 : std::unordered_set<String16> allowedProperties;
243 1545 : if (info[0]->IsBooleanObject() || info[0]->IsNumberObject() ||
244 1145 : info[0]->IsStringObject() || info[0]->IsSymbolObject()) {
245 40 : allowedProperties.insert(String16("[[PrimitiveValue]]"));
246 370 : } else if (info[0]->IsPromise()) {
247 30 : allowedProperties.insert(String16("[[PromiseStatus]]"));
248 30 : allowedProperties.insert(String16("[[PromiseValue]]"));
249 355 : } else if (info[0]->IsGeneratorObject()) {
250 10 : allowedProperties.insert(String16("[[GeneratorStatus]]"));
251 1705 : } else if (info[0]->IsMap() || info[0]->IsWeakMap() || info[0]->IsSet() ||
252 1295 : info[0]->IsWeakSet() || info[0]->IsMapIterator() ||
253 310 : info[0]->IsSetIterator()) {
254 90 : allowedProperties.insert(String16("[[Entries]]"));
255 : }
256 390 : if (!allowedProperties.size()) return;
257 :
258 : v8::Isolate* isolate = info.GetIsolate();
259 : v8::Local<v8::Array> allProperties;
260 85 : if (!unwrapInspector(info)
261 : ->debugger()
262 85 : ->internalProperties(isolate->GetCurrentContext(), info[0])
263 170 : .ToLocal(&allProperties) ||
264 170 : !allProperties->IsArray() || allProperties->Length() % 2 != 0)
265 : return;
266 :
267 : {
268 85 : v8::Local<v8::Context> context = isolate->GetCurrentContext();
269 85 : v8::TryCatch tryCatch(isolate);
270 : v8::Isolate::DisallowJavascriptExecutionScope throwJs(
271 : isolate,
272 170 : v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
273 :
274 85 : v8::Local<v8::Array> properties = v8::Array::New(isolate);
275 85 : if (tryCatch.HasCaught()) return;
276 :
277 : uint32_t outputIndex = 0;
278 150 : for (uint32_t i = 0; i < allProperties->Length(); i += 2) {
279 : v8::Local<v8::Value> key;
280 350 : if (!allProperties->Get(context, i).ToLocal(&key)) continue;
281 150 : if (tryCatch.HasCaught()) {
282 0 : tryCatch.Reset();
283 0 : continue;
284 : }
285 150 : String16 keyString = toProtocolStringWithTypeCheck(key);
286 300 : if (keyString.isEmpty() ||
287 : allowedProperties.find(keyString) == allowedProperties.end())
288 : continue;
289 : v8::Local<v8::Value> value;
290 200 : if (!allProperties->Get(context, i + 1).ToLocal(&value)) continue;
291 100 : if (tryCatch.HasCaught()) {
292 0 : tryCatch.Reset();
293 0 : continue;
294 : }
295 100 : createDataProperty(context, properties, outputIndex++, key);
296 100 : createDataProperty(context, properties, outputIndex++, value);
297 : }
298 85 : info.GetReturnValue().Set(properties);
299 : }
300 : }
301 :
302 60 : void V8InjectedScriptHost::objectHasOwnPropertyCallback(
303 180 : const v8::FunctionCallbackInfo<v8::Value>& info) {
304 240 : if (info.Length() < 2 || !info[0]->IsObject() || !info[1]->IsString()) return;
305 : bool result = info[0]
306 : .As<v8::Object>()
307 : ->HasOwnProperty(info.GetIsolate()->GetCurrentContext(),
308 120 : v8::Local<v8::String>::Cast(info[1]))
309 120 : .FromMaybe(false);
310 : info.GetReturnValue().Set(v8::Boolean::New(info.GetIsolate(), result));
311 : }
312 :
313 2540233 : void V8InjectedScriptHost::bindCallback(
314 10160932 : const v8::FunctionCallbackInfo<v8::Value>& info) {
315 5080466 : if (info.Length() < 2 || !info[1]->IsString()) return;
316 : InjectedScript* injectedScript =
317 2540233 : InjectedScript::fromInjectedScriptHost(info.GetIsolate(), info.Holder());
318 2540233 : if (!injectedScript) return;
319 :
320 2540233 : v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
321 : v8::Local<v8::String> v8groupName =
322 2540233 : info[1]->ToString(context).ToLocalChecked();
323 2540233 : String16 groupName = toProtocolStringWithTypeCheck(v8groupName);
324 2540233 : int id = injectedScript->bindObject(info[0], groupName);
325 : info.GetReturnValue().Set(id);
326 : }
327 :
328 0 : void V8InjectedScriptHost::proxyTargetValueCallback(
329 0 : const v8::FunctionCallbackInfo<v8::Value>& info) {
330 0 : if (info.Length() != 1 || !info[0]->IsProxy()) {
331 0 : UNREACHABLE();
332 : return;
333 : }
334 : v8::Local<v8::Object> target = info[0].As<v8::Proxy>();
335 0 : while (target->IsProxy())
336 0 : target = v8::Local<v8::Proxy>::Cast(target)->GetTarget();
337 : info.GetReturnValue().Set(target);
338 0 : }
339 :
340 : } // namespace v8_inspector
|