/
githubmirror
/
node
Обзор
Документация
Войти
/
githubmirror
/
node
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
deps/v8/src/debug/wasm/gdb-server/wasm-module-debug.cc
438 строк
16 KB
Michaël Zasso
deps: update V8 to 14.1.146.11
04 окт 2025, 19:47
Не верифицирован
04 окт 2025, 19:47
7772a2d
Код
Авторство
О чём код?
// 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. #include "src/debug/wasm/gdb-server/wasm-module-debug.h" #include "src/api/api-inl.h" #include "src/api/api.h" #include "src/debug/debug.h" #include "src/execution/frames-inl.h" #include "src/execution/frames.h" #include "src/objects/script.h" #include "src/wasm/constant-expression.h" #include "src/wasm/module-instantiate.h" #include "src/wasm/wasm-debug.h" #include "src/wasm/wasm-opcodes.h" #include "src/wasm/wasm-value.h" #include "src/zone/zone.h" namespace v8 { namespace internal { namespace wasm { namespace gdb_server { WasmModuleDebug::WasmModuleDebug(v8::Isolate* isolate, Local<debug::WasmScript> wasm_script) { DCHECK_EQ(Script::Type::kWasm, Utils::OpenHandle(*wasm_script)->type()); isolate_ = isolate; wasm_script_ = Global<debug::WasmScript>(isolate, wasm_script); } std::string WasmModuleDebug::GetModuleName() const { v8::Local<debug::WasmScript> wasm_script = wasm_script_.Get(isolate_); v8::Local<v8::String> name; std::string module_name; if (wasm_script->Name().ToLocal(&name)) { module_name = *(v8::String::Utf8Value(isolate_, name)); } return module_name; } Handle<WasmInstanceObject> WasmModuleDebug::GetFirstWasmInstance() { v8::Local<debug::WasmScript> wasm_script = wasm_script_.Get(isolate_); Handle<Script> script = Utils::OpenHandle(*wasm_script); Handle<WeakArrayList> weak_instance_list(script->wasm_weak_instance_list(), GetIsolate()); if (weak_instance_list->length() > 0) { Tagged<MaybeObject> maybe_instance = weak_instance_list->Get(0); if (maybe_instance.IsWeak()) { Handle<WasmInstanceObject> instance( Cast<WasmInstanceObject>(maybe_instance.GetHeapObjectAssumeWeak()), GetIsolate()); return instance; } } return Handle<WasmInstanceObject>::null(); } int GetLEB128Size(base::Vector<const uint8_t> module_bytes, int offset) { int index = offset; while (module_bytes[index] & 0x80) index++; return index + 1 - offset; } int ReturnPc(const NativeModule* native_module, int pc) { base::Vector<const uint8_t> wire_bytes = native_module->wire_bytes(); uint8_t opcode = wire_bytes[pc]; switch (opcode) { case kExprCallFunction: { // skip opcode pc++; // skip function index return pc + GetLEB128Size(wire_bytes, pc); } case kExprCallIndirect: { // skip opcode pc++; // skip signature index pc += GetLEB128Size(wire_bytes, pc); // skip table index return pc + GetLEB128Size(wire_bytes, pc); } default: UNREACHABLE(); } } // static std::vector<wasm_addr_t> WasmModuleDebug::GetCallStack( uint32_t debug_context_id, Isolate* isolate) { std::vector<wasm_addr_t> call_stack; for (StackFrameIterator frame_it(isolate); !frame_it.done(); frame_it.Advance()) { StackFrame* const frame = frame_it.frame(); switch (frame->type()) { case StackFrame::JAVASCRIPT_BUILTIN_CONTINUATION: case StackFrame::JAVASCRIPT_BUILTIN_CONTINUATION_WITH_CATCH: case StackFrame::INTERPRETED: case StackFrame::BASELINE: case StackFrame::MAGLEV: case StackFrame::TURBOFAN_JS: case StackFrame::BUILTIN: case StackFrame::WASM: { // A standard frame may include many summarized frames, due to inlining. FrameSummaries summaries = CommonFrame::cast(frame)->Summarize(); for (size_t i = summaries.size(); i-- != 0;) { int offset = 0; Handle<Script> script; auto& summary = summaries.frames[i]; if (summary.IsJavaScript()) { FrameSummary::JavaScriptFrameSummary const& javascript = summary.AsJavaScript(); offset = javascript.code_offset(); script = Cast<Script>(javascript.script()); } else if (summary.IsWasm()) { FrameSummary::WasmFrameSummary const& wasm = summary.AsWasm(); offset = GetWasmFunctionOffset(wasm.wasm_instance()->module(), wasm.function_index()) + wasm.code_offset(); script = wasm.script(); bool zeroth_frame = call_stack.empty(); if (!zeroth_frame) { const NativeModule* native_module = wasm.wasm_instance()->module_object()->native_module(); offset = ReturnPc(native_module, offset); } } if (offset > 0) { call_stack.push_back( {debug_context_id << 16 | script->id(), uint32_t(offset)}); } } break; } case StackFrame::BUILTIN_EXIT: default: // ignore the frame. break; } } if (call_stack.empty()) call_stack.push_back({1, 0}); return call_stack; } // static std::vector<FrameSummary> WasmModuleDebug::FindWasmFrame( DebuggableStackFrameIterator* frame_it, uint32_t* frame_index) { while (!frame_it->done()) { StackFrame* const frame = frame_it->frame(); switch (frame->type()) { case StackFrame::JAVASCRIPT_BUILTIN_CONTINUATION: case StackFrame::JAVASCRIPT_BUILTIN_CONTINUATION_WITH_CATCH: case StackFrame::INTERPRETED: case StackFrame::BASELINE: case StackFrame::MAGLEV: case StackFrame::TURBOFAN_JS: case StackFrame::BUILTIN: case StackFrame::WASM: { // A standard frame may include many summarized frames, due to inlining. FrameSummaries summaries = CommonFrame::cast(frame)->Summarize(); const size_t frame_count = summaries.size(); DCHECK_GT(frame_count, 0); if (frame_count > *frame_index) { #if V8_ENABLE_DRUMBRAKE if (frame_it->is_wasm() && !frame_it->is_wasm_interpreter_entry()) #else // V8_ENABLE_DRUMBRAKE if (frame_it->is_wasm()) #endif // V8_ENABLE_DRUMBRAKE return summaries.frames; else return {}; } else { *frame_index -= frame_count; frame_it->Advance(); } break; } case StackFrame::BUILTIN_EXIT: default: // ignore the frame. break; } } return {}; } // static DirectHandle<WasmInstanceObject> WasmModuleDebug::GetWasmInstance( Isolate* isolate, uint32_t frame_index) { DebuggableStackFrameIterator frame_it(isolate); std::vector<FrameSummary> frames = FindWasmFrame(&frame_it, &frame_index); if (frames.empty()) { return DirectHandle<WasmInstanceObject>::null(); } int reversed_index = static_cast<int>(frames.size() - 1 - frame_index); const FrameSummary::WasmFrameSummary& summary = frames[reversed_index].AsWasm(); return summary.wasm_instance(); } // static bool WasmModuleDebug::GetWasmGlobal(Isolate* isolate, uint32_t frame_index, uint32_t index, uint8_t* buffer, uint32_t buffer_size, uint32_t* size) { HandleScope handles(isolate); DirectHandle<WasmInstanceObject> instance = GetWasmInstance(isolate, frame_index); if (!instance.is_null()) { Handle<WasmModuleObject> module_object(instance->module_object(), isolate); const wasm::WasmModule* module = module_object->native_module()->module(); if (index < module->globals.size()) { DirectHandle<WasmTrustedInstanceData> trusted_data( instance->trusted_data(isolate), isolate); wasm::WasmValue wasm_value = trusted_data->GetGlobalValue(isolate, module->globals[index]); return GetWasmValue(wasm_value, buffer, buffer_size, size); } } return false; } // static bool WasmModuleDebug::GetWasmLocal(Isolate* isolate, uint32_t frame_index, uint32_t index, uint8_t* buffer, uint32_t buffer_size, uint32_t* size) { HandleScope handles(isolate); DebuggableStackFrameIterator frame_it(isolate); std::vector<FrameSummary> frames = FindWasmFrame(&frame_it, &frame_index); if (frames.empty()) { return false; } int reversed_index = static_cast<int>(frames.size() - 1 - frame_index); const FrameSummary& summary = frames[reversed_index]; if (summary.IsWasm()) { DirectHandle<WasmInstanceObject> instance = summary.AsWasm().wasm_instance(); if (!instance.is_null()) { Handle<WasmModuleObject> module_object(instance->module_object(), isolate); wasm::NativeModule* native_module = module_object->native_module(); DebugInfo* debug_info = native_module->GetDebugInfo(); if (static_cast<uint32_t>(debug_info->GetNumLocals(frame_it.frame()->pc(), isolate)) > index) { wasm::WasmValue wasm_value = debug_info->GetLocalValue( index, frame_it.frame()->pc(), frame_it.frame()->fp(), frame_it.frame()->callee_fp(), isolate); return GetWasmValue(wasm_value, buffer, buffer_size, size); } } } return false; } // static bool WasmModuleDebug::GetWasmStackValue(Isolate* isolate, uint32_t frame_index, uint32_t index, uint8_t* buffer, uint32_t buffer_size, uint32_t* size) { HandleScope handles(isolate); DebuggableStackFrameIterator frame_it(isolate); std::vector<FrameSummary> frames = FindWasmFrame(&frame_it, &frame_index); if (frames.empty()) { return false; } int reversed_index = static_cast<int>(frames.size() - 1 - frame_index); const FrameSummary& summary = frames[reversed_index]; if (summary.IsWasm()) { DirectHandle<WasmInstanceObject> instance = summary.AsWasm().wasm_instance(); if (!instance.is_null()) { Handle<WasmModuleObject> module_object(instance->module_object(), isolate); wasm::NativeModule* native_module = module_object->native_module(); DebugInfo* debug_info = native_module->GetDebugInfo(); if (static_cast<uint32_t>(debug_info->GetStackDepth( frame_it.frame()->pc(), isolate)) > index) { WasmValue wasm_value = debug_info->GetStackValue( index, frame_it.frame()->pc(), frame_it.frame()->fp(), frame_it.frame()->callee_fp(), isolate); return GetWasmValue(wasm_value, buffer, buffer_size, size); } } } return false; } uint32_t WasmModuleDebug::GetWasmMemory(Isolate* isolate, uint32_t offset, uint8_t* buffer, uint32_t size) { HandleScope handles(isolate); uint32_t bytes_read = 0; Handle<WasmInstanceObject> instance = GetFirstWasmInstance(); if (!instance.is_null()) { uint8_t* mem_start = instance->trusted_data(isolate)->memory0_start(); size_t mem_size = instance->trusted_data(isolate)->memory0_size(); if (static_cast<uint64_t>(offset) + size <= mem_size) { memcpy(buffer, mem_start + offset, size); bytes_read = size; } else if (offset < mem_size) { bytes_read = static_cast<uint32_t>(mem_size) - offset; memcpy(buffer, mem_start + offset, bytes_read); } } return bytes_read; } uint32_t WasmModuleDebug::GetWasmData(Zone* zone, Isolate* isolate, uint32_t offset, uint8_t* buffer, uint32_t size) { HandleScope handles(isolate); uint32_t bytes_read = 0; Handle<WasmInstanceObject> instance = GetFirstWasmInstance(); if (!instance.is_null()) { DirectHandle<WasmTrustedInstanceData> trusted_data( instance->trusted_data(isolate), isolate); DirectHandle<WasmTrustedInstanceData> shared_data( trusted_data->shared_part(), isolate); Handle<WasmModuleObject> module_object(instance->module_object(), isolate); const wasm::WasmModule* module = module_object->native_module()->module(); if (!module->data_segments.empty()) { const WasmDataSegment& segment = module->data_segments[0]; wasm::ValueOrError result = wasm::EvaluateConstantExpression( zone, segment.dest_addr, wasm::kWasmI32, module, isolate, trusted_data, shared_data); if (!wasm::is_error(result)) { uint32_t data_offset = wasm::to_value(result).to_u32(); offset += data_offset; uint8_t* mem_start = trusted_data->memory0_start(); size_t mem_size = trusted_data->memory0_size(); if (static_cast<uint64_t>(offset) + size <= mem_size) { memcpy(buffer, mem_start + offset, size); bytes_read = size; } else if (offset < mem_size) { bytes_read = static_cast<uint32_t>(mem_size) - offset; memcpy(buffer, mem_start + offset, bytes_read); } } } } return bytes_read; } uint32_t WasmModuleDebug::GetWasmModuleBytes(wasm_addr_t wasm_addr, uint8_t* buffer, uint32_t size) { uint32_t bytes_read = 0; // Any instance will work. Handle<WasmInstanceObject> instance = GetFirstWasmInstance(); if (!instance.is_null()) { Handle<WasmModuleObject> module_object(instance->module_object(), GetIsolate()); wasm::NativeModule* native_module = module_object->native_module(); const wasm::ModuleWireBytes wire_bytes(native_module->wire_bytes()); uint32_t offset = wasm_addr.Offset(); if (offset < wire_bytes.length()) { uint32_t module_size = static_cast<uint32_t>(wire_bytes.length()); bytes_read = module_size - offset >= size ? size : module_size - offset; memcpy(buffer, wire_bytes.start() + offset, bytes_read); } } return bytes_read; } bool WasmModuleDebug::AddBreakpoint(uint32_t offset, int* breakpoint_id) { v8::Local<debug::WasmScript> wasm_script = wasm_script_.Get(isolate_); Handle<Script> script = Utils::OpenHandle(*wasm_script); Handle<String> condition = GetIsolate()->factory()->empty_string(); int breakpoint_address = static_cast<int>(offset); return GetIsolate()->debug()->SetBreakPointForScript( script, condition, &breakpoint_address, breakpoint_id); } void WasmModuleDebug::RemoveBreakpoint(uint32_t offset, int breakpoint_id) { v8::Local<debug::WasmScript> wasm_script = wasm_script_.Get(isolate_); Handle<Script> script = Utils::OpenHandle(*wasm_script); GetIsolate()->debug()->RemoveBreakpointForWasmScript(script, breakpoint_id); } void WasmModuleDebug::PrepareStep() { i::Isolate* isolate = GetIsolate(); DebugScope debug_scope(isolate->debug()); debug::PrepareStep(reinterpret_cast<v8::Isolate*>(isolate), debug::StepAction::StepInto); } template <typename T> bool StoreValue(const T& value, uint8_t* buffer, uint32_t buffer_size, uint32_t* size) { *size = sizeof(value); if (*size > buffer_size) return false; memcpy(buffer, &value, *size); return true; } // static bool WasmModuleDebug::GetWasmValue(const wasm::WasmValue& wasm_value, uint8_t* buffer, uint32_t buffer_size, uint32_t* size) { switch (wasm_value.type().kind()) { case wasm::kI32: return StoreValue(wasm_value.to_i32(), buffer, buffer_size, size); case wasm::kI64: return StoreValue(wasm_value.to_i64(), buffer, buffer_size, size); case wasm::kF32: return StoreValue(wasm_value.to_f32(), buffer, buffer_size, size); case wasm::kF64: return StoreValue(wasm_value.to_f64(), buffer, buffer_size, size); case wasm::kS128: return StoreValue(wasm_value.to_s128(), buffer, buffer_size, size); case wasm::kRef: case wasm::kRefNull: case wasm::kVoid: case wasm::kBottom: // TODO(): Support references. return false; default: return false; } } } // namespace gdb_server } // namespace wasm } // namespace internal } // namespace v8