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