summaryrefslogtreecommitdiff
path: root/chromium/v8/tools/v8windbg/src/local-variables.cc
blob: e00d06b5955ea797c6bac1f3e8a1d13d48867910 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
// 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 "tools/v8windbg/src/local-variables.h"

#include <vector>

#include "tools/v8windbg/base/utilities.h"
#include "tools/v8windbg/src/object-inspection.h"
#include "tools/v8windbg/src/v8-debug-helper-interop.h"
#include "tools/v8windbg/src/v8windbg-extension.h"

V8LocalVariables::V8LocalVariables(WRL::ComPtr<IModelPropertyAccessor> original,
                                   bool is_parameters)
    : original_(original), is_parameters_(is_parameters) {}
V8LocalVariables::~V8LocalVariables() = default;

IFACEMETHODIMP V8LocalVariables::GetValue(PCWSTR key, IModelObject* context,
                                          IModelObject** value) noexcept {
  // See if the frame can fetch locals based on symbols. If so, it's a normal
  // C++ frame, so we can be done.
  HRESULT original_hr = original_->GetValue(key, context, value);
  if (SUCCEEDED(original_hr)) return original_hr;

  // Next, try to find out about the instruction pointer. If it is within the V8
  // module, or points to unknown space outside a module (generated code), then
  // we're interested. Otherwise, we have nothing useful to do.
  WRL::ComPtr<IModelObject> attributes;
  RETURN_IF_FAIL(context->GetKeyValue(L"Attributes", &attributes, nullptr));
  WRL::ComPtr<IModelObject> boxed_instruction_offset;
  RETURN_IF_FAIL(attributes->GetKeyValue(L"InstructionOffset",
                                         &boxed_instruction_offset, nullptr));
  ULONG64 instruction_offset{};
  RETURN_IF_FAIL(
      UnboxULong64(boxed_instruction_offset.Get(), &instruction_offset));
  WRL::ComPtr<IDebugHostSymbols> symbols;
  RETURN_IF_FAIL(sp_debug_host.As(&symbols));
  WRL::ComPtr<IDebugHostContext> host_context;
  RETURN_IF_FAIL(sp_debug_host->GetCurrentContext(&host_context));
  WRL::ComPtr<IDebugHostModule> module;
  if (SUCCEEDED(symbols->FindModuleByLocation(host_context.Get(),
                                              instruction_offset, &module))) {
    Location module_base;
    RETURN_IF_FAIL(module->GetBaseLocation(&module_base));
    WRL::ComPtr<IDebugHostModule> v8_module =
        Extension::Current()->GetV8Module(host_context);
    if (v8_module == nullptr) {
      // Anything in a module must not be in the V8 module if the V8 module
      // doesn't exist.
      return original_hr;
    }
    Location v8_base;
    RETURN_IF_FAIL(v8_module->GetBaseLocation(&v8_base));
    if (module_base != v8_base) {
      // It's in a module, but not the one that contains V8.
      return original_hr;
    }
  }

  // Initialize an empty result object.
  WRL::ComPtr<IModelObject> result;
  RETURN_IF_FAIL(sp_data_model_manager->CreateSyntheticObject(
      host_context.Get(), &result));
  WRL::ComPtr<IModelObject> parent_model;
  RETURN_IF_FAIL(sp_data_model_manager->AcquireNamedModel(
      is_parameters_ ? L"Debugger.Models.Parameters"
                     : L"Debugger.Models.LocalVariables",
      &parent_model));
  RETURN_IF_FAIL(result->AddParentModel(parent_model.Get(), /*context=*/nullptr,
                                        /*override=*/false));

  if (is_parameters_) {
    // We're not actually adding any parameters data yet; we just need it to not
    // fail so that the locals pane displays the LocalVariables. The locals pane
    // displays nothing if getting either LocalVariables or Parameters fails.
    *value = result.Detach();
    return S_OK;
  }

  // Get the stack and frame pointers for the current frame.
  WRL::ComPtr<IModelObject> boxed_stack_offset;
  RETURN_IF_FAIL(
      attributes->GetKeyValue(L"StackOffset", &boxed_stack_offset, nullptr));
  ULONG64 stack_offset{};
  RETURN_IF_FAIL(UnboxULong64(boxed_stack_offset.Get(), &stack_offset));
  WRL::ComPtr<IModelObject> boxed_frame_offset;
  RETURN_IF_FAIL(
      attributes->GetKeyValue(L"FrameOffset", &boxed_frame_offset, nullptr));
  ULONG64 frame_offset{};
  RETURN_IF_FAIL(UnboxULong64(boxed_frame_offset.Get(), &frame_offset));

  // Eventually v8_debug_helper will provide some help here, but for now, just
  // provide the option to view the whole stack frame as tagged data. It can
  // be somewhat useful.
  WRL::ComPtr<IDebugHostType> object_type =
      Extension::Current()->GetV8ObjectType(host_context);
  if (object_type == nullptr) {
    // There's nothing useful to do if we can't find the symbol for
    // v8::internal::Object.
    return original_hr;
  }
  ULONG64 object_size{};
  RETURN_IF_FAIL(object_type->GetSize(&object_size));
  ULONG64 num_objects = (frame_offset - stack_offset) / object_size;
  ArrayDimension dimensions[] = {
      {/*start=*/0, /*length=*/num_objects, /*stride=*/object_size}};
  WRL::ComPtr<IDebugHostType> object_array_type;
  RETURN_IF_FAIL(object_type->CreateArrayOf(/*dimensions=*/1, dimensions,
                                            &object_array_type));
  WRL::ComPtr<IModelObject> array;
  RETURN_IF_FAIL(sp_data_model_manager->CreateTypedObject(
      host_context.Get(), stack_offset, object_array_type.Get(), &array));
  RETURN_IF_FAIL(
      result->SetKey(L"memory interpreted as Objects", array.Get(), nullptr));

  std::vector<Property> properties = GetStackFrame(host_context, frame_offset);
  for (const auto& prop : properties) {
    WRL::ComPtr<IModelObject> property;
    RETURN_IF_FAIL(GetModelForProperty(prop, host_context, &property));
    result->SetKey(reinterpret_cast<const wchar_t*>(prop.name.c_str()),
                   property.Get(), nullptr);
  }

  *value = result.Detach();
  return S_OK;
}

IFACEMETHODIMP V8LocalVariables::SetValue(PCWSTR key, IModelObject* context,
                                          IModelObject* value) noexcept {
  return E_NOTIMPL;
}