v8/tools/v8windbg/base/utilities.cc
Seth Brenith af76dd6e7e [tools] Add v8windbg, a WinDbg extension for V8
Please take a look at tools/v8windbg/README.md for an overview of what
v8windbg can do and how it's structured. This platform-specific
debugging plugin makes use of the data provided by the V8 postmortem
debugging API in tools/debug_helper.

Note: This code began as https://github.com/billti/v8dbg and then moved
into the Edge repository, where I added features gradually and got code
reviews for individual changes. Now, taken in its entirety, it's an
obnoxiously large CL. I'm open to breaking it up into a few chunks if
that would be preferable.

Bug: v8:9376
Change-Id: I3e503de00bb1aea870ae83e9bd99e4e2eab9ef98
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2031700
Reviewed-by: Michael Stanton <mvstanton@chromium.org>
Reviewed-by: Tamer Tas <tmrts@chromium.org>
Reviewed-by: Tobias Tebbi <tebbi@chromium.org>
Commit-Queue: Seth Brenith <seth.brenith@microsoft.com>
Cr-Commit-Position: refs/heads/master@{#66319}
2020-02-18 19:16:18 +00:00

247 lines
7.6 KiB
C++

// 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 <comutil.h>
#include <oleauto.h>
#include <vector>
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<IModelPropertyAccessor> accessor;
RETURN_IF_FAIL(WRL::ComPtr<IUnknown>(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<int8_t>(value);
break;
case VT_UI1:
vt_val.bVal = static_cast<uint8_t>(value);
break;
case VT_I2:
vt_val.iVal = static_cast<int16_t>(value);
break;
case VT_UI2:
vt_val.uiVal = static_cast<uint16_t>(value);
break;
case VT_INT:
vt_val.intVal = static_cast<int>(value);
break;
case VT_UINT:
vt_val.uintVal = static_cast<unsigned int>(value);
break;
case VT_I4:
vt_val.lVal = static_cast<int32_t>(value);
break;
case VT_UI4:
vt_val.ulVal = static_cast<uint32_t>(value);
break;
case VT_INT_PTR:
vt_val.llVal = static_cast<intptr_t>(value);
break;
case VT_UINT_PTR:
vt_val.ullVal = static_cast<uintptr_t>(value);
break;
case VT_I8:
vt_val.llVal = static_cast<int64_t>(value);
break;
case VT_UI8:
vt_val.ullVal = static_cast<uint64_t>(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 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<const OLECHAR*>(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<IModelObject>& sp_parent,
WRL::ComPtr<IModelObject>& sp_index,
IModelObject** p_result) {
WRL::ComPtr<IIndexableConcept> sp_indexable_concept;
RETURN_IF_FAIL(sp_parent->GetConcept(__uuidof(IIndexableConcept),
&sp_indexable_concept, nullptr));
std::vector<IModelObject*> p_indexers{sp_index.Get()};
return sp_indexable_concept->GetAt(sp_parent.Get(), 1, p_indexers.data(),
p_result, nullptr);
}
HRESULT GetCurrentThread(WRL::ComPtr<IDebugHostContext>& sp_host_context,
IModelObject** p_current_thread) {
WRL::ComPtr<IModelObject> sp_boxed_context, sp_root_namespace;
WRL::ComPtr<IModelObject> sp_debugger, sp_sessions, sp_processes, sp_threads;
WRL::ComPtr<IModelObject> 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);
}