// 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/base/utilities.h" #include #include #include namespace { HRESULT BoxObject(IDataModelManager* p_manager, IUnknown* p_object, ModelObjectKind kind, IModelObject** pp_model_object) { *pp_model_object = nullptr; VARIANT vt_val; vt_val.vt = VT_UNKNOWN; vt_val.punkVal = p_object; HRESULT hr = p_manager->CreateIntrinsicObject(kind, &vt_val, pp_model_object); return hr; } } // namespace HRESULT CreateProperty(IDataModelManager* p_manager, IModelPropertyAccessor* p_property, IModelObject** pp_property_object) { return BoxObject(p_manager, p_property, ObjectPropertyAccessor, pp_property_object); } HRESULT CreateMethod(IDataModelManager* p_manager, IModelMethod* p_method, IModelObject** pp_method_object) { return BoxObject(p_manager, p_method, ObjectMethod, pp_method_object); } HRESULT UnboxProperty(IModelObject* object, IModelPropertyAccessor** result) { ModelObjectKind kind = (ModelObjectKind)-1; RETURN_IF_FAIL(object->GetKind(&kind)); if (kind != ObjectPropertyAccessor) return E_FAIL; _variant_t variant; RETURN_IF_FAIL(object->GetIntrinsicValue(&variant)); if (variant.vt != VT_UNKNOWN) return E_FAIL; WRL::ComPtr accessor; RETURN_IF_FAIL(WRL::ComPtr(variant.punkVal).As(&accessor)); *result = accessor.Detach(); return S_OK; } HRESULT CreateTypedIntrinsic(uint64_t value, IDebugHostType* type, IModelObject** result) { // Figure out what kind of VARIANT we need to make. IntrinsicKind kind; VARTYPE carrier; RETURN_IF_FAIL(type->GetIntrinsicType(&kind, &carrier)); VARIANT vt_val; switch (carrier) { case VT_BOOL: vt_val.boolVal = value ? VARIANT_TRUE : VARIANT_FALSE; break; case VT_I1: vt_val.cVal = static_cast(value); break; case VT_UI1: vt_val.bVal = static_cast(value); break; case VT_I2: vt_val.iVal = static_cast(value); break; case VT_UI2: vt_val.uiVal = static_cast(value); break; case VT_INT: vt_val.intVal = static_cast(value); break; case VT_UINT: vt_val.uintVal = static_cast(value); break; case VT_I4: vt_val.lVal = static_cast(value); break; case VT_UI4: vt_val.ulVal = static_cast(value); break; case VT_INT_PTR: vt_val.llVal = static_cast(value); break; case VT_UINT_PTR: vt_val.ullVal = static_cast(value); break; case VT_I8: vt_val.llVal = static_cast(value); break; case VT_UI8: vt_val.ullVal = static_cast(value); break; default: return E_FAIL; } vt_val.vt = carrier; return sp_data_model_manager->CreateTypedIntrinsicObject(&vt_val, type, result); } HRESULT CreateULong64(ULONG64 value, IModelObject** pp_int) { HRESULT hr = S_OK; *pp_int = nullptr; VARIANT vt_val; vt_val.vt = VT_UI8; vt_val.ullVal = value; hr = sp_data_model_manager->CreateIntrinsicObject(ObjectIntrinsic, &vt_val, pp_int); return hr; } HRESULT UnboxULong64(IModelObject* object, ULONG64* value, bool convert) { ModelObjectKind kind = (ModelObjectKind)-1; RETURN_IF_FAIL(object->GetKind(&kind)); if (kind != ObjectIntrinsic) return E_FAIL; _variant_t variant; RETURN_IF_FAIL(object->GetIntrinsicValue(&variant)); if (convert) { RETURN_IF_FAIL(VariantChangeType(&variant, &variant, 0, VT_UI8)); } if (variant.vt != VT_UI8) return E_FAIL; *value = variant.ullVal; return S_OK; } HRESULT GetInt32(IDebugHostConstant* object, int* value) { variant_t variant; RETURN_IF_FAIL(object->GetValue(&variant)); if (variant.vt != VT_I4) return E_FAIL; *value = variant.lVal; return S_OK; } HRESULT CreateInt32(int value, IModelObject** pp_int) { HRESULT hr = S_OK; *pp_int = nullptr; VARIANT vt_val; vt_val.vt = VT_I4; vt_val.intVal = value; hr = sp_data_model_manager->CreateIntrinsicObject(ObjectIntrinsic, &vt_val, pp_int); return hr; } HRESULT CreateUInt32(uint32_t value, IModelObject** pp_int) { HRESULT hr = S_OK; *pp_int = nullptr; VARIANT vt_val; vt_val.vt = VT_UI4; vt_val.uintVal = value; hr = sp_data_model_manager->CreateIntrinsicObject(ObjectIntrinsic, &vt_val, pp_int); return hr; } HRESULT CreateBool(bool value, IModelObject** pp_val) { HRESULT hr = S_OK; *pp_val = nullptr; VARIANT vt_val; vt_val.vt = VT_BOOL; vt_val.boolVal = value; hr = sp_data_model_manager->CreateIntrinsicObject(ObjectIntrinsic, &vt_val, pp_val); return hr; } HRESULT CreateNumber(double value, IModelObject** pp_val) { HRESULT hr = S_OK; *pp_val = nullptr; VARIANT vt_val; vt_val.vt = VT_R8; vt_val.dblVal = value; hr = sp_data_model_manager->CreateIntrinsicObject(ObjectIntrinsic, &vt_val, pp_val); return hr; } HRESULT CreateString(std::u16string value, IModelObject** pp_val) { HRESULT hr = S_OK; *pp_val = nullptr; VARIANT vt_val; vt_val.vt = VT_BSTR; vt_val.bstrVal = ::SysAllocString(reinterpret_cast(value.c_str())); hr = sp_data_model_manager->CreateIntrinsicObject(ObjectIntrinsic, &vt_val, pp_val); return hr; } HRESULT UnboxString(IModelObject* object, BSTR* value) { ModelObjectKind kind = (ModelObjectKind)-1; RETURN_IF_FAIL(object->GetKind(&kind)); if (kind != ObjectIntrinsic) return E_FAIL; _variant_t variant; RETURN_IF_FAIL(object->GetIntrinsicValue(&variant)); if (variant.vt != VT_BSTR) return E_FAIL; *value = variant.Detach().bstrVal; return S_OK; } HRESULT GetModelAtIndex(WRL::ComPtr& sp_parent, WRL::ComPtr& sp_index, IModelObject** p_result) { WRL::ComPtr sp_indexable_concept; RETURN_IF_FAIL(sp_parent->GetConcept(__uuidof(IIndexableConcept), &sp_indexable_concept, nullptr)); std::vector p_indexers{sp_index.Get()}; return sp_indexable_concept->GetAt(sp_parent.Get(), 1, p_indexers.data(), p_result, nullptr); } HRESULT GetCurrentThread(WRL::ComPtr& sp_host_context, IModelObject** p_current_thread) { WRL::ComPtr sp_boxed_context, sp_root_namespace; WRL::ComPtr sp_debugger, sp_sessions, sp_processes, sp_threads; WRL::ComPtr sp_curr_session, sp_curr_process; RETURN_IF_FAIL(BoxObject(sp_data_model_manager.Get(), sp_host_context.Get(), ObjectContext, &sp_boxed_context)); RETURN_IF_FAIL(sp_data_model_manager->GetRootNamespace(&sp_root_namespace)); RETURN_IF_FAIL( sp_root_namespace->GetKeyValue(L"Debugger", &sp_debugger, nullptr)); RETURN_IF_FAIL(sp_debugger->GetKeyValue(L"Sessions", &sp_sessions, nullptr)); RETURN_IF_FAIL( GetModelAtIndex(sp_sessions, sp_boxed_context, &sp_curr_session)); RETURN_IF_FAIL( sp_curr_session->GetKeyValue(L"Processes", &sp_processes, nullptr)); RETURN_IF_FAIL( GetModelAtIndex(sp_processes, sp_boxed_context, &sp_curr_process)); RETURN_IF_FAIL( sp_curr_process->GetKeyValue(L"Threads", &sp_threads, nullptr)); return GetModelAtIndex(sp_threads, sp_boxed_context, p_current_thread); }