Skip to content

Commit

Permalink
per request, provide implementation-side visualizations. and always s…
Browse files Browse the repository at this point in the history
…how raw data. (#1128)
  • Loading branch information
Scottj1s authored Mar 24, 2022
1 parent 27adc6b commit b69f40d
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 43 deletions.
5 changes: 5 additions & 0 deletions natvis/cppwinrt.natvis
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@
<CustomVisualizer Condition="this != 0" VisualizerId="2ec1a02f-997c-4693-840e-88ffa1e21b56"/>
<DisplayString Condition="this == 0">null</DisplayString>
</Type>
<!-- Visualize C++/WinRT object implementations -->
<Type Name="winrt::impl::producer&lt;*&gt;">
<CustomVisualizer Condition="this != 0" VisualizerId="2ec1a02f-997c-4693-840e-88ffa1e21b56"/>
<DisplayString Condition="this == 0">null</DisplayString>
</Type>
<!--Visualize all raw IInspectable pointers-->
<Type Name="IInspectable">
<CustomVisualizer Condition="this != 0" VisualizerId="2ec1a02f-997c-4693-840e-88ffa1e21b56"/>
Expand Down
15 changes: 10 additions & 5 deletions natvis/cppwinrt_visualizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -207,21 +207,26 @@ HRESULT cppwinrt_visualizer::EvaluateVisualizedExpression(
IF_FAIL_RET(pTypeSymbol->get_name(&bstrTypeName));

// Visualize top-level C++/WinRT objects containing ABI pointers
bool isAbiObject;
ObjectType objectType;
if (wcscmp(bstrTypeName, L"winrt::Windows::Foundation::IInspectable") == 0)
{
isAbiObject = false;
objectType = ObjectType::Projection;
}
// Visualize nested object properties via raw ABI pointers
else if ((wcscmp(bstrTypeName, L"winrt::impl::IInspectable") == 0) ||
(wcscmp(bstrTypeName, L"winrt::impl::inspectable_abi") == 0))
{
isAbiObject = true;
objectType = ObjectType::Abi;
}
// Visualize C++/WinRT object implementations
else if (wcsncmp(bstrTypeName, L"winrt::impl::producer<", wcslen(L"winrt::impl::producer<")) == 0)
{
objectType = ObjectType::Abi;
}
// Visualize all raw IInspectable pointers
else if (wcscmp(bstrTypeName, L"IInspectable") == 0)
{
isAbiObject = true;
objectType = ObjectType::Abi;
}
else
{
Expand All @@ -231,7 +236,7 @@ HRESULT cppwinrt_visualizer::EvaluateVisualizedExpression(
return S_OK;
}

IF_FAIL_RET(object_visualizer::CreateEvaluationResult(pVisualizedExpression, isAbiObject, ppResultObject));
IF_FAIL_RET(object_visualizer::CreateEvaluationResult(pVisualizedExpression, objectType, ppResultObject));

return S_OK;
}
Expand Down
54 changes: 20 additions & 34 deletions natvis/object_visualizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,14 +99,14 @@ static HRESULT EvaluatePropertyExpression(
_In_ PropertyData const& prop,
_In_ DkmVisualizedExpression* pExpression,
_In_ DkmPointerValueHome* pObject,
bool isAbiObject,
ObjectType objectType,
_Out_ com_ptr<DkmEvaluationResult>& pEvaluationResult
)
{
wchar_t abiAddress[40];
auto process = pExpression->RuntimeInstance()->Process();
bool is64Bit = ((process->SystemInformation()->Flags() & DefaultPort::DkmSystemInformationFlags::Is64Bit) != 0);
swprintf_s(abiAddress, is64Bit ? L"%s0x%I64x" : L"%s0x%08x", isAbiObject ? L"(::IUnknown*)" : L"*(::IUnknown**)", pObject->Address());
swprintf_s(abiAddress, is64Bit ? L"%s0x%I64x" : L"%s0x%08x", objectType == ObjectType::Abi ? L"(::IUnknown*)" : L"*(::IUnknown**)", pObject->Address());
wchar_t wszEvalText[500];
std::wstring propCast;
PCWSTR propField;
Expand Down Expand Up @@ -174,12 +174,12 @@ static HRESULT EvaluatePropertyString(
_In_ PropertyData const& prop,
_In_ DkmVisualizedExpression* pExpression,
_In_ DkmPointerValueHome* pObject,
bool isAbiObject,
ObjectType objectType,
_Out_ com_ptr<DkmString>& pValue
)
{
com_ptr<DkmEvaluationResult> pEvaluationResult;
IF_FAIL_RET(EvaluatePropertyExpression(prop, pExpression, pObject, isAbiObject, pEvaluationResult));
IF_FAIL_RET(EvaluatePropertyExpression(prop, pExpression, pObject, objectType, pEvaluationResult));
if (pEvaluationResult->TagValue() != DkmEvaluationResult::Tag::SuccessResult)
{
return E_FAIL;
Expand All @@ -195,11 +195,11 @@ static HRESULT EvaluatePropertyString(
static std::string GetRuntimeClass(
_In_ DkmVisualizedExpression* pExpression,
_In_ DkmPointerValueHome* pObject,
bool isAbiObject
ObjectType objectType
)
{
com_ptr<DkmString> pValue;
EvaluatePropertyString({ IID_IInspectable, -2, PropertyCategory::String }, pExpression, pObject, isAbiObject, pValue);
EvaluatePropertyString({ IID_IInspectable, -2, PropertyCategory::String }, pExpression, pObject, objectType, pValue);
if (!pValue || pValue->Length() == 0)
{
return "";
Expand All @@ -210,16 +210,11 @@ static std::string GetRuntimeClass(
static HRESULT ObjectToString(
_In_ DkmVisualizedExpression* pExpression,
_In_ DkmPointerValueHome* pObject,
bool isAbiObject,
_Out_ com_ptr<DkmString>& pValue,
bool* unavailable = nullptr
ObjectType objectType,
_Out_ com_ptr<DkmString>& pValue
)
{
if (unavailable)
{
*unavailable = false;
}
if (SUCCEEDED(EvaluatePropertyString({ IID_IStringable, 0, PropertyCategory::String }, pExpression, pObject, isAbiObject, pValue)))
if (SUCCEEDED(EvaluatePropertyString({ IID_IStringable, 0, PropertyCategory::String }, pExpression, pObject, objectType, pValue)))
{
if (pValue && pValue->Length() > 0)
{
Expand All @@ -229,25 +224,21 @@ static HRESULT ObjectToString(

// WINRT_abi_val returned 0, which may be success or failure (due to VirtualQuery validation)
// Call back for the runtime class name to determine which it was
if (!GetRuntimeClass(pExpression, pObject, isAbiObject).empty())
if (!GetRuntimeClass(pExpression, pObject, objectType).empty())
{
return DkmString::Create(L"<Expand object to view properties>", pValue.put());
}
}

// VirtualQuery validation failed (as determined by no runtime class name) or an
// exception escaped WINRT_abi_val (e.g, bad pointer, which we try to avoid via VirtualQuery)
if (unavailable)
{
*unavailable = true;
}
return DkmString::Create(L"<Object uninitialized or information unavailable>", pValue.put());
}

static HRESULT CreateChildVisualizedExpression(
_In_ PropertyData const& prop,
_In_ DkmVisualizedExpression* pParent,
bool isAbiObject,
ObjectType objectType,
_Deref_out_ DkmChildVisualizedExpression** ppResult
)
{
Expand All @@ -256,7 +247,7 @@ static HRESULT CreateChildVisualizedExpression(
com_ptr<DkmEvaluationResult> pEvaluationResult;
auto valueHome = make_com_ptr(pParent->ValueHome());
com_ptr<DkmPointerValueHome> pParentPointer = valueHome.as<DkmPointerValueHome>();
IF_FAIL_RET(EvaluatePropertyExpression(prop, pParent, pParentPointer.get(), isAbiObject, pEvaluationResult));
IF_FAIL_RET(EvaluatePropertyExpression(prop, pParent, pParentPointer.get(), objectType, pEvaluationResult));
if (pEvaluationResult->TagValue() != DkmEvaluationResult::Tag::SuccessResult)
{
return E_FAIL;
Expand All @@ -273,7 +264,7 @@ static HRESULT CreateChildVisualizedExpression(
{
isNonNullObject = true;
IF_FAIL_RET(DkmPointerValueHome::Create(childObjectAddress, pChildPointer.put()));
IF_FAIL_RET(ObjectToString(pParent, pChildPointer.get(), true, pValue));
IF_FAIL_RET(ObjectToString(pParent, pChildPointer.get(), ObjectType::Abi, pValue));
}
}
if(!isNonNullObject)
Expand Down Expand Up @@ -335,7 +326,7 @@ static HRESULT CreateChildVisualizedExpression(

if (isNonNullObject)
{
com_ptr<object_visualizer> pObjectVisualizer = make_self<object_visualizer>(pChildVisualizedExpression.get(), true);
com_ptr<object_visualizer> pObjectVisualizer = make_self<object_visualizer>(pChildVisualizedExpression.get(), ObjectType::Abi);
IF_FAIL_RET(pChildVisualizedExpression->SetDataItem(DkmDataCreationDisposition::CreateNew, pObjectVisualizer.get()));
}
else
Expand Down Expand Up @@ -492,7 +483,7 @@ void object_visualizer::GetPropertyData()
{
auto valueHome = make_com_ptr(m_pVisualizedExpression->ValueHome());
com_ptr<DkmPointerValueHome> pObject = valueHome.as<DkmPointerValueHome>();
auto rc = GetRuntimeClass(m_pVisualizedExpression.get(), pObject.get(), m_isAbiObject);
auto rc = GetRuntimeClass(m_pVisualizedExpression.get(), pObject.get(), m_objectType);
if (rc.empty())
{
return;
Expand Down Expand Up @@ -539,9 +530,9 @@ void object_visualizer::GetTypeProperties(Microsoft::VisualStudio::Debugger::Dkm
}
}

HRESULT object_visualizer::CreateEvaluationResult(_In_ DkmVisualizedExpression* pVisualizedExpression, _In_ bool isAbiObject, _Deref_out_ DkmEvaluationResult** ppResultObject)
HRESULT object_visualizer::CreateEvaluationResult(_In_ DkmVisualizedExpression* pVisualizedExpression, _In_ ObjectType objectType, _Deref_out_ DkmEvaluationResult** ppResultObject)
{
com_ptr<object_visualizer> pObjectVisualizer = make_self<object_visualizer>(pVisualizedExpression, isAbiObject);
com_ptr<object_visualizer> pObjectVisualizer = make_self<object_visualizer>(pVisualizedExpression, objectType);

IF_FAIL_RET(pVisualizedExpression->SetDataItem(DkmDataCreationDisposition::CreateNew, pObjectVisualizer.get()));

Expand Down Expand Up @@ -582,7 +573,7 @@ HRESULT object_visualizer::CreateEvaluationResult(_Deref_out_ DkmEvaluationResul
auto address = pPointerValueHome->Address();

com_ptr<DkmString> pValue;
DkmEvaluationResultFlags_t evalResultFlags = DkmEvaluationResultFlags::ReadOnly;
DkmEvaluationResultFlags_t evalResultFlags = DkmEvaluationResultFlags::ReadOnly | DkmEvaluationResultFlags::Expandable;;
if (requires_refresh(address, m_pVisualizedExpression->InspectionContext()->EvaluationFlags()))
{
IF_FAIL_RET(DkmString::Create(L"<Refresh to view properties>", pValue.put()));
Expand All @@ -591,12 +582,7 @@ HRESULT object_visualizer::CreateEvaluationResult(_Deref_out_ DkmEvaluationResul
else
{
cache_refresh(address);
bool unavailable;
IF_FAIL_RET(ObjectToString(m_pVisualizedExpression.get(), pPointerValueHome.get(), m_isAbiObject, pValue, &unavailable));
if (!unavailable)
{
evalResultFlags |= DkmEvaluationResultFlags::Expandable;
}
IF_FAIL_RET(ObjectToString(m_pVisualizedExpression.get(), pPointerValueHome.get(), m_objectType, pValue));
}

com_ptr<DkmDataAddress> pAddress;
Expand Down Expand Up @@ -689,7 +675,7 @@ HRESULT object_visualizer::GetItems(
{
auto& prop = m_propertyData[i + (size_t)StartIndex];
com_ptr<DkmChildVisualizedExpression> pPropertyVisualized;
if (FAILED(CreateChildVisualizedExpression(prop, pParent, m_isAbiObject, pPropertyVisualized.put())))
if(FAILED(CreateChildVisualizedExpression(prop, pParent, m_objectType, pPropertyVisualized.put())))
{
com_ptr<DkmString> pErrorMessage;
IF_FAIL_RET(DkmString::Create(L"<Property evaluation failed>", pErrorMessage.put()));
Expand Down
14 changes: 10 additions & 4 deletions natvis/object_visualizer.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@ enum class PropertyCategory
Class,
};

enum class ObjectType
{
Abi,
Projection,
};

// Metatdata for resolving a runtime class property value
struct PropertyData
{
Expand All @@ -36,17 +42,17 @@ struct PropertyData
struct __declspec(uuid("c7da92da-3bc9-4312-8a93-46f480663980"))
object_visualizer : winrt::implements<object_visualizer, ::IUnknown>
{
object_visualizer(Microsoft::VisualStudio::Debugger::Evaluation::DkmVisualizedExpression* pVisualizedExpression, bool isAbiObject)
object_visualizer(Microsoft::VisualStudio::Debugger::Evaluation::DkmVisualizedExpression* pVisualizedExpression, ObjectType objectType)
{
m_pVisualizedExpression = make_com_ptr(pVisualizedExpression);
m_isAbiObject = isAbiObject;
m_objectType = objectType;
}

~object_visualizer()
{
}

static HRESULT CreateEvaluationResult(_In_ Microsoft::VisualStudio::Debugger::Evaluation::DkmVisualizedExpression* pVisualizedExpression, _In_ bool isAbiObject, _Deref_out_ Microsoft::VisualStudio::Debugger::Evaluation::DkmEvaluationResult** ppResultObject);
static HRESULT CreateEvaluationResult(_In_ Microsoft::VisualStudio::Debugger::Evaluation::DkmVisualizedExpression* pVisualizedExpression, _In_ ObjectType objectType, _Deref_out_ Microsoft::VisualStudio::Debugger::Evaluation::DkmEvaluationResult** ppResultObject);

HRESULT CreateEvaluationResult(_Deref_out_ Microsoft::VisualStudio::Debugger::Evaluation::DkmEvaluationResult** ppResultObject);

Expand All @@ -69,7 +75,7 @@ object_visualizer : winrt::implements<object_visualizer, ::IUnknown>
void GetPropertyData();
void GetTypeProperties(Microsoft::VisualStudio::Debugger::DkmProcess* process, std::string_view const& type_name);
winrt::com_ptr<Microsoft::VisualStudio::Debugger::Evaluation::DkmVisualizedExpression> m_pVisualizedExpression;
bool m_isAbiObject;
ObjectType m_objectType;
std::vector<PropertyData> m_propertyData;
bool m_isStringable{ false };
};

0 comments on commit b69f40d

Please sign in to comment.