In the past I blogged quite a few times about two immensely useful albeit mostly-unofficial debugger features: watch modification via autoexp.dat, and step-into modification via NoStepInto registry key. A long while ago I raised two suggestions at MS UserVoice, to invest in making these two semi-hacks into documented, supported features. The first suggestion got some traction, and is officially implemented in VS2012. The 2nd suggestion went mostly ignored – but nevertheless, there’s a new and better – though still undocumented – way to skip functions while stepping.
NatVis files
The Natvis (native-visualizers) file format is the shiny new replacement for autoexp.dat. It is well documented, and although still quite rough around the edges – bugs are accepted and treated, which means that for the first time it is actually supported. The new apparatus comes with several design advantages:
- It seems to be better isolated and not to crash the IDE so much,
- New visualizer debugging facilities are built in,
- Separate customized visualizers can be kept in separate files, allowing easier sharing (e.g., library writers can now share distribute .natvis files with their libraries).
- Natvis files can be placed at per-user locations.
It isn’t that much fun rehashing the syntax – being official and all – but I will include here a custom mfc-containers natvis, similar to the autoexp section I shared a while back
<?xml version="1.0" encoding="utf-8"?> <AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010"> <!--from afxwin.h --> <Type Name="CArray<*,*>"> <AlternativeType Name="CObArray"></AlternativeType> <AlternativeType Name="CByteArray"></AlternativeType> <AlternativeType Name="CDWordArray"></AlternativeType> <AlternativeType Name="CPtrArray"></AlternativeType> <AlternativeType Name="CStringArray"></AlternativeType> <AlternativeType Name="CWordArray"></AlternativeType> <AlternativeType Name="CUIntArray"></AlternativeType> <AlternativeType Name="CTypedPtrArray<*,*>"></AlternativeType> <DisplayString>{{size = {m_nSize}}}</DisplayString> <Expand> <Item Name="[size]">m_nSize</Item> <Item Name="[capacity]">m_nMaxSize</Item> <ArrayItems> <Size>m_nSize</Size> <ValuePointer>m_pData</ValuePointer> </ArrayItems> </Expand> </Type> <Type Name="CList<*,*>"> <AlternativeType Name="CObList"></AlternativeType> <AlternativeType Name="CPtrList"></AlternativeType> <AlternativeType Name="CStringList"></AlternativeType> <AlternativeType Name="CTypedPtrList<*,*>"></AlternativeType> <DisplayString>{{Count = {m_nCount}}}</DisplayString> <Expand> <Item Name="Count">m_nCount</Item> <LinkedListItems> <Size>m_nCount</Size> <HeadPointer>m_pNodeHead</HeadPointer> <NextPointer>pNext</NextPointer> <ValueNode>data</ValueNode> </LinkedListItems> </Expand> </Type> <Type Name="CMap<*,*,*,*>::CAssoc"> <AlternativeType Name="CMapPtrToWord::CAssoc"></AlternativeType> <AlternativeType Name="CMapPtrToPtr::CAssoc"></AlternativeType> <AlternativeType Name="CMapStringToOb::CAssoc"></AlternativeType> <AlternativeType Name="CMapStringToPtr::CAssoc"></AlternativeType> <AlternativeType Name="CMapStringToString::CAssoc"></AlternativeType> <AlternativeType Name="CMapWordToOb::CAssoc"></AlternativeType> <AlternativeType Name="CMapWordToPtr::CAssoc"></AlternativeType> <AlternativeType Name="CTypedPtrMap<*,*,*>::CAssoc"></AlternativeType> <DisplayString>{{key={key}, value={value}}}</DisplayString> </Type> <Type Name="CMap<*,*,*,*>"> <AlternativeType Name="CMapPtrToWord"></AlternativeType> <AlternativeType Name="CMapPtrToPtr"></AlternativeType> <AlternativeType Name="CMapStringToOb"></AlternativeType> <AlternativeType Name="CMapStringToPtr"></AlternativeType> <AlternativeType Name="CMapStringToString"></AlternativeType> <AlternativeType Name="CMapWordToOb"></AlternativeType> <AlternativeType Name="CMapWordToPtr"></AlternativeType> <AlternativeType Name="CTypedPtrMap<*,*,*>"></AlternativeType> <DisplayString Condition="(m_nHashTableSize >= 0 && m_nHashTableSize <= 65535">{{size={m_nHashTableSize}}}</DisplayString> <Expand> <Item Name="num bins">m_nHashTableSize</Item> <ArrayItems> <Size>m_nHashTableSize</Size> <ValuePointer>m_pHashTable</ValuePointer> </ArrayItems> </Expand> </Type> <Type Name="CMap<*,*,*,*>"> <AlternativeType Name="CMapPtrToWord"></AlternativeType> <AlternativeType Name="CMapPtrToPtr"></AlternativeType> <AlternativeType Name="CMapStringToOb"></AlternativeType> <AlternativeType Name="CMapStringToPtr"></AlternativeType> <AlternativeType Name="CMapStringToString"></AlternativeType> <AlternativeType Name="CMapWordToOb"></AlternativeType> <AlternativeType Name="CMapWordToPtr"></AlternativeType> <AlternativeType Name="CTypedPtrMap<*,*,*>"></AlternativeType> <DisplayString>{Hash table too large!}</DisplayString> </Type> <Type Name="ATL::CAtlMap<*,*,*,*>"> <AlternativeType Name="ATL::CMapToInterface<*,*,*>"/> <AlternativeType Name="ATL::CMapToAutoPtr<*,*,*>"/> <DisplayString>{{Count = {m_nElements}}}</DisplayString> <Expand> <Item Name="Count">m_nElements</Item> <ArrayItems> <Size>m_nBins</Size> <ValuePointer>m_ppBins</ValuePointer> </ArrayItems> </Expand> </Type> <Type Name="ATL::CAtlMap<*,*,*,*>::CNode"> <DisplayString Condition="this==0">Empty bucket</DisplayString> <DisplayString Condition="this!=0">Hash table bucket</DisplayString> </Type> </AutoVisualizer>
Visualizing Map is a bit tricky, and I didn’t take the time yet to look deep into it – but the file is hopefully useful as it is. To use, just save the text as, say, MfcContainers.natvis, either under %VSINSTALLDIR%\Common7\Packages\Debugger\Visualizers (requires admin access), or under %USERPROFILE%\My Documents\Visual Studio 2012\Visualizers\ .
NatStepFilter Files
– are the new and improved substitute for the NoStepInto registry key. While there are some online hints and traces, the natstepfilter spec is yet to be introduced into MSDN – or even the VC++ team blog. For now you can watch the format specification, along with some good comments, at the %VSINSTALLDIR%\Xml\Schemas\natstepfilter.xsd near you, or even better – inspect a small sample at %VSINSTALLDIR%\Common7\Packages\Debugger\Visualizers\default.natstepfilter.
The default.natstepfilter is implemented by Stephen T. Lavavej, and is very far from complete – both because of regex limitations and because of decisions not to set non-overridable limitations on users:
“Adding something to the default natstepfilter is a very aggressive move, because I don’t believe there’s an easy way for users to undo it (hacking the file requires admin access), and it may be surprising when the debugger just decides to skip stuff.”
I can think of several ways for users to override .natstepfilter directives (never mind stepping-into via assembly, how about setting a plain breakpoint it the function you wish to step into?) – and so I don’t agree with that decision. Still I hope the default rules would improve alongside the documentation. We mostly avoid STL, so I had no need to customize .natstepfilter’s yet – I’ll be sure to share such customizations if I do go there.
Caveat
Both improvements, natvis and natstepfilter files, do not work for debugging native/managed mixed code, which sadly renders them unusable for most of our code. While this behavior is documented – I would hardly say it is ‘by design’. It does seem to irritate many others, so there is hope – as Brad Sullivan writes that MS are-
“… working on making everything just work in a future release of Visual Studio.”
Although I came to this post looking for autoexp.dat, I found your discussion of the NatStepFilter. I believe the better UI you want is included in Visual Assist:
http://www.wholetomato.com/features/feature-debug-assistance.asp
I work for the company that makes Visual Assist and the product isn’t free, but if you debug native C/C++, you do have a way to step directly into methods without stepping into the methods of argument lists.
@Jeff Straathof – thanks! I use VA extensively and have only love for the tool. You say that this debug-assistance feature is a wrapper around a custom natstepfilter file?
No, Visual Assist isn’t providing a UI to a custom natstepfilter file. I think Visual Assist does you better: it provides a UI as you debug. If you step into a method you don’t want to step into again, just mark the method. You don’t need to edit the natstepfilter file.
Visual Assist comes with built-in filters that step over common methods, e.g. the std string class.
You need Visual Assist build 2042 or newer to get the VA Step Filter.
http://wholetomato.com/features/whats-new.asp