Delen via


Aangepaste intrinsieke functie van NatVis implementeren voor C++

In dit artikel leert u meer over de richtlijnen voor het implementeren van een aangepaste intrinsieke functie binnen een NatVis-visualisatie. Zie Aangepaste weergaven maken van C++-objectenvoor meer informatie over NatVis.

Syntaxis

Een NatVis-bestand kan een intrinsieke functie definiëren met behulp van de volgende syntaxis:

<Intrinsic Name="Func" Expression="arg + 1">
  <Parameter Name="arg" Type="int" />
</Intrinsic>

Zodra de definitie bestaat, kan elke foutopsporingsprogramma-expressie de functie aanroepen, net als elke andere functie. Als u bijvoorbeeld de voorgaande NatVis-definitie gebruikt, resulteert de expressie Func(3) in 4.

Een <Intrinsic>-element kan worden weergegeven op bestandsniveau of in een <Type> element, vóór eventuele andere elementen. Intrinsieke functies die zijn gedefinieerd in een <Type> lidfuncties van dat type definiëren, terwijl intrinsieke functies die buiten een <Type> globale functies definiëren. Bijvoorbeeld:

<?xml version="1.0" encoding="utf-8"?>
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
  <Type Name="std::vector&lt;*&gt;">
    <Intrinsic Name="size" Expression="_Mypair._Myval2._Mylast - _Mypair._Myval2._Myfirst" />
    <Intrinsic Name="capacity" Expression="_Mypair._Myval2._Myend - _Mypair._Myval2._Myfirst" />
  </Type>
  <Intrinsic Name="LOWORD" Expression="arg & 0xFFFF">
    <Parameter Name="arg" Type="unsigned int" />
  </Intrinsic>
</AutoVisualizer>

In het voorgaande voorbeeld worden size() en capacity() gedefinieerd als lidfuncties van de std::vector-klasse, dus wanneer een expressie vector.size()evalueert, wordt vector._Mypair._Myval2._Mylast - vector._Mypair._Myval2._Myfirstdaadwerkelijk geëvalueerd in plaats van een func-eval uit te voeren. Op dezelfde manier retourneert LOWORD(0x12345678)0x5678, ook zonder func-eval.

Zie de Intrinsieke uitbreidingvoor een ander voorbeeld.

Richtlijnen voor het gebruik van een intrinsieke functie

Houd rekening met de volgende richtlijnen bij het gebruik van een intrinsieke functie:

  • Intrinsieke functies kunnen overbelast zijn, hetzij met door PDB gedefinieerde functies of met elkaar.

  • Wanneer een intrinsieke functie conflicteert met een door PDB gedefinieerde functie met dezelfde naam en argumentlijst, wint de intrinsieke functie. U kunt de PDB-functie niet uitvoeren als er een equivalente intrinsieke functie bestaat.

  • U kunt het adres van een intrinsieke functie niet aannemen; u kunt het alleen aanroepen.

  • Intrinsieke lidfuncties moeten behoren tot de standaardweergave van het betreffende type om te kunnen worden geëvalueerd in een expressie. Een typevermelding met een IncludeView beperking kan bijvoorbeeld geen intrinsieke functie opgeven.

  • Intrinsieke functies kunnen worden aangeroepen vanuit elke expressie, met inbegrip van NatVis-expressies. Intrinsieke functies kunnen elkaar ook aanroepen. Intrinsieke functies die gebruikmaken van recursie worden momenteel echter niet ondersteund. Bijvoorbeeld:

    <!-- OK -->
    <Intrinsic Name="Func2" Expression="this-&gt;Func3(arg + 1)">
      <Parameter Name="arg" Type="int" />
    </Intrinsic>
    <Intrinsic Name="Func3" Expression="arg + 1">
      <Parameter Name="arg" Type="int"/>
    </Intrinsic>
    
    <!-- Unsupported -->
    <Intrinsic Name="Func2" Expression="this-&gt;Func3(arg + 1)">
      <Parameter Name="arg" Type="int" />
    </Intrinsic>
    <Intrinsic Name="Func3" Expression="Func2(arg + 1)">
      <Parameter Name="arg" Type="int"/>
    </Intrinsic>
    
    <!-- Also unsupported-->
    <Intrinsic Name="Fib" Expression="(n &lt;= 1) ? 1 : Fib(n - 1) + Fib(n - 2)">
      <Parameter Name="n" Type="int"/>
    </Intrinsic>
    
  • Standaard wordt ervan uitgegaan dat intrinsieke functies neveneffectvrij zijn. Dat wil gezegd, ze kunnen worden aangeroepen in contexten die bijwerkingen niet toestaan en de implementatie-expressie mag geen bijwerkingen bevatten.

    De definitie kan dit gedrag overschrijven door het kenmerk SideEffect in de declaratie op te geven. Als de functie is gemarkeerd als bijwerkingen, worden bijwerkingen in de implementatie-expressie toegestaan. Het aanroepen van de functie in contexten waarbij bijwerkingen niet meer zijn toegestaan, is echter niet meer toegestaan.

  • Wanneer de definities van twee intrinsieke functies met elkaar conflicteren (dezelfde naam, dezelfde handtekening), wint de laatste (binnen hetzelfde bestand).

    Binnen verschillende bestanden heeft het exemplaar in het bestand met hogere prioriteit voorrang (projectmap heeft hogere prioriteit dan de gebruikersmap, die hogere prioriteit heeft dan de installatiemap). Als een definitie met een hogere prioriteit een expressie bevat die niet wordt geparseerd, wordt die definitie genegeerd en wordt in plaats daarvan de definitie met de hoogste prioriteit gebruikt.

Richtlijnen voor het implementeren van een intrinsieke functie

Intrinsieke functies ondersteunen twee mogelijke vormen van implementatie:

  • Op expressies gebaseerd

    Het NatVis-bestand definieert een expressie die resulteert in de retourwaarde van de functie. De expressie kan alle argumenten gebruiken die erin zijn doorgegeven als <Parameter> elementen. Functies die binnen een klasse zijn gedefinieerd, worden verondersteld 'instantie'-functies te zijn en kunnen ook de 'this'-pointer benaderen.

  • Op basis van extensies

    Het NatVis-bestand bevat instructies voor het aanroepen van een foutopsporingsprogramma-extensie om de functie daadwerkelijk te evalueren. Een foutopsporingsprogramma-extensie heeft volledige toegang tot de Concord-API en heeft de mogelijkheid om taken uit te voeren die niet mogelijk zijn binnen een NatVis-expressie.

Als u een implementatie op basis van extensies wilt bieden, moet het <Intrinsic> element het kenmerk Expression weglaten en in plaats daarvan SourceId, LanguageId, Iden ReturnType kenmerken opgeven, zoals is opgegeven in het volgende voorbeeld:

<Intrinsic Name="MyFunc" SourceId="a665fa54-6e7d-480e-a80b-1fc1202e9646" LanguageId="3a12d0b7-c26c-11d0-b442-00a0244a1dd2" Id="1000" ReturnType="double">
  <Parameter Type="int" />
  <Parameter Type="int" />
  <Parameter Type="int" />
</Intrinsic>

Als u de functie wilt implementeren, moet de extensie voor foutopsporingsprogramma de IDkmIntrinsicFunctionEvaluator140-interface implementeren met behulp van LanguageId- en SourceId-filters die overeenkomen met de bijbehorende waarden van het <Intrinsic>-element in het NatVis-bestand. Wanneer de functie wordt aangeroepen, wordt de aanroep omgezet in de Execute() methode van het onderdeel:

STDMETHOD(Execute)(
    _In_ Evaluation::IL::DkmILExecuteIntrinsic* pExecuteIntrinsic,
    _In_ Evaluation::DkmILContext* pILContext,
    _In_ Evaluation::IL::DkmCompiledILInspectionQuery* pInspectionQuery,
    _In_ const DkmArray<Evaluation::IL::DkmILEvaluationResult*>& Arguments,
    _In_opt_ DkmReadOnlyCollection<Evaluation::DkmCompiledInspectionQuery*>* pSubroutines,
    _Out_ DkmArray<Evaluation::IL::DkmILEvaluationResult*>* pResults,
    _Out_ Evaluation::IL::DkmILFailureReason* pFailureReason
    );

Het onderdeel ontvangt de bytes van elk argument via het argument Arguments. Als de betreffende functie een lidfunctie is, komt de this aanwijzer eerst, gevolgd door de expliciete argumenten. Het onderdeel moet het resultaat retourneren door een matrix met één element toe te wijzen in pResults, waarbij de bytes van de retourwaarde worden opgeslagen.

Gebruik de volgende richtlijnen om functies te implementeren:

  • Het is illegaal om de twee implementatieformulieren te combineren en te matchen. Dat wil gezegd, u kunt niet zowel een expressie als een bron-id opnemen.

  • Het opgeven van een retourtype voor een implementatie op basis van expressies is toegestaan, maar niet vereist. Als een retourtype is opgegeven, moet het retourtype van de expressie exact overeenkomen (geen impliciete cast-conversie is toegestaan). Als er geen retourtype is opgegeven, wordt het retourtype afgeleid van de expressie. Elke implementatie op basis van extensies moet een retourtype in het NatVis-bestand aangeven.

  • Niet-recursieve aanroepen naar andere intrinsieke functies zijn toegestaan. Recursie is niet toegestaan.

  • Als de functie bijwerkingen heeft, moet u SideEffect="true" opgeven in de declaratie. Het is onwettig voor een implementatie op basis van expressies om bijwerkingen in de expressie te veroorzaken zonder dat de functie voor bijwerkingen is gedeclareerd. Het is ongedefinieerd gedrag om een implementatie op basis van extensies aan te roepen waardoor er bijwerkingen optreden zonder de functie als zodanig te declareren, en dit dient te worden vermeden.

  • Intrinsieke functies van Varargs zijn toegestaan. Als u een varargs-functie wilt declareren, geeft u Varargs="true" op in de declaratie. Hoewel het juridisch is voor een implementatie op basis van expressies om een vararg functie te declareren, hebben alleen implementaties op basis van extensies een manier om toegang te krijgen tot de variabeleargumenten. Met een implementatie op basis van extensies ontvangt de functie Execute() alle argumenten die daadwerkelijk worden doorgegeven, niet alleen de gedeclareerde argumenten.

  • Intrinsieke functies die een type klasse/struct/samenvoeging als argumenttype gebruiken, worden niet ondersteund. Het retourneren van een klasse/struct/samenvoegingstype is OK. (Een aanwijzer of verwijzing naar een klasse/struct/samenvoegingstype is OK als argumenttype).

Pas het pictogram aan voor aanroepen naar intrinsieke functies.

Wanneer u een intrinsieke functie aanroept, krijgt de expressie standaard het roze ruitpictogram in het venster Watch dat is gekoppeld aan functieaanroepen. U kunt dit gedrag overschrijven door het kenmerk Category op te geven met behulp van een van de volgende waarden:

  • Methode. Gebruik het roze ruitpictogram, meestal gebruikt met methode-aanroepen (standaard).
  • Eigenschap. Gebruik het zwarte sleutelpictogram, dat meestal met eigenschappen wordt gebruikt.
  • Gegevens. Gebruik het blauwe ruitpictogram, meestal gebruikt met gegevens.

Door intrinsieke functies te combineren met het <Item>-element, is het mogelijk om een NatVis-bestand te maken waarin itemexpressies het sleuteltje-eigenschapspictogram hebben:

<Type Name="MyClass">
  <Intrinsic Name="GetValue" ReturnType="int" Expression="m_value" Category="Property" />
  <Expand>
    <Item Name="Value">this-&gt;GetValue()</Item>
  </Expand>
</Type>

Notitie

Als u de pictogramkeuze op het functieniveau plaatst in plaats van het <Item> niveau, voorkomt u problemen waarbij de pictogramaanpassing verloren gaat wanneer de volledige naam wordt geëvalueerd. Omdat de volledige naam een aanroep naar de functie bevat, heeft deze dezelfde pictogramaanpassing als de <Item> zelf.