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-native.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-copier.h"
14 :
15 : #include "include/v8-inspector.h"
16 :
17 : namespace v8_inspector {
18 :
19 : namespace {
20 :
21 36981 : 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 36981 : toV8StringInternalized(context->GetIsolate(), name);
27 : v8::Local<v8::Function> func;
28 36981 : if (!v8::Function::New(context, callback, external, 0,
29 36981 : v8::ConstructorBehavior::kThrow)
30 73962 : .ToLocal(&func))
31 0 : return;
32 36981 : func->SetName(funcName);
33 36981 : createDataProperty(context, obj, funcName, func);
34 : }
35 :
36 : V8InspectorImpl* unwrapInspector(
37 10149592 : const v8::FunctionCallbackInfo<v8::Value>& info) {
38 : DCHECK(!info.Data().IsEmpty());
39 : DCHECK(info.Data()->IsExternal());
40 : V8InspectorImpl* inspector =
41 10149592 : static_cast<V8InspectorImpl*>(info.Data().As<v8::External>()->Value());
42 : DCHECK(inspector);
43 : return inspector;
44 : }
45 :
46 : } // namespace
47 :
48 4109 : v8::Local<v8::Object> V8InjectedScriptHost::create(
49 4109 : v8::Local<v8::Context> context, V8InspectorImpl* inspector) {
50 : v8::Isolate* isolate = inspector->isolate();
51 4109 : v8::Local<v8::Object> injectedScriptHost = v8::Object::New(isolate);
52 4109 : bool success = injectedScriptHost->SetPrototype(context, v8::Null(isolate))
53 4109 : .FromMaybe(false);
54 : DCHECK(success);
55 : USE(success);
56 : v8::Local<v8::External> debuggerExternal =
57 4109 : v8::External::New(isolate, inspector);
58 : setFunctionProperty(context, injectedScriptHost, "nullifyPrototype",
59 : V8InjectedScriptHost::nullifyPrototypeCallback,
60 4109 : debuggerExternal);
61 : setFunctionProperty(context, injectedScriptHost, "getProperty",
62 : V8InjectedScriptHost::getPropertyCallback,
63 4109 : debuggerExternal);
64 : setFunctionProperty(context, injectedScriptHost, "internalConstructorName",
65 : V8InjectedScriptHost::internalConstructorNameCallback,
66 4109 : debuggerExternal);
67 : setFunctionProperty(
68 : context, injectedScriptHost, "formatAccessorsAsProperties",
69 4109 : V8InjectedScriptHost::formatAccessorsAsProperties, debuggerExternal);
70 : setFunctionProperty(context, injectedScriptHost, "subtype",
71 4109 : V8InjectedScriptHost::subtypeCallback, debuggerExternal);
72 : setFunctionProperty(context, injectedScriptHost, "getInternalProperties",
73 : V8InjectedScriptHost::getInternalPropertiesCallback,
74 4109 : debuggerExternal);
75 : setFunctionProperty(context, injectedScriptHost, "objectHasOwnProperty",
76 : V8InjectedScriptHost::objectHasOwnPropertyCallback,
77 4109 : debuggerExternal);
78 : setFunctionProperty(context, injectedScriptHost, "bind",
79 4109 : V8InjectedScriptHost::bindCallback, debuggerExternal);
80 : setFunctionProperty(context, injectedScriptHost, "proxyTargetValue",
81 : V8InjectedScriptHost::proxyTargetValueCallback,
82 4109 : debuggerExternal);
83 : createDataProperty(context, injectedScriptHost,
84 : toV8StringInternalized(isolate, "keys"),
85 12327 : v8::debug::GetBuiltin(isolate, v8::debug::kObjectKeys));
86 : createDataProperty(
87 : context, injectedScriptHost,
88 : toV8StringInternalized(isolate, "getPrototypeOf"),
89 12327 : v8::debug::GetBuiltin(isolate, v8::debug::kObjectGetPrototypeOf));
90 : createDataProperty(
91 : context, injectedScriptHost,
92 : toV8StringInternalized(isolate, "getOwnPropertyDescriptor"),
93 : v8::debug::GetBuiltin(isolate,
94 12327 : v8::debug::kObjectGetOwnPropertyDescriptor));
95 : createDataProperty(
96 : context, injectedScriptHost,
97 : toV8StringInternalized(isolate, "getOwnPropertyNames"),
98 12327 : v8::debug::GetBuiltin(isolate, v8::debug::kObjectGetOwnPropertyNames));
99 : createDataProperty(
100 : context, injectedScriptHost,
101 : toV8StringInternalized(isolate, "getOwnPropertySymbols"),
102 12327 : v8::debug::GetBuiltin(isolate, v8::debug::kObjectGetOwnPropertySymbols));
103 4109 : return injectedScriptHost;
104 : }
105 :
106 3562089 : void V8InjectedScriptHost::nullifyPrototypeCallback(
107 7124178 : const v8::FunctionCallbackInfo<v8::Value>& info) {
108 3562089 : CHECK(info.Length() == 1);
109 : DCHECK(info[0]->IsObject());
110 7124178 : if (!info[0]->IsObject()) return;
111 : v8::Isolate* isolate = info.GetIsolate();
112 : info[0]
113 : .As<v8::Object>()
114 7124178 : ->SetPrototype(isolate->GetCurrentContext(), v8::Null(isolate))
115 7124178 : .ToChecked();
116 : }
117 :
118 2270048 : void V8InjectedScriptHost::getPropertyCallback(
119 6810144 : const v8::FunctionCallbackInfo<v8::Value>& info) {
120 4540096 : CHECK(info.Length() == 2 && info[1]->IsString());
121 2270048 : if (!info[0]->IsObject()) return;
122 : v8::Isolate* isolate = info.GetIsolate();
123 2270048 : v8::Local<v8::Context> context = isolate->GetCurrentContext();
124 2270048 : v8::TryCatch tryCatch(isolate);
125 : v8::Isolate::DisallowJavascriptExecutionScope throwJs(
126 4540096 : isolate, v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
127 : v8::Local<v8::Value> property;
128 2270048 : if (info[0]
129 : .As<v8::Object>()
130 2270048 : ->Get(context, v8::Local<v8::String>::Cast(info[1]))
131 4540096 : .ToLocal(&property)) {
132 : info.GetReturnValue().Set(property);
133 2270048 : }
134 : }
135 :
136 7590332 : void V8InjectedScriptHost::internalConstructorNameCallback(
137 15094328 : const v8::FunctionCallbackInfo<v8::Value>& info) {
138 22770996 : if (info.Length() < 1 || !info[0]->IsObject()) return;
139 :
140 : v8::Local<v8::Object> object = info[0].As<v8::Object>();
141 7503996 : info.GetReturnValue().Set(object->GetConstructorName());
142 : }
143 :
144 8916 : void V8InjectedScriptHost::formatAccessorsAsProperties(
145 9000 : const v8::FunctionCallbackInfo<v8::Value>& info) {
146 : DCHECK_EQ(info.Length(), 2);
147 : info.GetReturnValue().Set(false);
148 8916 : if (!info[1]->IsFunction()) return;
149 : // Check that function is user-defined.
150 8898 : if (info[1].As<v8::Function>()->ScriptId() != v8::UnboundScript::kNoScriptId)
151 : return;
152 : info.GetReturnValue().Set(
153 168 : unwrapInspector(info)->client()->formatAccessorsAsProperties(info[0]));
154 : }
155 :
156 10415478 : void V8InjectedScriptHost::subtypeCallback(
157 21097028 : const v8::FunctionCallbackInfo<v8::Value>& info) {
158 10681550 : if (info.Length() < 1) return;
159 :
160 : v8::Isolate* isolate = info.GetIsolate();
161 : v8::Local<v8::Value> value = info[0];
162 10415478 : if (value->IsObject()) {
163 : v8::Local<v8::Value> internalType = v8InternalValueTypeFrom(
164 10187910 : isolate->GetCurrentContext(), v8::Local<v8::Object>::Cast(value));
165 10187910 : if (internalType->IsString()) {
166 : info.GetReturnValue().Set(internalType);
167 1044 : return;
168 : }
169 : }
170 10414434 : if (value->IsArray() || value->IsArgumentsObject()) {
171 244182 : info.GetReturnValue().Set(toV8StringInternalized(isolate, "array"));
172 : return;
173 : }
174 10170252 : if (value->IsTypedArray()) {
175 126 : info.GetReturnValue().Set(toV8StringInternalized(isolate, "typedarray"));
176 : return;
177 : }
178 10170126 : if (value->IsDate()) {
179 98 : info.GetReturnValue().Set(toV8StringInternalized(isolate, "date"));
180 : return;
181 : }
182 10170028 : if (value->IsRegExp()) {
183 36 : info.GetReturnValue().Set(toV8StringInternalized(isolate, "regexp"));
184 : return;
185 : }
186 10169992 : if (value->IsMap()) {
187 362 : info.GetReturnValue().Set(toV8StringInternalized(isolate, "map"));
188 : return;
189 : }
190 10169630 : if (value->IsWeakMap()) {
191 180 : info.GetReturnValue().Set(toV8StringInternalized(isolate, "weakmap"));
192 : return;
193 : }
194 10169450 : if (value->IsSet()) {
195 366 : info.GetReturnValue().Set(toV8StringInternalized(isolate, "set"));
196 : return;
197 : }
198 10169084 : if (value->IsWeakSet()) {
199 180 : info.GetReturnValue().Set(toV8StringInternalized(isolate, "weakset"));
200 : return;
201 : }
202 10168904 : if (value->IsMapIterator() || value->IsSetIterator()) {
203 996 : info.GetReturnValue().Set(toV8StringInternalized(isolate, "iterator"));
204 : return;
205 : }
206 10167908 : if (value->IsGeneratorObject()) {
207 450 : info.GetReturnValue().Set(toV8StringInternalized(isolate, "generator"));
208 : return;
209 : }
210 10167458 : if (value->IsNativeError()) {
211 15564 : info.GetReturnValue().Set(toV8StringInternalized(isolate, "error"));
212 : return;
213 : }
214 10151894 : if (value->IsProxy()) {
215 18 : info.GetReturnValue().Set(toV8StringInternalized(isolate, "proxy"));
216 : return;
217 : }
218 10151876 : if (value->IsPromise()) {
219 2470 : info.GetReturnValue().Set(toV8StringInternalized(isolate, "promise"));
220 : return;
221 : }
222 : std::unique_ptr<StringBuffer> subtype =
223 10149406 : unwrapInspector(info)->client()->valueSubtype(value);
224 10149406 : if (subtype) {
225 0 : info.GetReturnValue().Set(toV8String(isolate, subtype->string()));
226 : return;
227 : }
228 : }
229 :
230 366 : void V8InjectedScriptHost::getInternalPropertiesCallback(
231 570 : const v8::FunctionCallbackInfo<v8::Value>& info) {
232 630 : if (info.Length() < 1) return;
233 :
234 366 : std::unordered_set<String16> allowedProperties;
235 1446 : if (info[0]->IsBooleanObject() || info[0]->IsNumberObject() ||
236 1068 : info[0]->IsStringObject() || info[0]->IsSymbolObject()) {
237 48 : allowedProperties.insert(String16("[[PrimitiveValue]]"));
238 342 : } else if (info[0]->IsPromise()) {
239 36 : allowedProperties.insert(String16("[[PromiseStatus]]"));
240 36 : allowedProperties.insert(String16("[[PromiseValue]]"));
241 324 : } else if (info[0]->IsGeneratorObject()) {
242 12 : allowedProperties.insert(String16("[[GeneratorStatus]]"));
243 630 : } else if (info[0]->IsMapIterator() || info[0]->IsSetIterator()) {
244 24 : allowedProperties.insert(String16("[[IteratorHasMore]]"));
245 24 : allowedProperties.insert(String16("[[IteratorIndex]]"));
246 24 : allowedProperties.insert(String16("[[IteratorKind]]"));
247 24 : allowedProperties.insert(String16("[[Entries]]"));
248 1170 : } else if (info[0]->IsMap() || info[0]->IsWeakMap() || info[0]->IsSet() ||
249 270 : info[0]->IsWeakSet()) {
250 84 : allowedProperties.insert(String16("[[Entries]]"));
251 : }
252 366 : if (!allowedProperties.size()) return;
253 :
254 : v8::Isolate* isolate = info.GetIsolate();
255 : v8::Local<v8::Array> allProperties;
256 102 : if (!unwrapInspector(info)
257 : ->debugger()
258 102 : ->internalProperties(isolate->GetCurrentContext(), info[0])
259 306 : .ToLocal(&allProperties) ||
260 204 : !allProperties->IsArray() || allProperties->Length() % 2 != 0)
261 : return;
262 :
263 : {
264 102 : v8::Local<v8::Context> context = isolate->GetCurrentContext();
265 102 : v8::TryCatch tryCatch(isolate);
266 : v8::Isolate::DisallowJavascriptExecutionScope throwJs(
267 : isolate,
268 204 : v8::Isolate::DisallowJavascriptExecutionScope::THROW_ON_FAILURE);
269 :
270 102 : v8::Local<v8::Array> properties = v8::Array::New(isolate);
271 102 : if (tryCatch.HasCaught()) return;
272 :
273 : uint32_t outputIndex = 0;
274 180 : for (uint32_t i = 0; i < allProperties->Length(); i += 2) {
275 : v8::Local<v8::Value> key;
276 384 : if (!allProperties->Get(context, i).ToLocal(&key)) continue;
277 180 : if (tryCatch.HasCaught()) {
278 0 : tryCatch.Reset();
279 0 : continue;
280 : }
281 180 : String16 keyString = toProtocolStringWithTypeCheck(key);
282 360 : if (keyString.isEmpty() ||
283 : allowedProperties.find(keyString) == allowedProperties.end())
284 : continue;
285 : v8::Local<v8::Value> value;
286 312 : if (!allProperties->Get(context, i + 1).ToLocal(&value)) continue;
287 156 : if (tryCatch.HasCaught()) {
288 0 : tryCatch.Reset();
289 0 : continue;
290 : }
291 156 : createDataProperty(context, properties, outputIndex++, key);
292 156 : createDataProperty(context, properties, outputIndex++, value);
293 : }
294 102 : info.GetReturnValue().Set(properties);
295 : }
296 : }
297 :
298 24 : void V8InjectedScriptHost::objectHasOwnPropertyCallback(
299 72 : const v8::FunctionCallbackInfo<v8::Value>& info) {
300 96 : if (info.Length() < 2 || !info[0]->IsObject() || !info[1]->IsString()) return;
301 : bool result = info[0]
302 : .As<v8::Object>()
303 : ->HasOwnProperty(info.GetIsolate()->GetCurrentContext(),
304 48 : v8::Local<v8::String>::Cast(info[1]))
305 48 : .FromMaybe(false);
306 : info.GetReturnValue().Set(v8::Boolean::New(info.GetIsolate(), result));
307 : }
308 :
309 3780575 : void V8InjectedScriptHost::bindCallback(
310 15122300 : const v8::FunctionCallbackInfo<v8::Value>& info) {
311 7561150 : if (info.Length() < 2 || !info[1]->IsString()) return;
312 : InjectedScriptNative* injectedScriptNative =
313 : InjectedScriptNative::fromInjectedScriptHost(info.GetIsolate(),
314 3780575 : info.Holder());
315 3780575 : if (!injectedScriptNative) return;
316 :
317 3780575 : v8::Local<v8::Context> context = info.GetIsolate()->GetCurrentContext();
318 : v8::Local<v8::String> v8groupName =
319 3780575 : info[1]->ToString(context).ToLocalChecked();
320 3780575 : String16 groupName = toProtocolStringWithTypeCheck(v8groupName);
321 3780575 : int id = injectedScriptNative->bind(info[0], groupName);
322 : info.GetReturnValue().Set(id);
323 : }
324 :
325 0 : void V8InjectedScriptHost::proxyTargetValueCallback(
326 0 : const v8::FunctionCallbackInfo<v8::Value>& info) {
327 0 : if (info.Length() != 1 || !info[0]->IsProxy()) {
328 0 : UNREACHABLE();
329 : return;
330 : }
331 : v8::Local<v8::Object> target = info[0].As<v8::Proxy>();
332 0 : while (target->IsProxy())
333 0 : target = v8::Local<v8::Proxy>::Cast(target)->GetTarget();
334 : info.GetReturnValue().Set(target);
335 0 : }
336 :
337 : } // namespace v8_inspector
|