11cb0ef41Sopenharmony_ci// Copyright 2020 the V8 project authors. All rights reserved.
21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be
31cb0ef41Sopenharmony_ci// found in the LICENSE file.
41cb0ef41Sopenharmony_ci
51cb0ef41Sopenharmony_ci#include "tools/v8windbg/src/local-variables.h"
61cb0ef41Sopenharmony_ci
71cb0ef41Sopenharmony_ci#include <vector>
81cb0ef41Sopenharmony_ci
91cb0ef41Sopenharmony_ci#include "tools/v8windbg/base/utilities.h"
101cb0ef41Sopenharmony_ci#include "tools/v8windbg/src/object-inspection.h"
111cb0ef41Sopenharmony_ci#include "tools/v8windbg/src/v8-debug-helper-interop.h"
121cb0ef41Sopenharmony_ci#include "tools/v8windbg/src/v8windbg-extension.h"
131cb0ef41Sopenharmony_ci
141cb0ef41Sopenharmony_ciV8LocalVariables::V8LocalVariables(WRL::ComPtr<IModelPropertyAccessor> original,
151cb0ef41Sopenharmony_ci                                   bool is_parameters)
161cb0ef41Sopenharmony_ci    : original_(original), is_parameters_(is_parameters) {}
171cb0ef41Sopenharmony_ciV8LocalVariables::~V8LocalVariables() = default;
181cb0ef41Sopenharmony_ci
191cb0ef41Sopenharmony_ciIFACEMETHODIMP V8LocalVariables::GetValue(PCWSTR key, IModelObject* context,
201cb0ef41Sopenharmony_ci                                          IModelObject** value) noexcept {
211cb0ef41Sopenharmony_ci  // See if the frame can fetch locals based on symbols. If so, it's a normal
221cb0ef41Sopenharmony_ci  // C++ frame, so we can be done.
231cb0ef41Sopenharmony_ci  HRESULT original_hr = original_->GetValue(key, context, value);
241cb0ef41Sopenharmony_ci  if (SUCCEEDED(original_hr)) return original_hr;
251cb0ef41Sopenharmony_ci
261cb0ef41Sopenharmony_ci  // Next, try to find out about the instruction pointer. If it is within the V8
271cb0ef41Sopenharmony_ci  // module, or points to unknown space outside a module (generated code), then
281cb0ef41Sopenharmony_ci  // we're interested. Otherwise, we have nothing useful to do.
291cb0ef41Sopenharmony_ci  WRL::ComPtr<IModelObject> attributes;
301cb0ef41Sopenharmony_ci  RETURN_IF_FAIL(context->GetKeyValue(L"Attributes", &attributes, nullptr));
311cb0ef41Sopenharmony_ci  WRL::ComPtr<IModelObject> boxed_instruction_offset;
321cb0ef41Sopenharmony_ci  RETURN_IF_FAIL(attributes->GetKeyValue(L"InstructionOffset",
331cb0ef41Sopenharmony_ci                                         &boxed_instruction_offset, nullptr));
341cb0ef41Sopenharmony_ci  ULONG64 instruction_offset{};
351cb0ef41Sopenharmony_ci  RETURN_IF_FAIL(
361cb0ef41Sopenharmony_ci      UnboxULong64(boxed_instruction_offset.Get(), &instruction_offset));
371cb0ef41Sopenharmony_ci  WRL::ComPtr<IDebugHostSymbols> symbols;
381cb0ef41Sopenharmony_ci  RETURN_IF_FAIL(sp_debug_host.As(&symbols));
391cb0ef41Sopenharmony_ci  WRL::ComPtr<IDebugHostContext> host_context;
401cb0ef41Sopenharmony_ci  RETURN_IF_FAIL(sp_debug_host->GetCurrentContext(&host_context));
411cb0ef41Sopenharmony_ci  WRL::ComPtr<IDebugHostModule> module;
421cb0ef41Sopenharmony_ci  if (SUCCEEDED(symbols->FindModuleByLocation(host_context.Get(),
431cb0ef41Sopenharmony_ci                                              instruction_offset, &module))) {
441cb0ef41Sopenharmony_ci    Location module_base;
451cb0ef41Sopenharmony_ci    RETURN_IF_FAIL(module->GetBaseLocation(&module_base));
461cb0ef41Sopenharmony_ci    WRL::ComPtr<IDebugHostModule> v8_module =
471cb0ef41Sopenharmony_ci        Extension::Current()->GetV8Module(host_context);
481cb0ef41Sopenharmony_ci    if (v8_module == nullptr) {
491cb0ef41Sopenharmony_ci      // Anything in a module must not be in the V8 module if the V8 module
501cb0ef41Sopenharmony_ci      // doesn't exist.
511cb0ef41Sopenharmony_ci      return original_hr;
521cb0ef41Sopenharmony_ci    }
531cb0ef41Sopenharmony_ci    Location v8_base;
541cb0ef41Sopenharmony_ci    RETURN_IF_FAIL(v8_module->GetBaseLocation(&v8_base));
551cb0ef41Sopenharmony_ci    if (module_base != v8_base) {
561cb0ef41Sopenharmony_ci      // It's in a module, but not the one that contains V8.
571cb0ef41Sopenharmony_ci      return original_hr;
581cb0ef41Sopenharmony_ci    }
591cb0ef41Sopenharmony_ci  }
601cb0ef41Sopenharmony_ci
611cb0ef41Sopenharmony_ci  // Initialize an empty result object.
621cb0ef41Sopenharmony_ci  WRL::ComPtr<IModelObject> result;
631cb0ef41Sopenharmony_ci  RETURN_IF_FAIL(sp_data_model_manager->CreateSyntheticObject(
641cb0ef41Sopenharmony_ci      host_context.Get(), &result));
651cb0ef41Sopenharmony_ci  WRL::ComPtr<IModelObject> parent_model;
661cb0ef41Sopenharmony_ci  RETURN_IF_FAIL(sp_data_model_manager->AcquireNamedModel(
671cb0ef41Sopenharmony_ci      is_parameters_ ? L"Debugger.Models.Parameters"
681cb0ef41Sopenharmony_ci                     : L"Debugger.Models.LocalVariables",
691cb0ef41Sopenharmony_ci      &parent_model));
701cb0ef41Sopenharmony_ci  RETURN_IF_FAIL(result->AddParentModel(parent_model.Get(), /*context=*/nullptr,
711cb0ef41Sopenharmony_ci                                        /*override=*/false));
721cb0ef41Sopenharmony_ci
731cb0ef41Sopenharmony_ci  if (is_parameters_) {
741cb0ef41Sopenharmony_ci    // We're not actually adding any parameters data yet; we just need it to not
751cb0ef41Sopenharmony_ci    // fail so that the locals pane displays the LocalVariables. The locals pane
761cb0ef41Sopenharmony_ci    // displays nothing if getting either LocalVariables or Parameters fails.
771cb0ef41Sopenharmony_ci    *value = result.Detach();
781cb0ef41Sopenharmony_ci    return S_OK;
791cb0ef41Sopenharmony_ci  }
801cb0ef41Sopenharmony_ci
811cb0ef41Sopenharmony_ci  // Get the stack and frame pointers for the current frame.
821cb0ef41Sopenharmony_ci  WRL::ComPtr<IModelObject> boxed_stack_offset;
831cb0ef41Sopenharmony_ci  RETURN_IF_FAIL(
841cb0ef41Sopenharmony_ci      attributes->GetKeyValue(L"StackOffset", &boxed_stack_offset, nullptr));
851cb0ef41Sopenharmony_ci  ULONG64 stack_offset{};
861cb0ef41Sopenharmony_ci  RETURN_IF_FAIL(UnboxULong64(boxed_stack_offset.Get(), &stack_offset));
871cb0ef41Sopenharmony_ci  WRL::ComPtr<IModelObject> boxed_frame_offset;
881cb0ef41Sopenharmony_ci  RETURN_IF_FAIL(
891cb0ef41Sopenharmony_ci      attributes->GetKeyValue(L"FrameOffset", &boxed_frame_offset, nullptr));
901cb0ef41Sopenharmony_ci  ULONG64 frame_offset{};
911cb0ef41Sopenharmony_ci  RETURN_IF_FAIL(UnboxULong64(boxed_frame_offset.Get(), &frame_offset));
921cb0ef41Sopenharmony_ci
931cb0ef41Sopenharmony_ci  // Eventually v8_debug_helper will provide some help here, but for now, just
941cb0ef41Sopenharmony_ci  // provide the option to view the whole stack frame as tagged data. It can
951cb0ef41Sopenharmony_ci  // be somewhat useful.
961cb0ef41Sopenharmony_ci  WRL::ComPtr<IDebugHostType> object_type =
971cb0ef41Sopenharmony_ci      Extension::Current()->GetV8ObjectType(host_context);
981cb0ef41Sopenharmony_ci  if (object_type == nullptr) {
991cb0ef41Sopenharmony_ci    // There's nothing useful to do if we can't find the symbol for
1001cb0ef41Sopenharmony_ci    // v8::internal::Object.
1011cb0ef41Sopenharmony_ci    return original_hr;
1021cb0ef41Sopenharmony_ci  }
1031cb0ef41Sopenharmony_ci  ULONG64 object_size{};
1041cb0ef41Sopenharmony_ci  RETURN_IF_FAIL(object_type->GetSize(&object_size));
1051cb0ef41Sopenharmony_ci  ULONG64 num_objects = (frame_offset - stack_offset) / object_size;
1061cb0ef41Sopenharmony_ci  ArrayDimension dimensions[] = {
1071cb0ef41Sopenharmony_ci      {/*start=*/0, /*length=*/num_objects, /*stride=*/object_size}};
1081cb0ef41Sopenharmony_ci  WRL::ComPtr<IDebugHostType> object_array_type;
1091cb0ef41Sopenharmony_ci  RETURN_IF_FAIL(object_type->CreateArrayOf(/*dimensions=*/1, dimensions,
1101cb0ef41Sopenharmony_ci                                            &object_array_type));
1111cb0ef41Sopenharmony_ci  WRL::ComPtr<IModelObject> array;
1121cb0ef41Sopenharmony_ci  RETURN_IF_FAIL(sp_data_model_manager->CreateTypedObject(
1131cb0ef41Sopenharmony_ci      host_context.Get(), stack_offset, object_array_type.Get(), &array));
1141cb0ef41Sopenharmony_ci  RETURN_IF_FAIL(
1151cb0ef41Sopenharmony_ci      result->SetKey(L"memory interpreted as Objects", array.Get(), nullptr));
1161cb0ef41Sopenharmony_ci
1171cb0ef41Sopenharmony_ci  std::vector<Property> properties = GetStackFrame(host_context, frame_offset);
1181cb0ef41Sopenharmony_ci  for (const auto& prop : properties) {
1191cb0ef41Sopenharmony_ci    WRL::ComPtr<IModelObject> property;
1201cb0ef41Sopenharmony_ci    RETURN_IF_FAIL(GetModelForProperty(prop, host_context, &property));
1211cb0ef41Sopenharmony_ci    result->SetKey(reinterpret_cast<const wchar_t*>(prop.name.c_str()),
1221cb0ef41Sopenharmony_ci                   property.Get(), nullptr);
1231cb0ef41Sopenharmony_ci  }
1241cb0ef41Sopenharmony_ci
1251cb0ef41Sopenharmony_ci  *value = result.Detach();
1261cb0ef41Sopenharmony_ci  return S_OK;
1271cb0ef41Sopenharmony_ci}
1281cb0ef41Sopenharmony_ci
1291cb0ef41Sopenharmony_ciIFACEMETHODIMP V8LocalVariables::SetValue(PCWSTR key, IModelObject* context,
1301cb0ef41Sopenharmony_ci                                          IModelObject* value) noexcept {
1311cb0ef41Sopenharmony_ci  return E_NOTIMPL;
1321cb0ef41Sopenharmony_ci}
133