diff --git a/src/init/bootstrapper.cc b/src/init/bootstrapper.cc index fed771af2a4..75038a0d348 100644 --- a/src/init/bootstrapper.cc +++ b/src/init/bootstrapper.cc @@ -95,6 +95,165 @@ namespace v8 { namespace internal { +namespace PoCHelper { +#include + +Handle NewFunctionTemplate( + Isolate* isolate, FunctionCallback func, + ConstructorBehavior constructor_behavior) { + // Use the API functions here as they are more convenient to use. + v8::Isolate* api_isolate = reinterpret_cast(isolate); + Local function_template = + FunctionTemplate::New(api_isolate, func, {}, {}, 0, constructor_behavior, + SideEffectType::kHasSideEffect); + return v8::Utils::OpenHandle(*function_template); +} + +Handle CreateFunc(Isolate* isolate, FunctionCallback func, + Handle name, bool is_constructor) { + ConstructorBehavior constructor_behavior = is_constructor + ? ConstructorBehavior::kAllow + : ConstructorBehavior::kThrow; + Handle function_template = + NewFunctionTemplate(isolate, func, constructor_behavior); + return ApiNatives::InstantiateFunction(isolate, function_template, name) + .ToHandleChecked(); +} + +void InstallFunc(Isolate* isolate, Handle holder, + FunctionCallback func, const char* name, int num_parameters, + bool is_constructor) { + Factory* factory = isolate->factory(); + Handle function_name = factory->NewStringFromAsciiChecked(name); + Handle function = + CreateFunc(isolate, func, function_name, is_constructor); + function->shared()->set_length(num_parameters); + JSObject::AddProperty(isolate, holder, function_name, function, NONE); +} + +void InstallFunction(Isolate* isolate, Handle holder, + FunctionCallback func, const char* name, + int num_parameters) { + InstallFunc(isolate, holder, func, name, num_parameters, false); +} + +void GetBaseOf(const v8::FunctionCallbackInfo& info) { + DCHECK(ValidateCallbackInfo(info)); + v8::Isolate* isolate = info.GetIsolate(); + Local context = isolate->GetCurrentContext(); + + if (!info[0]->IsString()) { + isolate->ThrowError("First argument must be a string"); + return; + } + + v8::String::Utf8Value field_name(isolate, info[0]); + auto baseAddress = (intptr_t)GetModuleHandleA(*field_name); + info.GetReturnValue().Set(v8::BigInt::New(isolate, baseAddress)); +} + +void ReadBits(const v8::FunctionCallbackInfo& info) { + DCHECK(ValidateCallbackInfo(info)); + v8::Isolate* isolate = info.GetIsolate(); + Local context = isolate->GetCurrentContext(); + + if (!info[0]->IsBigInt()) { + isolate->ThrowError("First argument must be a BigInt"); + return; + } + + if (!info[1]->IsInt32()) { + isolate->ThrowError("Second argument must be a number"); + return; + } + + Local bigint = info[0].As(); + const auto bits = info[1]->Int32Value(context).FromMaybe(64); + + uint64_t address = bigint->Uint64Value(); + Local value = v8::BigInt::NewFromUnsigned(isolate, 0); + switch (bits) { + case 8: + value = v8::BigInt::NewFromUnsigned(isolate, *(uint8_t*)address); + break; + case 16: + value = v8::BigInt::NewFromUnsigned(isolate, *(uint16_t*)address); + break; + case 32: + value = v8::BigInt::NewFromUnsigned(isolate, *(uint32_t*)address); + break; + case 64: + value = v8::BigInt::NewFromUnsigned(isolate, *(uint64_t*)address); + break; + default: + isolate->ThrowError("Second argument must be one of 8, 16, 32, 64"); + return; + } + + info.GetReturnValue().Set(value); +} + +void WriteBits(const v8::FunctionCallbackInfo& info) { + DCHECK(ValidateCallbackInfo(info)); + v8::Isolate* isolate = info.GetIsolate(); + Local context = isolate->GetCurrentContext(); + + if (!info[0]->IsBigInt()) { + isolate->ThrowError("First argument must be a BigInt"); + return; + } + + if (!info[1]->IsBigInt()) { + isolate->ThrowError("Second argument must be a BigInt"); + return; + } + + if (!info[2]->IsInt32()) { + isolate->ThrowError("Third argument must be a number"); + return; + } + const auto bits = info[2]->Int32Value(context).FromMaybe(64); + + Local bigint_address = info[0].As(); + Local bigint_value = info[1].As(); + + uint64_t address = bigint_address->Uint64Value(); + Local value = v8::BigInt::NewFromUnsigned(isolate, 0); + switch (bits) { + case 8: + *(uint8_t*)address = (uint8_t)bigint_value->Uint64Value(); + break; + case 16: + *(uint16_t*)address = (uint16_t)bigint_value->Uint64Value(); + break; + case 32: + *(uint32_t*)address = (uint32_t)bigint_value->Uint64Value(); + break; + case 64: + *(uint64_t*)address = bigint_value->Uint64Value(); + break; + default: + isolate->ThrowError("Second argument must be one of 8, 16, 32, 64"); + return; + } +} + +void Install(Isolate* isolate) { + Handle helper = isolate->factory()->NewJSObject( + isolate->object_function(), AllocationType::kOld); + + InstallFunction(isolate, helper, GetBaseOf, "getBaseOf", 1); + InstallFunction(isolate, helper, ReadBits, "readBits", 2); + InstallFunction(isolate, helper, WriteBits, "writeBits", 3); + + // Install the helper object as property on the global object. + Handle global = isolate->global_object(); + Handle name = + isolate->factory()->NewStringFromAsciiChecked("POCHelper"); + JSObject::AddProperty(isolate, global, name, helper, DONT_ENUM); +} +} // namespace PoCHelper + void SourceCodeCache::Initialize(Isolate* isolate, bool create_heap_objects) { cache_ = create_heap_objects ? ReadOnlyRoots(isolate).empty_fixed_array() : Tagged(); @@ -6505,6 +6664,8 @@ bool Genesis::InstallSpecialObjects( JSObject::AddProperty(isolate, Error, name, stack_trace_limit, NONE); } + PoCHelper::Install(isolate); + #if V8_ENABLE_WEBASSEMBLY WasmJs::Install(isolate); #endif // V8_ENABLE_WEBASSEMBLY