Writing debugger type visualizers for C++ using .natvis files

Visual Studio 2012 introduces a new type visualization framework (natvis) for customizing the way C++ types are displayed in the debugger. This sample contains type visualizer examples and a simple project that demonstrates VSIX deployment of type visualizers.

C# (105.0 KB)
 
 
 
 
 
4.6 Star
(14)
3,655 times
Add to favorites
7/9/2012
E-mail Twitter del.icio.us Digg Facebook
Sign in to ask a question


  • Loops in natvis files
    2 Posts | Last post August 11, 2017
    • Hello Cagri,
      
      I am writing natvis files for a class which has a double pointer type. So, to be able to retrieve the data pointed to by the pointers, I need looping construct in the natvis file. Fortunately, there was one format posted by one ADRIAN here which I followed. But looks like it results in an error (which I am not able to find) and hence, the whole natvis file doesn't execute. Here is the code:
      
      <Type Name="Structrue">
              <DisplayString>Structure = {size}</DisplayString>
              <Expand>
      		<Item Name="Element1">element1</Item>
      		<Item Name="Element2">element2</Item>
      
      		<Item Name="Double Pointer">m_pointer</Item>
                      <Variable Name='i' InitialValue='0'/>
      		<Loop Condition='{i} &lt; {size}'>
      			<Item Name='Pointer{i}'>m_pointer[i]</Item>
      			<Exec>i++</Exec>
      		</Loop>
              </Expand>
          </Type>
      
      I am not sure what I am doing wrong. Please help.
      
      Esash
    • Sorry, missed the customListItems tag. 
      
      <Type Name="Structrue">
              <DisplayString>Structure = {size}</DisplayString>
              <Expand>
      		<Item Name="Element1">element1</Item>
      		<Item Name="Element2">element2</Item>
      
      		<Item Name="Double Pointer">m_pointer</Item>
                      <CustomListItems>
                      <Variable Name='i' InitialValue='0'/>
      		<Loop Condition='{i} &lt; {size}'>
      			<Item Name='Pointer{i}'>m_pointer[i]</Item>
      			<Exec>i++</Exec>
      		</Loop>
                      </CustomListItems>
              </Expand>
          </Type>
      
      But still doesn't work. :(
  • How to write a debugger type visualizer for a custom string type
    3 Posts | Last post January 04, 2017
    • I have a custom string type that represents the string as a pointer and a length. The buffered string data referenced by the pointer is not null terminated.
      
      How can I visualize such a string with a .natvis visualizer? I can do something like this:
      
      <Type Name="String">
          <DisplayString>[Len={m_length}] {m_data,s}</DisplayString>
      </Type>
      
      
      But the {m_data,s} assumes null termination, so this ends up displaying characters beyond the string's actual length.  Is there any way to supply the string's length in the c++ format specifier?
      
    • Yes - it would be
      <DisplayString>{m_data,[m_length],s}</DisplayString>
      
      ,s qualifier accepts array qualifiers (e.g. ,5s would show only 5 characters and [] mean 'the value of this variable')
      
      Hope it helps.
    • This is almost right: you should not separate array qualifier and s with a comma:
      <DisplayString>{m_data,[m_length]s}</DisplayString>
  • Visualizing MFC's CMap
    6 Posts | Last post November 18, 2016
    • In autoexp.dat I was able to visualise a CMap with something like this
      
      children
      (
          #(
              #array
              (
                  expr : ($c.m_pHashTable)[$i],
                  size : $c.m_nHashTableSize
              ) : #(
                  #list
                  (
                      head : $e,
                      next : pNext
                  )
              )
          )
      )
      
      However I cannot figure out how to get that nested linked list type of thing in the .natvis format. Additionally, this in autoexp.dat would only show the nodes which had actual values, as a m_HashTable might have 17 elements, but only one or two of those might have values inside it, and this would only show those.
      
      Any help in replicating this in natvis would be appreciated.
    • Sorry Paul, what you are trying to do is not supported by natvis. You can try modeling your entry based on CATLMap defined in atlmfc.natvis file under the installation directory. That would still show all the hashtable buckets though.
    • Is this still not possible with VS2013? I'm trying to get this to display info, also I can't find the atlmfc.natvis file you're talking about.
    • Hi Paul, thanks for the info.  With your definition, I was able to create a visualizer in VS2013 and VS2015.
      
      Here they are if you are still interested VS2013:
      
        <Type Name='CMap&lt;*,*,*,*&gt;'>
          <DisplayString>{{ size={m_nCount} }}</DisplayString>
          <Expand>
            <LinkedListItems Condition='  0 &lt; m_nHashTableSize'>
              <HeadPointer>m_pHashTable[  0]</HeadPointer>
              <NextPointer>pNext</NextPointer>
              <ValueNode>this</ValueNode>
            </LinkedListItems>
      
            <LinkedListItems Condition='  1 &lt; m_nHashTableSize'>
              <HeadPointer>m_pHashTable[  1]</HeadPointer>
              <NextPointer>pNext</NextPointer>
              <ValueNode>this</ValueNode>
            </LinkedListItems>
      
            <!-- Copy and paste the LinkedListItems above while modifying
                 the index to be able to display more bins                 -->
      
          </Expand>
        </Type>
      
        <Type Name='CMap&lt;*,*,*,*&gt;::CAssoc'>
          <Expand>
            <Item Name='key'>key</Item>
            <Item Name='value'>value</Item>
          </Expand>
        </Type>
      
      Couldn't put the linked list in the CMap<*,*,*,*>::CAssoc definition unfortunately, so have to specify each bin separately.  This causes the index to constantly reset and requires multiple copies of the LinkedListItems node, but it does work.
    • For VS2015, we can use the CustomListItems node:
      
        <Type Name='CMap&lt;*,*,*,*&gt;'>
          <DisplayString>{{ size={m_nCount} }}</DisplayString>
          <Expand>
            <CustomListItems>
              <Variable Name='pHashtable' InitialValue='m_pHashTable'/>
              <Variable Name='hashtable_index' InitialValue='0'/>
              <Variable Name='pList' InitialValue='*m_pHashTable'/>
              <Variable Name='i' InitialValue='0'/>
              <Loop Condition='hashtable_index &lt; m_nHashTableSize'>
                <Exec>pList = pHashtable[hashtable_index]</Exec>
                <Loop Condition='pList '>
                  <Item Name='{i}: [{pList->key}]'>pList->value</Item>
                  <Exec>pList = pList->pNext</Exec>
                  <Exec>++i</Exec>
                </Loop>
                <Exec>++hashtable_index</Exec>
              </Loop>
            </CustomListItems>
          </Expand>
        </Type>
        
        <Type Name='CMap&lt;*,*,*,*&gt;' IncludeView='keys'>
          <DisplayString>{{ size={m_nCount} }}</DisplayString>
          <Expand>
            <CustomListItems>
              <Variable Name='pHashtable' InitialValue='m_pHashTable'/>
              <Variable Name='hashtable_index' InitialValue='0'/>
              <Variable Name='pList' InitialValue='*m_pHashTable'/>
              <Variable Name='i' InitialValue='0'/>
              <Loop Condition='hashtable_index &lt; m_nHashTableSize'>
                <Exec>pList = pHashtable[hashtable_index]</Exec>
                <Loop Condition='pList '>
                  <Item Name='[{i}].key:'>pList->key</Item>
                  <Item Name='  [{i}].value:'>pList->value</Item>
                  <Exec>pList = pList->pNext</Exec>
                  <Exec>++i</Exec>
                </Loop>
                <Exec>++hashtable_index</Exec>
              </Loop>
            </CustomListItems>
          </Expand>
        </Type>
      
      This has two views.  By specifying:
        var_name, view(keys)
      
      You see a [index].key and [index].value lines.  Where as if you specify without the view(keys), you get index: [key] with the value in the value column.
      
      HTH
      
    • Oh, looks like I missed how to get each pair to show up in each index:
      
        <Type Name='CMap&lt;*,*,*,*&gt;::CAssoc'>
          <Expand>
            <Item Name='key'>key</Item>
            <Item Name='value'>value</Item>
          </Expand>
        </Type>
        
        <Type Name='CMap&lt;*,*,*,*&gt;' IncludeView='pair'>
          <DisplayString>{{ size={m_nCount} }}</DisplayString>
          <Expand>
            <CustomListItems>
              <Variable Name='pHashtable' InitialValue='m_pHashTable'/>
              <Variable Name='hashtable_index' InitialValue='0'/>
              <Variable Name='pList' InitialValue='*m_pHashTable'/>
              <Variable Name='i' InitialValue='0'/>
              <Loop Condition='hashtable_index &lt; m_nHashTableSize'>
                <Exec>pList = pHashtable[hashtable_index]</Exec>
                <Loop Condition='pList '>
                  <Item Name='[{i}]'>pList</Item>
                  <Exec>pList = pList->pNext</Exec>
                  <Exec>++i</Exec>
                </Loop>
                <Exec>++hashtable_index</Exec>
              </Loop>
            </CustomListItems>
          </Expand>
        </Type>
      
      I put it here using IncludeView='pair' requiring that you specify ,view(pair) to see it, but you can remove that and use this as your default if you like.  This is better than my view(keys) one IMO.
  • Question about mask visualizers
    1 Posts | Last post June 25, 2015
    • Hi, Cagri
      
      I have a class that represents a custom-length bitmask for a given enum, where each enum vaue can be represented by a bit corresponding to its value:
      
      template<typename T, T total>
      class Mask 
      {
      ...
      unsigned char m_mask[total/8+1]; 
      }
      
      I would like to visualize it so that expanding would give me the lsit of enum values, whose bits are set.
      
      So far, the best I can think of is something like this:
         <Type Name="Smart::Mask&lt;*&gt;">
              <DisplayString>...</DisplayString>
              <Expand>
                  <IndexListItems>
                      <Size>cN*8</Size>
                      <ValueNode Condition="(m_mask[$i/8] &gt;&gt; $i%8) &amp; 0x1">($T1)$i</ValueNode>
                  </IndexListItems>
              </Expand>
          </Type>
      
      However, for each node where the condition is not met, the value is still displayed:
      -		a0	...	Smart::Mask<enum big::T,100>
      		[0]	<Unable to display value>	
      		[1]	v2 (1)	big::T
      		[2]	<Unable to display value>	
      Is there a way to hide items, where the condition is false? - [0] and [2] in this case?
      
      Also, it seems that non-type template arguments are not handled properly by $Tx macro (I am using VS2013):
                      <Size>$T2</Size>
      gives me: 
      Error: identifier "$T2" is undefined
          Error while evaluating '$T2' in the context of type 'UnitTest.exe!Smart::Mask<enum big::T,100>'.
      
      and <Size>total</Size>
      Error: identifier "total" is undefined
          Error while evaluating 'total' in the context of type 'UnitTest.exe!Smart::Mask<enum big::T,100>'.
      
      
      Is there a better way to do something of the kind?
      
      
      It would be really nice to have some built-in visualizer capabilities for writing mask visualizers
  • Visualizer not working after compilingg
    6 Posts | Last post June 10, 2015
    • Hello,
      
      After compiling my project in VS 2012, the custom visualizer no longer works.  I enabled the debugging of the visualizers and it says it loads and parses the visualizer okay, but I do not at the values or anything of my variables.
      
      Any ideas?
      
      Thanks,
      
      David Block
      
    • Just so I understand correctly, the visualizer is loaded ok but it doesn't visualize the types you expect it to visualize and you are seeing the raw view of the variables. Is that correct? If that's the case, it should be an issue with type name matching. Look at the name of the type in the 'type' column of the watch window. Does it match what you have in your entry? 
    • Yes, that's correct.  But what's strange is that the first time I start Visual Studio 2012 it works okay.  It's only after a compile that it stops working.  I need to close down Visual Studio and start it again in order to get it to work.
      Thanks.
      David
      
    • Hi Davod,
      
      I cannot think of anything obvious that would result in such behavior. If you could submit a bug here https://connect.microsoft.com/VisualStudio and give us the name of the type you are visualizing, your visualizer entry, and if possible, a sample project that reproduces this problem, we should be able to figure out what's going on.
    • Hello again... It's actually not a native type, but a custom natvis file that I'm using.  Is there a way I can contact you that is not in a public forum?
      Thanks,
      David
      
    • Hi Davod, you can send the information via https://connect.microsoft.com/VisualStudio. You can contact me at caslan@microsoft.com as well.
  • How to make a visualizer for HICON, HBITMAP, and other GDI Handles?
    2 Posts | Last post June 10, 2015
    • Not sure if you got my last message.  Clicked on "Answer the Question" link because there was no "Reply" link.
      
      Is the reason that the you are saying that the type is PVOID because of some C# mapping issue?  Because in C/C++ it does have a type at point of use.  E.g. HICON, HBITMAP, HMENU, etc...
      
      If this is indeed a C# issue, then I think it needs to be addressed in how the visualizer works.
    • What I meant was all of them are defined as handles (HICON, HBITMAP --> HANDLE* --> PVOID). They are essentially opaque pointers which will show up as integral types in the watch window. (Depending on how the target app is compiled they will be either PVOID in which case visualizers simply won't work or a struct with an int member which you won't be able to do much with a natvis entry).
      
      I suppose you could write a graphical visualizer (not a natvis one) that knows how to get more information for the handle given its value (again, if it shows up as PVOID nothing will work). You can look at https://code.msdn.microsoft.com/Writing-graphical-debugger-a17e3d75 for information on that. I don't know what extra information you could get from the handle from user-mode to display in your visualizer.
      
  • How to make a visualizer for HICON, HBITMAP, and other GDI Handles?
    3 Posts | Last post June 04, 2015
    • I see that it is possible to write VS visualizer for objects, but is it possible to do it for WIN32 API objects?  Considering how old the visualizer API is (under other versions in the paged linked, I saw reference to VS2005), I'm very surprised that they aren't available as of yet in the general debugger.
      
      I've not written a COM object before (I think that is what the linked page is referring to), so I'm not sure how to proceed in attempting this.
      
      Any help is appreciated.
      
      Thanks,
      
      
      A
      --
      This question was originally posted here:
      
      https://social.msdn.microsoft.com/Forums/vstudio/en-US/76b1e9c4-e1f2-4bce-acda-73f2965ed6eb/is-there-hbitmaphicon-or-other-win-objects-debugger-visualizers-out-there?forum=vsdebug
    • No, it's not possible. These are all defined as handles (PVOID), you cannot write visualizers for void pointers.
    • But, where they are used, they have a type that is not PVOID.  I.e. HICON, HBITMAP, HMENU, etc.  Can it not use that?
      
      
      A
  • Custom condition for link list termination
    1 Posts | Last post October 09, 2014
    • Hi, Cagri
      
      One more question: the <LinkedListItems> term assumes that the list is either terminated with 0 or that it is a ring (last->next = first).
      
      I have a case where the condition for the link list termination is different (I need to test one of the fields of the value item). Is there a way for me to specify custom termination condition? <NextPointer> doesn't seem to support Condition attribute...
      
      Thanks!
  • else-type Condition
    1 Posts | Last post October 09, 2014
    • Hi, Cagri
      
      For DisplayString, I can specify N permutations with various conditions and the last one without any condition, which would be taken if all the rest are not recognized.
      
      But I cannot do it for Expanded items:
                  <ExpandedItem Condition="(flags&amp;0xff) == 27">*(net_type*)this</ExpandedItem>
                  <ExpandedItem Condition="(flags&amp;0xff) == 44">*(db_group_type*)this</ExpandedItem>
                  <ExpandedItem>*this</ExpandedItem>
      
      The last expanded item will be there even if one of the conditions above has been met. Is there a way to specify a condition like 'none of the above' other than explicitly listing (!(cond1) && !(cond2)...)?
      
      If not, it would be nice to have it in future versions (something like Condition="otherwise")...
      
      Thanks
      
  • Visualizers and derived classes
    2 Posts | Last post July 07, 2014
    • I have a visualizer for one of my classes:
      	
      <Type Name="BaseTask"> 
        <Expand> 
          <Item Name="Fields">(ETask*)(mBody.mValue)</Item> 
        </Expand> 
      </Type>
      
      This works great for BaseTask, casting mBody.mValue to ETask and displaying its fields. However, I have a class DerivedTask that is derived from BaseTask. Whenever I look at DerivedTask in the debugger, it only shows the BaseTask fields - I don't see any of the additional fields defined in DerivedClass.
      
      I know that I can type "pTask,!" in the debugger to have my BaseTask displayed as-is, but I don't want to have to do that every time (and I have many more classes like this that I want to create visualizers for). Is there a way to limit the visualizer to only the base class?
    • I've seen one and only one place mention this, https://connect.microsoft.com/VisualStudio/feedback/details/777381
      and the answer there was a) create a visualizer entry for every possible derived class, and b) it's supposedly fixed in VS2013.
1 - 10 of 54 Items