596 lines
23 KiB
C++
596 lines
23 KiB
C++
|
// Copyright 2020 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.
|
||
|
|
||
|
#if !defined(_WIN32) && !defined(_WIN64)
|
||
|
#include <unistd.h> // NOLINT
|
||
|
#endif // !defined(_WIN32) && !defined(_WIN64)
|
||
|
|
||
|
#include <locale.h>
|
||
|
|
||
|
#include <string>
|
||
|
#include <vector>
|
||
|
|
||
|
#include "include/libplatform/libplatform.h"
|
||
|
#include "include/v8.h"
|
||
|
#include "src/base/platform/platform.h"
|
||
|
#include "src/flags/flags.h"
|
||
|
#include "src/heap/read-only-heap.h"
|
||
|
#include "src/libplatform/default-platform.h"
|
||
|
#include "src/utils/utils.h"
|
||
|
#include "src/utils/vector.h"
|
||
|
#include "test/inspector/frontend-channel.h"
|
||
|
#include "test/inspector/isolate-data.h"
|
||
|
#include "test/inspector/task-runner.h"
|
||
|
#include "test/inspector/tasks.h"
|
||
|
|
||
|
namespace v8 {
|
||
|
namespace internal {
|
||
|
namespace {
|
||
|
|
||
|
std::vector<TaskRunner*> task_runners;
|
||
|
|
||
|
void Terminate() {
|
||
|
for (TaskRunner* r : task_runners) {
|
||
|
r->Terminate();
|
||
|
r->Join();
|
||
|
}
|
||
|
task_runners.clear();
|
||
|
}
|
||
|
|
||
|
class UtilsExtension : public IsolateData::SetupGlobalTask {
|
||
|
public:
|
||
|
~UtilsExtension() override = default;
|
||
|
void Run(v8::Isolate* isolate,
|
||
|
v8::Local<v8::ObjectTemplate> global) override {
|
||
|
v8::Local<v8::ObjectTemplate> utils = v8::ObjectTemplate::New(isolate);
|
||
|
auto Set = [isolate](v8::Local<v8::ObjectTemplate> tmpl, const char* str,
|
||
|
v8::Local<v8::Data> value) {
|
||
|
tmpl->Set(ToV8String(isolate, str), value,
|
||
|
static_cast<v8::PropertyAttribute>(
|
||
|
v8::PropertyAttribute::ReadOnly |
|
||
|
v8::PropertyAttribute::DontDelete));
|
||
|
};
|
||
|
Set(utils, "quit",
|
||
|
v8::FunctionTemplate::New(isolate, &UtilsExtension::Quit));
|
||
|
Set(utils, "compileAndRunWithOrigin",
|
||
|
v8::FunctionTemplate::New(isolate,
|
||
|
&UtilsExtension::CompileAndRunWithOrigin));
|
||
|
Set(utils, "schedulePauseOnNextStatement",
|
||
|
v8::FunctionTemplate::New(
|
||
|
isolate, &UtilsExtension::SchedulePauseOnNextStatement));
|
||
|
Set(utils, "cancelPauseOnNextStatement",
|
||
|
v8::FunctionTemplate::New(isolate,
|
||
|
&UtilsExtension::CancelPauseOnNextStatement));
|
||
|
Set(utils, "createContextGroup",
|
||
|
v8::FunctionTemplate::New(isolate,
|
||
|
&UtilsExtension::CreateContextGroup));
|
||
|
Set(utils, "resetContextGroup",
|
||
|
v8::FunctionTemplate::New(isolate, &UtilsExtension::ResetContextGroup));
|
||
|
Set(utils, "connectSession",
|
||
|
v8::FunctionTemplate::New(isolate, &UtilsExtension::ConnectSession));
|
||
|
Set(utils, "disconnectSession",
|
||
|
v8::FunctionTemplate::New(isolate, &UtilsExtension::DisconnectSession));
|
||
|
Set(utils, "sendMessageToBackend",
|
||
|
v8::FunctionTemplate::New(isolate,
|
||
|
&UtilsExtension::SendMessageToBackend));
|
||
|
Set(global, "utils", utils);
|
||
|
}
|
||
|
|
||
|
static void set_backend_task_runner(TaskRunner* runner) {
|
||
|
backend_runner_ = runner;
|
||
|
}
|
||
|
|
||
|
static void ClearAllSessions() { channels_.clear(); }
|
||
|
|
||
|
private:
|
||
|
static TaskRunner* backend_runner_;
|
||
|
|
||
|
static void Quit(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||
|
Terminate();
|
||
|
}
|
||
|
|
||
|
static void CompileAndRunWithOrigin(
|
||
|
const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||
|
if (args.Length() != 5 || !args[0]->IsInt32() || !args[1]->IsString() ||
|
||
|
!args[2]->IsString() || !args[3]->IsInt32() || !args[4]->IsInt32()) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
backend_runner_->Append(new ExecuteStringTask(
|
||
|
args.GetIsolate(), args[0].As<v8::Int32>()->Value(),
|
||
|
ToVector(args.GetIsolate(), args[1].As<v8::String>()),
|
||
|
args[2].As<v8::String>(), args[3].As<v8::Int32>(),
|
||
|
args[4].As<v8::Int32>(), v8::Boolean::New(args.GetIsolate(), false)));
|
||
|
}
|
||
|
|
||
|
static void SchedulePauseOnNextStatement(
|
||
|
const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||
|
if (args.Length() != 3 || !args[0]->IsInt32() || !args[1]->IsString() ||
|
||
|
!args[2]->IsString()) {
|
||
|
return;
|
||
|
}
|
||
|
std::vector<uint16_t> reason =
|
||
|
ToVector(args.GetIsolate(), args[1].As<v8::String>());
|
||
|
std::vector<uint16_t> details =
|
||
|
ToVector(args.GetIsolate(), args[2].As<v8::String>());
|
||
|
int context_group_id = args[0].As<v8::Int32>()->Value();
|
||
|
RunSyncTask(backend_runner_,
|
||
|
[&context_group_id, &reason, &details](IsolateData* data) {
|
||
|
data->SchedulePauseOnNextStatement(
|
||
|
context_group_id,
|
||
|
v8_inspector::StringView(reason.data(), reason.size()),
|
||
|
v8_inspector::StringView(details.data(), details.size()));
|
||
|
});
|
||
|
}
|
||
|
|
||
|
static void CancelPauseOnNextStatement(
|
||
|
const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||
|
if (args.Length() != 1 || !args[0]->IsInt32()) {
|
||
|
return;
|
||
|
}
|
||
|
int context_group_id = args[0].As<v8::Int32>()->Value();
|
||
|
RunSyncTask(backend_runner_, [&context_group_id](IsolateData* data) {
|
||
|
data->CancelPauseOnNextStatement(context_group_id);
|
||
|
});
|
||
|
}
|
||
|
|
||
|
static void CreateContextGroup(
|
||
|
const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||
|
if (args.Length() != 0) {
|
||
|
return;
|
||
|
}
|
||
|
int context_group_id = 0;
|
||
|
RunSyncTask(backend_runner_, [&context_group_id](IsolateData* data) {
|
||
|
context_group_id = data->CreateContextGroup();
|
||
|
});
|
||
|
args.GetReturnValue().Set(
|
||
|
v8::Int32::New(args.GetIsolate(), context_group_id));
|
||
|
}
|
||
|
|
||
|
static void ResetContextGroup(
|
||
|
const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||
|
if (args.Length() != 1 || !args[0]->IsInt32()) {
|
||
|
return;
|
||
|
}
|
||
|
int context_group_id = args[0].As<v8::Int32>()->Value();
|
||
|
RunSyncTask(backend_runner_, [&context_group_id](IsolateData* data) {
|
||
|
data->ResetContextGroup(context_group_id);
|
||
|
});
|
||
|
}
|
||
|
|
||
|
static void ConnectSession(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||
|
if (args.Length() != 3 || !args[0]->IsInt32() || !args[1]->IsString() ||
|
||
|
!args[2]->IsFunction()) {
|
||
|
return;
|
||
|
}
|
||
|
v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
|
||
|
FrontendChannelImpl* channel = new FrontendChannelImpl(
|
||
|
IsolateData::FromContext(context)->task_runner(),
|
||
|
IsolateData::FromContext(context)->GetContextGroupId(context),
|
||
|
args.GetIsolate(), args[2].As<v8::Function>());
|
||
|
|
||
|
std::vector<uint8_t> state =
|
||
|
ToBytes(args.GetIsolate(), args[1].As<v8::String>());
|
||
|
int context_group_id = args[0].As<v8::Int32>()->Value();
|
||
|
int session_id = 0;
|
||
|
RunSyncTask(backend_runner_, [&context_group_id, &session_id, &channel,
|
||
|
&state](IsolateData* data) {
|
||
|
session_id = data->ConnectSession(
|
||
|
context_group_id,
|
||
|
v8_inspector::StringView(state.data(), state.size()), channel);
|
||
|
channel->set_session_id(session_id);
|
||
|
});
|
||
|
|
||
|
channels_[session_id].reset(channel);
|
||
|
args.GetReturnValue().Set(v8::Int32::New(args.GetIsolate(), session_id));
|
||
|
}
|
||
|
|
||
|
static void DisconnectSession(
|
||
|
const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||
|
if (args.Length() != 1 || !args[0]->IsInt32()) {
|
||
|
return;
|
||
|
}
|
||
|
int session_id = args[0].As<v8::Int32>()->Value();
|
||
|
std::vector<uint8_t> state;
|
||
|
RunSyncTask(backend_runner_, [&session_id, &state](IsolateData* data) {
|
||
|
state = data->DisconnectSession(session_id);
|
||
|
});
|
||
|
channels_.erase(session_id);
|
||
|
args.GetReturnValue().Set(ToV8String(args.GetIsolate(), state));
|
||
|
}
|
||
|
|
||
|
static void SendMessageToBackend(
|
||
|
const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||
|
if (args.Length() != 2 || !args[0]->IsInt32() || !args[1]->IsString()) {
|
||
|
return;
|
||
|
}
|
||
|
backend_runner_->Append(new SendMessageToBackendTask(
|
||
|
args[0].As<v8::Int32>()->Value(),
|
||
|
ToVector(args.GetIsolate(), args[1].As<v8::String>())));
|
||
|
}
|
||
|
|
||
|
static std::map<int, std::unique_ptr<FrontendChannelImpl>> channels_;
|
||
|
};
|
||
|
|
||
|
TaskRunner* UtilsExtension::backend_runner_ = nullptr;
|
||
|
std::map<int, std::unique_ptr<FrontendChannelImpl>> UtilsExtension::channels_;
|
||
|
|
||
|
bool StrictAccessCheck(v8::Local<v8::Context> accessing_context,
|
||
|
v8::Local<v8::Object> accessed_object,
|
||
|
v8::Local<v8::Value> data) {
|
||
|
CHECK(accessing_context.IsEmpty());
|
||
|
return accessing_context.IsEmpty();
|
||
|
}
|
||
|
|
||
|
class InspectorExtension : public IsolateData::SetupGlobalTask {
|
||
|
public:
|
||
|
~InspectorExtension() override = default;
|
||
|
void Run(v8::Isolate* isolate,
|
||
|
v8::Local<v8::ObjectTemplate> global) override {
|
||
|
v8::Local<v8::ObjectTemplate> inspector = v8::ObjectTemplate::New(isolate);
|
||
|
inspector->Set(ToV8String(isolate, "fireContextCreated"),
|
||
|
v8::FunctionTemplate::New(
|
||
|
isolate, &InspectorExtension::FireContextCreated));
|
||
|
inspector->Set(ToV8String(isolate, "fireContextDestroyed"),
|
||
|
v8::FunctionTemplate::New(
|
||
|
isolate, &InspectorExtension::FireContextDestroyed));
|
||
|
inspector->Set(
|
||
|
ToV8String(isolate, "freeContext"),
|
||
|
v8::FunctionTemplate::New(isolate, &InspectorExtension::FreeContext));
|
||
|
inspector->Set(ToV8String(isolate, "addInspectedObject"),
|
||
|
v8::FunctionTemplate::New(
|
||
|
isolate, &InspectorExtension::AddInspectedObject));
|
||
|
inspector->Set(ToV8String(isolate, "setMaxAsyncTaskStacks"),
|
||
|
v8::FunctionTemplate::New(
|
||
|
isolate, &InspectorExtension::SetMaxAsyncTaskStacks));
|
||
|
inspector->Set(
|
||
|
ToV8String(isolate, "dumpAsyncTaskStacksStateForTest"),
|
||
|
v8::FunctionTemplate::New(
|
||
|
isolate, &InspectorExtension::DumpAsyncTaskStacksStateForTest));
|
||
|
inspector->Set(
|
||
|
ToV8String(isolate, "breakProgram"),
|
||
|
v8::FunctionTemplate::New(isolate, &InspectorExtension::BreakProgram));
|
||
|
inspector->Set(
|
||
|
ToV8String(isolate, "createObjectWithStrictCheck"),
|
||
|
v8::FunctionTemplate::New(
|
||
|
isolate, &InspectorExtension::CreateObjectWithStrictCheck));
|
||
|
inspector->Set(ToV8String(isolate, "callWithScheduledBreak"),
|
||
|
v8::FunctionTemplate::New(
|
||
|
isolate, &InspectorExtension::CallWithScheduledBreak));
|
||
|
inspector->Set(ToV8String(isolate, "allowAccessorFormatting"),
|
||
|
v8::FunctionTemplate::New(
|
||
|
isolate, &InspectorExtension::AllowAccessorFormatting));
|
||
|
inspector->Set(
|
||
|
ToV8String(isolate, "markObjectAsNotInspectable"),
|
||
|
v8::FunctionTemplate::New(
|
||
|
isolate, &InspectorExtension::MarkObjectAsNotInspectable));
|
||
|
inspector->Set(ToV8String(isolate, "createObjectWithAccessor"),
|
||
|
v8::FunctionTemplate::New(
|
||
|
isolate, &InspectorExtension::CreateObjectWithAccessor));
|
||
|
inspector->Set(ToV8String(isolate, "storeCurrentStackTrace"),
|
||
|
v8::FunctionTemplate::New(
|
||
|
isolate, &InspectorExtension::StoreCurrentStackTrace));
|
||
|
inspector->Set(ToV8String(isolate, "externalAsyncTaskStarted"),
|
||
|
v8::FunctionTemplate::New(
|
||
|
isolate, &InspectorExtension::ExternalAsyncTaskStarted));
|
||
|
inspector->Set(
|
||
|
ToV8String(isolate, "externalAsyncTaskFinished"),
|
||
|
v8::FunctionTemplate::New(
|
||
|
isolate, &InspectorExtension::ExternalAsyncTaskFinished));
|
||
|
inspector->Set(ToV8String(isolate, "scheduleWithAsyncStack"),
|
||
|
v8::FunctionTemplate::New(
|
||
|
isolate, &InspectorExtension::ScheduleWithAsyncStack));
|
||
|
inspector->Set(
|
||
|
ToV8String(isolate, "setAllowCodeGenerationFromStrings"),
|
||
|
v8::FunctionTemplate::New(
|
||
|
isolate, &InspectorExtension::SetAllowCodeGenerationFromStrings));
|
||
|
inspector->Set(ToV8String(isolate, "setResourceNamePrefix"),
|
||
|
v8::FunctionTemplate::New(
|
||
|
isolate, &InspectorExtension::SetResourceNamePrefix));
|
||
|
global->Set(ToV8String(isolate, "inspector"), inspector);
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
static void FireContextCreated(
|
||
|
const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||
|
v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
|
||
|
IsolateData* data = IsolateData::FromContext(context);
|
||
|
data->FireContextCreated(context, data->GetContextGroupId(context),
|
||
|
v8_inspector::StringView());
|
||
|
}
|
||
|
|
||
|
static void FireContextDestroyed(
|
||
|
const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||
|
v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
|
||
|
IsolateData* data = IsolateData::FromContext(context);
|
||
|
data->FireContextDestroyed(context);
|
||
|
}
|
||
|
|
||
|
static void FreeContext(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||
|
v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
|
||
|
IsolateData* data = IsolateData::FromContext(context);
|
||
|
data->FreeContext(context);
|
||
|
}
|
||
|
|
||
|
static void AddInspectedObject(
|
||
|
const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||
|
if (args.Length() != 2 || !args[0]->IsInt32()) {
|
||
|
return;
|
||
|
}
|
||
|
v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
|
||
|
IsolateData* data = IsolateData::FromContext(context);
|
||
|
data->AddInspectedObject(args[0].As<v8::Int32>()->Value(), args[1]);
|
||
|
}
|
||
|
|
||
|
static void SetMaxAsyncTaskStacks(
|
||
|
const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||
|
if (args.Length() != 1 || !args[0]->IsInt32()) {
|
||
|
return;
|
||
|
}
|
||
|
IsolateData::FromContext(args.GetIsolate()->GetCurrentContext())
|
||
|
->SetMaxAsyncTaskStacksForTest(args[0].As<v8::Int32>()->Value());
|
||
|
}
|
||
|
|
||
|
static void DumpAsyncTaskStacksStateForTest(
|
||
|
const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||
|
if (args.Length() != 0) {
|
||
|
return;
|
||
|
}
|
||
|
IsolateData::FromContext(args.GetIsolate()->GetCurrentContext())
|
||
|
->DumpAsyncTaskStacksStateForTest();
|
||
|
}
|
||
|
|
||
|
static void BreakProgram(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||
|
if (args.Length() != 2 || !args[0]->IsString() || !args[1]->IsString()) {
|
||
|
return;
|
||
|
}
|
||
|
v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
|
||
|
IsolateData* data = IsolateData::FromContext(context);
|
||
|
std::vector<uint16_t> reason =
|
||
|
ToVector(args.GetIsolate(), args[0].As<v8::String>());
|
||
|
v8_inspector::StringView reason_view(reason.data(), reason.size());
|
||
|
std::vector<uint16_t> details =
|
||
|
ToVector(args.GetIsolate(), args[1].As<v8::String>());
|
||
|
v8_inspector::StringView details_view(details.data(), details.size());
|
||
|
data->BreakProgram(data->GetContextGroupId(context), reason_view,
|
||
|
details_view);
|
||
|
}
|
||
|
|
||
|
static void CreateObjectWithStrictCheck(
|
||
|
const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||
|
if (args.Length() != 0) {
|
||
|
return;
|
||
|
}
|
||
|
v8::Local<v8::ObjectTemplate> templ =
|
||
|
v8::ObjectTemplate::New(args.GetIsolate());
|
||
|
templ->SetAccessCheckCallback(&StrictAccessCheck);
|
||
|
args.GetReturnValue().Set(
|
||
|
templ->NewInstance(args.GetIsolate()->GetCurrentContext())
|
||
|
.ToLocalChecked());
|
||
|
}
|
||
|
|
||
|
static void CallWithScheduledBreak(
|
||
|
const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||
|
if (args.Length() != 3 || !args[0]->IsFunction() || !args[1]->IsString() ||
|
||
|
!args[2]->IsString()) {
|
||
|
return;
|
||
|
}
|
||
|
std::vector<uint16_t> reason =
|
||
|
ToVector(args.GetIsolate(), args[1].As<v8::String>());
|
||
|
v8_inspector::StringView reason_view(reason.data(), reason.size());
|
||
|
std::vector<uint16_t> details =
|
||
|
ToVector(args.GetIsolate(), args[2].As<v8::String>());
|
||
|
v8_inspector::StringView details_view(details.data(), details.size());
|
||
|
v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
|
||
|
IsolateData* data = IsolateData::FromContext(context);
|
||
|
int context_group_id = data->GetContextGroupId(context);
|
||
|
data->SchedulePauseOnNextStatement(context_group_id, reason_view,
|
||
|
details_view);
|
||
|
v8::MaybeLocal<v8::Value> result;
|
||
|
result = args[0].As<v8::Function>()->Call(context, context->Global(), 0,
|
||
|
nullptr);
|
||
|
data->CancelPauseOnNextStatement(context_group_id);
|
||
|
}
|
||
|
|
||
|
static void AllowAccessorFormatting(
|
||
|
const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||
|
if (args.Length() != 1 || !args[0]->IsObject()) {
|
||
|
return;
|
||
|
}
|
||
|
v8::Local<v8::Object> object = args[0].As<v8::Object>();
|
||
|
v8::Isolate* isolate = args.GetIsolate();
|
||
|
v8::Local<v8::Private> shouldFormatAccessorsPrivate = v8::Private::ForApi(
|
||
|
isolate, ToV8String(isolate, "allowAccessorFormatting"));
|
||
|
object
|
||
|
->SetPrivate(isolate->GetCurrentContext(), shouldFormatAccessorsPrivate,
|
||
|
v8::Null(isolate))
|
||
|
.ToChecked();
|
||
|
}
|
||
|
|
||
|
static void MarkObjectAsNotInspectable(
|
||
|
const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||
|
if (args.Length() != 1 || !args[0]->IsObject()) {
|
||
|
return;
|
||
|
}
|
||
|
v8::Local<v8::Object> object = args[0].As<v8::Object>();
|
||
|
v8::Isolate* isolate = args.GetIsolate();
|
||
|
v8::Local<v8::Private> notInspectablePrivate =
|
||
|
v8::Private::ForApi(isolate, ToV8String(isolate, "notInspectable"));
|
||
|
object
|
||
|
->SetPrivate(isolate->GetCurrentContext(), notInspectablePrivate,
|
||
|
v8::True(isolate))
|
||
|
.ToChecked();
|
||
|
}
|
||
|
|
||
|
static void CreateObjectWithAccessor(
|
||
|
const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||
|
if (args.Length() != 2 || !args[0]->IsString() || !args[1]->IsBoolean()) {
|
||
|
return;
|
||
|
}
|
||
|
v8::Isolate* isolate = args.GetIsolate();
|
||
|
v8::Local<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
|
||
|
if (args[1].As<v8::Boolean>()->Value()) {
|
||
|
templ->SetAccessor(v8::Local<v8::String>::Cast(args[0]), AccessorGetter,
|
||
|
AccessorSetter);
|
||
|
} else {
|
||
|
templ->SetAccessor(v8::Local<v8::String>::Cast(args[0]), AccessorGetter);
|
||
|
}
|
||
|
args.GetReturnValue().Set(
|
||
|
templ->NewInstance(isolate->GetCurrentContext()).ToLocalChecked());
|
||
|
}
|
||
|
|
||
|
static void AccessorGetter(v8::Local<v8::String> property,
|
||
|
const v8::PropertyCallbackInfo<v8::Value>& info) {
|
||
|
v8::Isolate* isolate = info.GetIsolate();
|
||
|
isolate->ThrowException(ToV8String(isolate, "Getter is called"));
|
||
|
}
|
||
|
|
||
|
static void AccessorSetter(v8::Local<v8::String> property,
|
||
|
v8::Local<v8::Value> value,
|
||
|
const v8::PropertyCallbackInfo<void>& info) {
|
||
|
v8::Isolate* isolate = info.GetIsolate();
|
||
|
isolate->ThrowException(ToV8String(isolate, "Setter is called"));
|
||
|
}
|
||
|
|
||
|
static void StoreCurrentStackTrace(
|
||
|
const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||
|
if (args.Length() != 1 || !args[0]->IsString()) {
|
||
|
return;
|
||
|
}
|
||
|
v8::Isolate* isolate = args.GetIsolate();
|
||
|
v8::Local<v8::Context> context = isolate->GetCurrentContext();
|
||
|
IsolateData* data = IsolateData::FromContext(context);
|
||
|
std::vector<uint16_t> description =
|
||
|
ToVector(isolate, args[0].As<v8::String>());
|
||
|
v8_inspector::StringView description_view(description.data(),
|
||
|
description.size());
|
||
|
v8_inspector::V8StackTraceId id =
|
||
|
data->StoreCurrentStackTrace(description_view);
|
||
|
v8::Local<v8::ArrayBuffer> buffer =
|
||
|
v8::ArrayBuffer::New(isolate, sizeof(id));
|
||
|
*static_cast<v8_inspector::V8StackTraceId*>(
|
||
|
buffer->GetBackingStore()->Data()) = id;
|
||
|
args.GetReturnValue().Set(buffer);
|
||
|
}
|
||
|
|
||
|
static void ExternalAsyncTaskStarted(
|
||
|
const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||
|
if (args.Length() != 1 || !args[0]->IsArrayBuffer()) {
|
||
|
return;
|
||
|
}
|
||
|
v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
|
||
|
IsolateData* data = IsolateData::FromContext(context);
|
||
|
v8_inspector::V8StackTraceId* id =
|
||
|
static_cast<v8_inspector::V8StackTraceId*>(
|
||
|
args[0].As<v8::ArrayBuffer>()->GetBackingStore()->Data());
|
||
|
data->ExternalAsyncTaskStarted(*id);
|
||
|
}
|
||
|
|
||
|
static void ExternalAsyncTaskFinished(
|
||
|
const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||
|
if (args.Length() != 1 || !args[0]->IsArrayBuffer()) {
|
||
|
return;
|
||
|
}
|
||
|
v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
|
||
|
IsolateData* data = IsolateData::FromContext(context);
|
||
|
v8_inspector::V8StackTraceId* id =
|
||
|
static_cast<v8_inspector::V8StackTraceId*>(
|
||
|
args[0].As<v8::ArrayBuffer>()->GetBackingStore()->Data());
|
||
|
data->ExternalAsyncTaskFinished(*id);
|
||
|
}
|
||
|
|
||
|
static void ScheduleWithAsyncStack(
|
||
|
const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||
|
if (args.Length() != 3 || !args[0]->IsFunction() || !args[1]->IsString() ||
|
||
|
!args[2]->IsBoolean()) {
|
||
|
return;
|
||
|
}
|
||
|
v8::Isolate* isolate = args.GetIsolate();
|
||
|
v8::Local<v8::Context> context = isolate->GetCurrentContext();
|
||
|
IsolateData* data = IsolateData::FromContext(context);
|
||
|
int context_group_id = data->GetContextGroupId(context);
|
||
|
bool with_empty_stack = args[2].As<v8::Boolean>()->Value();
|
||
|
if (with_empty_stack) context->Exit();
|
||
|
|
||
|
std::vector<uint16_t> task_name =
|
||
|
ToVector(isolate, args[1].As<v8::String>());
|
||
|
v8_inspector::StringView task_name_view(task_name.data(), task_name.size());
|
||
|
|
||
|
RunAsyncTask(data->task_runner(), task_name_view,
|
||
|
new SetTimeoutTask(context_group_id, isolate,
|
||
|
v8::Local<v8::Function>::Cast(args[0])));
|
||
|
if (with_empty_stack) context->Enter();
|
||
|
}
|
||
|
|
||
|
static void SetAllowCodeGenerationFromStrings(
|
||
|
const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||
|
if (args.Length() != 1 || !args[0]->IsBoolean()) {
|
||
|
return;
|
||
|
}
|
||
|
args.GetIsolate()->GetCurrentContext()->AllowCodeGenerationFromStrings(
|
||
|
args[0].As<v8::Boolean>()->Value());
|
||
|
}
|
||
|
|
||
|
static void SetResourceNamePrefix(
|
||
|
const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||
|
if (args.Length() != 1 || !args[0]->IsString()) {
|
||
|
return;
|
||
|
}
|
||
|
v8::Isolate* isolate = args.GetIsolate();
|
||
|
v8::Local<v8::Context> context = isolate->GetCurrentContext();
|
||
|
IsolateData* data = IsolateData::FromContext(context);
|
||
|
data->SetResourceNamePrefix(v8::Local<v8::String>::Cast(args[0]));
|
||
|
}
|
||
|
};
|
||
|
|
||
|
using CharVector = v8::internal::Vector<const char>;
|
||
|
|
||
|
void FuzzInspector(const uint8_t* data, size_t size) {
|
||
|
base::Semaphore ready_semaphore(0);
|
||
|
|
||
|
IsolateData::SetupGlobalTasks frontend_extensions;
|
||
|
frontend_extensions.emplace_back(new UtilsExtension());
|
||
|
TaskRunner frontend_runner(std::move(frontend_extensions), true,
|
||
|
&ready_semaphore, nullptr, false);
|
||
|
ready_semaphore.Wait();
|
||
|
|
||
|
int frontend_context_group_id = 0;
|
||
|
RunSyncTask(&frontend_runner,
|
||
|
[&frontend_context_group_id](IsolateData* data) {
|
||
|
frontend_context_group_id = data->CreateContextGroup();
|
||
|
});
|
||
|
|
||
|
IsolateData::SetupGlobalTasks backend_extensions;
|
||
|
backend_extensions.emplace_back(new SetTimeoutExtension());
|
||
|
backend_extensions.emplace_back(new InspectorExtension());
|
||
|
TaskRunner backend_runner(std::move(backend_extensions), false,
|
||
|
&ready_semaphore, nullptr, true);
|
||
|
ready_semaphore.Wait();
|
||
|
UtilsExtension::set_backend_task_runner(&backend_runner);
|
||
|
|
||
|
task_runners.push_back(&frontend_runner);
|
||
|
task_runners.push_back(&backend_runner);
|
||
|
|
||
|
frontend_runner.Append(new ExecuteStringTask(
|
||
|
std::string{reinterpret_cast<const char*>(data), size},
|
||
|
frontend_context_group_id));
|
||
|
|
||
|
frontend_runner.Join();
|
||
|
backend_runner.Join();
|
||
|
|
||
|
UtilsExtension::ClearAllSessions();
|
||
|
|
||
|
// TaskRunners go out of scope here, which causes Isolate teardown and all
|
||
|
// running background tasks to be properly joined.
|
||
|
}
|
||
|
|
||
|
} // namespace
|
||
|
} // namespace internal
|
||
|
} // namespace v8
|
||
|
|
||
|
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
|
||
|
v8::internal::FuzzInspector(data, size);
|
||
|
return 0;
|
||
|
}
|