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/v8-debug-helper-interop.h"
61cb0ef41Sopenharmony_ci
71cb0ef41Sopenharmony_ci#include <Windows.h>
81cb0ef41Sopenharmony_ci#include <crtdbg.h>
91cb0ef41Sopenharmony_ci
101cb0ef41Sopenharmony_ci#include "src/common/globals.h"
111cb0ef41Sopenharmony_ci#include "tools/debug_helper/debug-helper.h"
121cb0ef41Sopenharmony_ci#include "tools/v8windbg/base/utilities.h"
131cb0ef41Sopenharmony_ci#include "tools/v8windbg/src/v8windbg-extension.h"
141cb0ef41Sopenharmony_ci
151cb0ef41Sopenharmony_cinamespace d = v8::debug_helper;
161cb0ef41Sopenharmony_ci
171cb0ef41Sopenharmony_ci// We need a plain C function pointer for interop with v8_debug_helper. We can
181cb0ef41Sopenharmony_ci// use this to get one as long as we never need two at once.
191cb0ef41Sopenharmony_ciclass V8_NODISCARD MemReaderScope {
201cb0ef41Sopenharmony_ci public:
211cb0ef41Sopenharmony_ci  explicit MemReaderScope(WRL::ComPtr<IDebugHostContext> sp_context)
221cb0ef41Sopenharmony_ci      : sp_context_(sp_context) {
231cb0ef41Sopenharmony_ci    _ASSERTE(!context_);
241cb0ef41Sopenharmony_ci    context_ = sp_context_.Get();
251cb0ef41Sopenharmony_ci  }
261cb0ef41Sopenharmony_ci  ~MemReaderScope() { context_ = nullptr; }
271cb0ef41Sopenharmony_ci  d::MemoryAccessor GetReader() { return &MemReaderScope::Read; }
281cb0ef41Sopenharmony_ci
291cb0ef41Sopenharmony_ci private:
301cb0ef41Sopenharmony_ci  MemReaderScope(const MemReaderScope&) = delete;
311cb0ef41Sopenharmony_ci  MemReaderScope& operator=(const MemReaderScope&) = delete;
321cb0ef41Sopenharmony_ci  static d::MemoryAccessResult Read(uintptr_t address, void* destination,
331cb0ef41Sopenharmony_ci                                    size_t byte_count) {
341cb0ef41Sopenharmony_ci    ULONG64 bytes_read;
351cb0ef41Sopenharmony_ci    Location loc{address};
361cb0ef41Sopenharmony_ci    HRESULT hr = sp_debug_host_memory->ReadBytes(context_, loc, destination,
371cb0ef41Sopenharmony_ci                                                 byte_count, &bytes_read);
381cb0ef41Sopenharmony_ci    // TODO determine when an address is valid but inaccessible
391cb0ef41Sopenharmony_ci    return SUCCEEDED(hr) ? d::MemoryAccessResult::kOk
401cb0ef41Sopenharmony_ci                         : d::MemoryAccessResult::kAddressNotValid;
411cb0ef41Sopenharmony_ci  }
421cb0ef41Sopenharmony_ci  WRL::ComPtr<IDebugHostContext> sp_context_;
431cb0ef41Sopenharmony_ci  static IDebugHostContext* context_;
441cb0ef41Sopenharmony_ci};
451cb0ef41Sopenharmony_ciIDebugHostContext* MemReaderScope::context_;
461cb0ef41Sopenharmony_ci
471cb0ef41Sopenharmony_ciStructField::StructField(std::u16string field_name, std::u16string type_name,
481cb0ef41Sopenharmony_ci                         std::string uncompressed_type_name, uint64_t offset,
491cb0ef41Sopenharmony_ci                         uint8_t num_bits, uint8_t shift_bits)
501cb0ef41Sopenharmony_ci    : name(field_name),
511cb0ef41Sopenharmony_ci      type_name(type_name),
521cb0ef41Sopenharmony_ci      uncompressed_type_name(uncompressed_type_name),
531cb0ef41Sopenharmony_ci      offset(offset),
541cb0ef41Sopenharmony_ci      num_bits(num_bits),
551cb0ef41Sopenharmony_ci      shift_bits(shift_bits) {}
561cb0ef41Sopenharmony_ciStructField::~StructField() = default;
571cb0ef41Sopenharmony_ciStructField::StructField(const StructField&) = default;
581cb0ef41Sopenharmony_ciStructField::StructField(StructField&&) = default;
591cb0ef41Sopenharmony_ciStructField& StructField::operator=(const StructField&) = default;
601cb0ef41Sopenharmony_ciStructField& StructField::operator=(StructField&&) = default;
611cb0ef41Sopenharmony_ci
621cb0ef41Sopenharmony_ciProperty::Property(std::u16string property_name, std::u16string type_name,
631cb0ef41Sopenharmony_ci                   std::string uncompressed_type_name, uint64_t address,
641cb0ef41Sopenharmony_ci                   size_t item_size)
651cb0ef41Sopenharmony_ci    : name(property_name),
661cb0ef41Sopenharmony_ci      type(PropertyType::kPointer),
671cb0ef41Sopenharmony_ci      type_name(type_name),
681cb0ef41Sopenharmony_ci      uncompressed_type_name(uncompressed_type_name),
691cb0ef41Sopenharmony_ci      addr_value(address),
701cb0ef41Sopenharmony_ci      item_size(item_size) {}
711cb0ef41Sopenharmony_ciProperty::~Property() = default;
721cb0ef41Sopenharmony_ciProperty::Property(const Property&) = default;
731cb0ef41Sopenharmony_ciProperty::Property(Property&&) = default;
741cb0ef41Sopenharmony_ciProperty& Property::operator=(const Property&) = default;
751cb0ef41Sopenharmony_ciProperty& Property::operator=(Property&&) = default;
761cb0ef41Sopenharmony_ci
771cb0ef41Sopenharmony_ciV8HeapObject::V8HeapObject() = default;
781cb0ef41Sopenharmony_ciV8HeapObject::~V8HeapObject() = default;
791cb0ef41Sopenharmony_ciV8HeapObject::V8HeapObject(const V8HeapObject&) = default;
801cb0ef41Sopenharmony_ciV8HeapObject::V8HeapObject(V8HeapObject&&) = default;
811cb0ef41Sopenharmony_ciV8HeapObject& V8HeapObject::operator=(const V8HeapObject&) = default;
821cb0ef41Sopenharmony_ciV8HeapObject& V8HeapObject::operator=(V8HeapObject&&) = default;
831cb0ef41Sopenharmony_ci
841cb0ef41Sopenharmony_cistd::vector<Property> GetPropertiesAsVector(size_t num_properties,
851cb0ef41Sopenharmony_ci                                            d::ObjectProperty** properties) {
861cb0ef41Sopenharmony_ci  std::vector<Property> result;
871cb0ef41Sopenharmony_ci  for (size_t property_index = 0; property_index < num_properties;
881cb0ef41Sopenharmony_ci       ++property_index) {
891cb0ef41Sopenharmony_ci    const auto& source_prop = *(properties)[property_index];
901cb0ef41Sopenharmony_ci    Property dest_prop(ConvertToU16String(source_prop.name),
911cb0ef41Sopenharmony_ci                       ConvertToU16String(source_prop.type),
921cb0ef41Sopenharmony_ci                       source_prop.decompressed_type, source_prop.address,
931cb0ef41Sopenharmony_ci                       source_prop.size);
941cb0ef41Sopenharmony_ci    if (source_prop.kind != d::PropertyKind::kSingle) {
951cb0ef41Sopenharmony_ci      dest_prop.type = PropertyType::kArray;
961cb0ef41Sopenharmony_ci      dest_prop.length = source_prop.num_values;
971cb0ef41Sopenharmony_ci    }
981cb0ef41Sopenharmony_ci    if (dest_prop.type_name.empty() || source_prop.num_struct_fields > 0) {
991cb0ef41Sopenharmony_ci      // If the helper library didn't provide a type, then it should have
1001cb0ef41Sopenharmony_ci      // provided struct fields instead. Set the struct type flag and copy the
1011cb0ef41Sopenharmony_ci      // fields into the result.
1021cb0ef41Sopenharmony_ci      dest_prop.type =
1031cb0ef41Sopenharmony_ci          static_cast<PropertyType>(static_cast<int>(dest_prop.type) |
1041cb0ef41Sopenharmony_ci                                    static_cast<int>(PropertyType::kStruct));
1051cb0ef41Sopenharmony_ci      for (size_t field_index = 0; field_index < source_prop.num_struct_fields;
1061cb0ef41Sopenharmony_ci           ++field_index) {
1071cb0ef41Sopenharmony_ci        const auto& struct_field = *source_prop.struct_fields[field_index];
1081cb0ef41Sopenharmony_ci        dest_prop.fields.push_back({ConvertToU16String(struct_field.name),
1091cb0ef41Sopenharmony_ci                                    ConvertToU16String(struct_field.type),
1101cb0ef41Sopenharmony_ci                                    struct_field.decompressed_type,
1111cb0ef41Sopenharmony_ci                                    struct_field.offset, struct_field.num_bits,
1121cb0ef41Sopenharmony_ci                                    struct_field.shift_bits});
1131cb0ef41Sopenharmony_ci      }
1141cb0ef41Sopenharmony_ci    }
1151cb0ef41Sopenharmony_ci    result.push_back(dest_prop);
1161cb0ef41Sopenharmony_ci  }
1171cb0ef41Sopenharmony_ci  return result;
1181cb0ef41Sopenharmony_ci}
1191cb0ef41Sopenharmony_ci
1201cb0ef41Sopenharmony_ciV8HeapObject GetHeapObject(WRL::ComPtr<IDebugHostContext> sp_context,
1211cb0ef41Sopenharmony_ci                           uint64_t tagged_ptr, uint64_t referring_pointer,
1221cb0ef41Sopenharmony_ci                           const char* type_name, bool is_compressed) {
1231cb0ef41Sopenharmony_ci  // Read the value at the address, and see if it is a tagged pointer
1241cb0ef41Sopenharmony_ci
1251cb0ef41Sopenharmony_ci  V8HeapObject obj;
1261cb0ef41Sopenharmony_ci  MemReaderScope reader_scope(sp_context);
1271cb0ef41Sopenharmony_ci
1281cb0ef41Sopenharmony_ci  d::HeapAddresses heap_addresses = {0, 0, 0, 0};
1291cb0ef41Sopenharmony_ci  // TODO ideally we'd provide real heap page pointers. For now, just testing
1301cb0ef41Sopenharmony_ci  // decompression based on the pointer to wherever we found this value,
1311cb0ef41Sopenharmony_ci  // which is likely (though not guaranteed) to be a heap pointer itself.
1321cb0ef41Sopenharmony_ci  heap_addresses.any_heap_pointer = referring_pointer;
1331cb0ef41Sopenharmony_ci
1341cb0ef41Sopenharmony_ci  auto props = d::GetObjectProperties(tagged_ptr, reader_scope.GetReader(),
1351cb0ef41Sopenharmony_ci                                      heap_addresses, type_name);
1361cb0ef41Sopenharmony_ci  obj.friendly_name = ConvertToU16String(props->brief);
1371cb0ef41Sopenharmony_ci  obj.properties =
1381cb0ef41Sopenharmony_ci      GetPropertiesAsVector(props->num_properties, props->properties);
1391cb0ef41Sopenharmony_ci
1401cb0ef41Sopenharmony_ci  // For each guessed type, create a synthetic property that will request data
1411cb0ef41Sopenharmony_ci  // about the same object again but with a more specific type hint.
1421cb0ef41Sopenharmony_ci  if (referring_pointer != 0) {
1431cb0ef41Sopenharmony_ci    for (size_t type_index = 0; type_index < props->num_guessed_types;
1441cb0ef41Sopenharmony_ci         ++type_index) {
1451cb0ef41Sopenharmony_ci      const std::string& type_name = props->guessed_types[type_index];
1461cb0ef41Sopenharmony_ci      Property dest_prop(
1471cb0ef41Sopenharmony_ci          ConvertToU16String(("guessed type " + type_name).c_str()),
1481cb0ef41Sopenharmony_ci          ConvertToU16String(is_compressed ? kTaggedValue : type_name),
1491cb0ef41Sopenharmony_ci          type_name, referring_pointer,
1501cb0ef41Sopenharmony_ci          is_compressed ? i::kTaggedSize : sizeof(void*));
1511cb0ef41Sopenharmony_ci      obj.properties.push_back(dest_prop);
1521cb0ef41Sopenharmony_ci    }
1531cb0ef41Sopenharmony_ci  }
1541cb0ef41Sopenharmony_ci
1551cb0ef41Sopenharmony_ci  return obj;
1561cb0ef41Sopenharmony_ci}
1571cb0ef41Sopenharmony_ci
1581cb0ef41Sopenharmony_cistd::vector<std::u16string> ListObjectClasses() {
1591cb0ef41Sopenharmony_ci  const d::ClassList* class_list = d::ListObjectClasses();
1601cb0ef41Sopenharmony_ci  std::vector<std::u16string> result;
1611cb0ef41Sopenharmony_ci  for (size_t i = 0; i < class_list->num_class_names; ++i) {
1621cb0ef41Sopenharmony_ci    result.push_back(ConvertToU16String(class_list->class_names[i]));
1631cb0ef41Sopenharmony_ci  }
1641cb0ef41Sopenharmony_ci  return result;
1651cb0ef41Sopenharmony_ci}
1661cb0ef41Sopenharmony_ci
1671cb0ef41Sopenharmony_ciconst char* BitsetName(uint64_t payload) { return d::BitsetName(payload); }
1681cb0ef41Sopenharmony_ci
1691cb0ef41Sopenharmony_cistd::vector<Property> GetStackFrame(WRL::ComPtr<IDebugHostContext> sp_context,
1701cb0ef41Sopenharmony_ci
1711cb0ef41Sopenharmony_ci                                    uint64_t frame_pointer) {
1721cb0ef41Sopenharmony_ci  MemReaderScope reader_scope(sp_context);
1731cb0ef41Sopenharmony_ci  auto props = d::GetStackFrame(static_cast<uintptr_t>(frame_pointer),
1741cb0ef41Sopenharmony_ci                                reader_scope.GetReader());
1751cb0ef41Sopenharmony_ci  return GetPropertiesAsVector(props->num_properties, props->properties);
1761cb0ef41Sopenharmony_ci}
177