1// Copyright 2020 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 "tools/v8windbg/src/local-variables.h" 6 7#include <vector> 8 9#include "tools/v8windbg/base/utilities.h" 10#include "tools/v8windbg/src/object-inspection.h" 11#include "tools/v8windbg/src/v8-debug-helper-interop.h" 12#include "tools/v8windbg/src/v8windbg-extension.h" 13 14V8LocalVariables::V8LocalVariables(WRL::ComPtr<IModelPropertyAccessor> original, 15 bool is_parameters) 16 : original_(original), is_parameters_(is_parameters) {} 17V8LocalVariables::~V8LocalVariables() = default; 18 19IFACEMETHODIMP V8LocalVariables::GetValue(PCWSTR key, IModelObject* context, 20 IModelObject** value) noexcept { 21 // See if the frame can fetch locals based on symbols. If so, it's a normal 22 // C++ frame, so we can be done. 23 HRESULT original_hr = original_->GetValue(key, context, value); 24 if (SUCCEEDED(original_hr)) return original_hr; 25 26 // Next, try to find out about the instruction pointer. If it is within the V8 27 // module, or points to unknown space outside a module (generated code), then 28 // we're interested. Otherwise, we have nothing useful to do. 29 WRL::ComPtr<IModelObject> attributes; 30 RETURN_IF_FAIL(context->GetKeyValue(L"Attributes", &attributes, nullptr)); 31 WRL::ComPtr<IModelObject> boxed_instruction_offset; 32 RETURN_IF_FAIL(attributes->GetKeyValue(L"InstructionOffset", 33 &boxed_instruction_offset, nullptr)); 34 ULONG64 instruction_offset{}; 35 RETURN_IF_FAIL( 36 UnboxULong64(boxed_instruction_offset.Get(), &instruction_offset)); 37 WRL::ComPtr<IDebugHostSymbols> symbols; 38 RETURN_IF_FAIL(sp_debug_host.As(&symbols)); 39 WRL::ComPtr<IDebugHostContext> host_context; 40 RETURN_IF_FAIL(sp_debug_host->GetCurrentContext(&host_context)); 41 WRL::ComPtr<IDebugHostModule> module; 42 if (SUCCEEDED(symbols->FindModuleByLocation(host_context.Get(), 43 instruction_offset, &module))) { 44 Location module_base; 45 RETURN_IF_FAIL(module->GetBaseLocation(&module_base)); 46 WRL::ComPtr<IDebugHostModule> v8_module = 47 Extension::Current()->GetV8Module(host_context); 48 if (v8_module == nullptr) { 49 // Anything in a module must not be in the V8 module if the V8 module 50 // doesn't exist. 51 return original_hr; 52 } 53 Location v8_base; 54 RETURN_IF_FAIL(v8_module->GetBaseLocation(&v8_base)); 55 if (module_base != v8_base) { 56 // It's in a module, but not the one that contains V8. 57 return original_hr; 58 } 59 } 60 61 // Initialize an empty result object. 62 WRL::ComPtr<IModelObject> result; 63 RETURN_IF_FAIL(sp_data_model_manager->CreateSyntheticObject( 64 host_context.Get(), &result)); 65 WRL::ComPtr<IModelObject> parent_model; 66 RETURN_IF_FAIL(sp_data_model_manager->AcquireNamedModel( 67 is_parameters_ ? L"Debugger.Models.Parameters" 68 : L"Debugger.Models.LocalVariables", 69 &parent_model)); 70 RETURN_IF_FAIL(result->AddParentModel(parent_model.Get(), /*context=*/nullptr, 71 /*override=*/false)); 72 73 if (is_parameters_) { 74 // We're not actually adding any parameters data yet; we just need it to not 75 // fail so that the locals pane displays the LocalVariables. The locals pane 76 // displays nothing if getting either LocalVariables or Parameters fails. 77 *value = result.Detach(); 78 return S_OK; 79 } 80 81 // Get the stack and frame pointers for the current frame. 82 WRL::ComPtr<IModelObject> boxed_stack_offset; 83 RETURN_IF_FAIL( 84 attributes->GetKeyValue(L"StackOffset", &boxed_stack_offset, nullptr)); 85 ULONG64 stack_offset{}; 86 RETURN_IF_FAIL(UnboxULong64(boxed_stack_offset.Get(), &stack_offset)); 87 WRL::ComPtr<IModelObject> boxed_frame_offset; 88 RETURN_IF_FAIL( 89 attributes->GetKeyValue(L"FrameOffset", &boxed_frame_offset, nullptr)); 90 ULONG64 frame_offset{}; 91 RETURN_IF_FAIL(UnboxULong64(boxed_frame_offset.Get(), &frame_offset)); 92 93 // Eventually v8_debug_helper will provide some help here, but for now, just 94 // provide the option to view the whole stack frame as tagged data. It can 95 // be somewhat useful. 96 WRL::ComPtr<IDebugHostType> object_type = 97 Extension::Current()->GetV8ObjectType(host_context); 98 if (object_type == nullptr) { 99 // There's nothing useful to do if we can't find the symbol for 100 // v8::internal::Object. 101 return original_hr; 102 } 103 ULONG64 object_size{}; 104 RETURN_IF_FAIL(object_type->GetSize(&object_size)); 105 ULONG64 num_objects = (frame_offset - stack_offset) / object_size; 106 ArrayDimension dimensions[] = { 107 {/*start=*/0, /*length=*/num_objects, /*stride=*/object_size}}; 108 WRL::ComPtr<IDebugHostType> object_array_type; 109 RETURN_IF_FAIL(object_type->CreateArrayOf(/*dimensions=*/1, dimensions, 110 &object_array_type)); 111 WRL::ComPtr<IModelObject> array; 112 RETURN_IF_FAIL(sp_data_model_manager->CreateTypedObject( 113 host_context.Get(), stack_offset, object_array_type.Get(), &array)); 114 RETURN_IF_FAIL( 115 result->SetKey(L"memory interpreted as Objects", array.Get(), nullptr)); 116 117 std::vector<Property> properties = GetStackFrame(host_context, frame_offset); 118 for (const auto& prop : properties) { 119 WRL::ComPtr<IModelObject> property; 120 RETURN_IF_FAIL(GetModelForProperty(prop, host_context, &property)); 121 result->SetKey(reinterpret_cast<const wchar_t*>(prop.name.c_str()), 122 property.Get(), nullptr); 123 } 124 125 *value = result.Detach(); 126 return S_OK; 127} 128 129IFACEMETHODIMP V8LocalVariables::SetValue(PCWSTR key, IModelObject* context, 130 IModelObject* value) noexcept { 131 return E_NOTIMPL; 132} 133