<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>ClrMD on Welcome to Christophe Nasarre's Blog</title><link>https://chrisnas.github.io/tags/clrmd/</link><description>Recent content in ClrMD on Welcome to Christophe Nasarre's Blog</description><generator>Hugo</generator><language>en-us</language><lastBuildDate>Wed, 11 Feb 2026 09:16:11 +0000</lastBuildDate><atom:link href="https://chrisnas.github.io/tags/clrmd/index.xml" rel="self" type="application/rss+xml"/><item><title>How to support .NET Framework PDB format and source line with ISymUnmanagedReader</title><link>https://chrisnas.github.io/posts/2026-02-11_how-to-support-net/</link><pubDate>Wed, 11 Feb 2026 09:16:11 +0000</pubDate><guid>https://chrisnas.github.io/posts/2026-02-11_how-to-support-net/</guid><description>After DIA and DbgHelp, time to dig into ISymUnmanagedReader to get its line in source code.</description><content:encoded><![CDATA[<hr>
<p>In my previous posts, I explained how to use <a href="/posts/2025-12-08_how-to-dump-function/">DIA</a> and <a href="/posts/2026-01-16_but-where-is-my/">DbgHelp</a> to map a method to its line in source code. I forgot to mention that it was correct for .NET Core but not for the “old” .NET Framework Windows PDB format. Instead of encoding the method token in the name, the symbol file contains the name of the methods. So, how to do the mapping for .NET Framework assemblies? You will find the answer (plus some tricks) in this article.</p>
<p>When I started to work on the support of the old Windows PDB format, I looked at what existed to parse the <a href="https://github.com/microsoft/microsoft-pdb/tree/master">raw format</a> and… I decided to try DbgHelp instead. With this <a href="/posts/2026-01-16_but-where-is-my/">first implementation</a>, I realized that some token where missing and source code information was not retrieved for most of the methods.</p>
<p><img loading="lazy" src="/posts/2026-02-11_how-to-support-net/1_ppZFw6o-Ygx7BzpX3jyWIw.png"></p>
<p>So, I looked for another API to use and I found <a href="https://learn.microsoft.com/en-us/dotnet/framework/unmanaged-api/diagnostics/isymunmanagedreader-interface?WT.mc_id=DT-MVP-5003325">ISymUnmanagedReader</a>. The usage philosophy is totally different from DIA or DbgHelp.</p>
<h2 id="a-little-bit-ofmagic">A little bit of magic</h2>
<p>This interface is implemented in diasymreader.dll that comes with every .NET Framework installation. But you need to do COM magic to get it. After having called <a href="https://learn.microsoft.com/en-us/windows/win32/api/objbase/nf-objbase-coinitialize?WT.mc_id=DT-MVP-5003325"><strong>CoInitialize</strong></a> to setup COM, you ask for an instance of <a href="https://learn.microsoft.com/en-us/dotnet/framework/unmanaged-api/diagnostics/isymunmanagedbinder-interface?WT.mc_id=DT-MVP-5003325"><strong>ISymUnmanagedBinder</strong></a> from <strong>CLSID_CorSymBinder_SxS</strong>:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">CComPtr</span><span class="o">&lt;</span><span class="n">ISymUnmanagedBinder</span><span class="o">&gt;</span> <span class="n">pBinder</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">hr</span> <span class="o">=</span> <span class="n">CoCreateInstance</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="n">CLSID_CorSymBinder_SxS</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nb">NULL</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">CLSCTX_INPROC_SERVER</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">IID_ISymUnmanagedBinder</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">(</span><span class="kt">void</span><span class="o">**</span><span class="p">)</span><span class="o">&amp;</span><span class="n">pBinder</span>
</span></span><span class="line"><span class="cl"><span class="p">);</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>From the binder, you can get the <a href="https://learn.microsoft.com/en-us/dotnet/framework/unmanaged-api/diagnostics/isymunmanagedreader-interface?WT.mc_id=DT-MVP-5003325"><strong>ISymUnmanagedReader</strong> interface</a> corresponding to the assembly you are interested in with <a href="https://learn.microsoft.com/en-us/dotnet/framework/unmanaged-api/diagnostics/isymunmanagedbinder-getreaderforfile-method?WT.mc_id=DT-MVP-5003325"><strong>GetReaderForFile</strong></a>. However, there are two tiny details to consider.</p>
<p>First, one parameter expects the path to the assembly, not to the .pdb file. That symbol file has to be stored in the same folder but note that the documentation states that you could have more flexible search with <a href="https://learn.microsoft.com/en-us/dotnet/framework/unmanaged-api/diagnostics/isymunmanagedbinder2-getreaderforfile2-method?WT.mc_id=DT-MVP-5003325"><strong>ISymUnmanagedBinder2::GetReaderForFile2</strong></a> but I did not test it.</p>
<p>The second detail is the first parameter: an instance of <strong>IMetaDataImport</strong> for the same assembly. The steps to get it are… complicated.</p>
<h2 id="hosting-theclr">Hosting the CLR</h2>
<p>The idea is to host the .NET Framework and get the corresponding <a href="https://learn.microsoft.com/en-us/dotnet/framework/unmanaged-api/hosting/iclrmetahost-interface?WT.mc_id=DT-MVP-5003325">ICLRMetaHost</a> interface:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">CComPtr</span><span class="o">&lt;</span><span class="n">ICLRMetaHost</span><span class="o">&gt;</span> <span class="n">pMetaHost</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">HRESULT</span> <span class="n">hr</span> <span class="o">=</span> <span class="n">CLRCreateInstance</span><span class="p">(</span><span class="n">CLSID_CLRMetaHost</span><span class="p">,</span> <span class="n">IID_ICLRMetaHost</span><span class="p">,</span> <span class="p">(</span><span class="kt">void</span><span class="o">**</span><span class="p">)</span><span class="o">&amp;</span><span class="n">pMetaHost</span><span class="p">);</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>Calling the <a href="CComPtr%3cICLRMetaHost%3e%20pMetaHost;"><strong>CLRCreateInstance</strong> API</a> allows you to get an instance of <strong>ICLRMetaHost</strong> from which you could <a href="https://learn.microsoft.com/en-us/dotnet/framework/unmanaged-api/hosting/iclrmetahost-enumerateinstalledruntimes-method?WT.mc_id=DT-MVP-5003325">enumerate installed version</a> of .NET Framework. In my case, I know which version I want:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="c1">// Get the installed .NET Framework runtime (v4.0+)
</span></span></span><span class="line"><span class="cl"><span class="n">CComPtr</span><span class="o">&lt;</span><span class="n">ICLRRuntimeInfo</span><span class="o">&gt;</span> <span class="n">pRuntimeInfo</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">hr</span> <span class="o">=</span> <span class="n">pMetaHost</span><span class="o">-&gt;</span><span class="n">GetRuntime</span><span class="p">(</span><span class="sa">L</span><span class="s">&#34;v4.0.30319&#34;</span><span class="p">,</span> <span class="n">IID_ICLRRuntimeInfo</span><span class="p">,</span> <span class="p">(</span><span class="kt">void</span><span class="o">**</span><span class="p">)</span><span class="o">&amp;</span><span class="n">pRuntimeInfo</span><span class="p">);</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>The <a href="https://learn.microsoft.com/en-us/dotnet/framework/unmanaged-api/hosting/iclrruntimeinfo-interface?WT.mc_id=DT-MVP-5003325">ICLRRuntimeInfo interface</a> allows you to get access to runtime services via <strong>GetInterface</strong>:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">CComPtr</span><span class="o">&lt;</span><span class="n">IMetaDataDispenser</span><span class="o">&gt;</span> <span class="n">pDispenser</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">hr</span> <span class="o">=</span> <span class="n">pRuntimeInfo</span><span class="o">-&gt;</span><span class="n">GetInterface</span><span class="p">(</span><span class="n">CLSID_CorMetaDataDispenser</span><span class="p">,</span> <span class="n">IID_IMetaDataDispenser</span><span class="p">,</span> <span class="p">(</span><span class="kt">void</span><span class="o">**</span><span class="p">)</span><span class="o">&amp;</span><span class="n">pDispenser</span><span class="p">);</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>The service I’m interested in is the <a href="https://learn.microsoft.com/en-us/windows/win32/api/rometadataapi/nn-rometadataapi-imetadatadispenser?WT.mc_id=DT-MVP-5003325"><strong>IMetadataDispenser</strong> interface</a> that allows you to “open a scope” on the assembly you are interested in:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">hr</span> <span class="o">=</span> <span class="n">pDispenser</span><span class="o">-&gt;</span><span class="n">OpenScope</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="n">wModulePath</span><span class="p">.</span><span class="n">c_str</span><span class="p">(),</span>
</span></span><span class="line"><span class="cl">    <span class="n">ofRead</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">IID_IMetaDataImport</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="p">(</span><span class="n">IUnknown</span><span class="o">**</span><span class="p">)</span><span class="o">&amp;</span><span class="n">_pMetaDataImport</span>
</span></span><span class="line"><span class="cl"><span class="p">);</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>Note that the first parameter is the path to the assembly not to the .pdb file. The scope is abstracted by an <strong>IMetadataImport</strong> interface <a href="/posts/2021-09-06_dealing-with-modules-assemblie/">I have already described</a> and that is needed to call <strong>GetReaderForFile</strong>: and get the <strong>ISymUnmanagedReader</strong>:</p>
<p>hr = pBinder-&gt;GetReaderForFile(_pMetaDataImport, wModulePath.c_str(), nullptr, &amp;_pReader);</p>
<h2 id="the-road-to-get-symbol-details-for-amethod">The road to get symbol details for a method</h2>
<p>The <strong>ISymUnmanagedReader</strong> interface implements <a href="https://learn.microsoft.com/en-us/dotnet/framework/unmanaged-api/diagnostics/isymunmanagedreader-getmethod-method?WT.mc_id=DT-MVP-5003325"><strong>GetMethod</strong></a> to get details about a given method token via an <strong>ISymUnmanagedMethod</strong> interface. So, the next question is how to get these tokens. If you remember <a href="/posts/2026-01-16_but-where-is-my/">the previous article</a>, these tokens are from the 06 MethodDef table in the assembly metadata; starting from <strong>06000001</strong> to the last one.</p>
<p>This means that you could write a simple loop starting from 1 up to a hardcoded maximum value, call <strong>TokenFromRid(index, mdtMethodDef)</strong> to get the corresponding token. However, since you are a professional developer, you would search for the exact number of tokens from <a href="https://learn.microsoft.com/en-us/dotnet/core/unmanaged-api/metadata/interfaces/imetadatatables-interface?WT.mc_id=DT-MVP-5003325"><strong>IMetadataTables</strong></a> retrieved from <strong>IMetadataImport</strong>:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="n">ULONG</span> <span class="n">cRows</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// Get IMetaDataTables interface to query the MethodDef table
</span></span></span><span class="line"><span class="cl"><span class="n">CComPtr</span><span class="o">&lt;</span><span class="n">IMetaDataTables</span><span class="o">&gt;</span> <span class="n">pTables</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">hr</span> <span class="o">=</span> <span class="n">_pMetaDataImport</span><span class="o">-&gt;</span><span class="n">QueryInterface</span><span class="p">(</span><span class="n">IID_IMetaDataTables</span><span class="p">,</span> <span class="p">(</span><span class="kt">void</span><span class="o">**</span><span class="p">)</span><span class="o">&amp;</span><span class="n">pTables</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="p">(</span><span class="n">FAILED</span><span class="p">(</span><span class="n">hr</span><span class="p">)</span> <span class="o">||</span> <span class="n">pTables</span> <span class="o">==</span> <span class="k">nullptr</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">cRows</span> <span class="o">=</span> <span class="n">LAST_METHODDEF_TOKEN</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="k">else</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// Get the number of rows in the MethodDef table (table index 0x06 = Method)
</span></span></span><span class="line"><span class="cl">    <span class="n">hr</span> <span class="o">=</span> <span class="n">pTables</span><span class="o">-&gt;</span><span class="n">GetTableInfo</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="mh">0x06</span><span class="p">,</span>           <span class="c1">// MethodDef table
</span></span></span><span class="line"><span class="cl">        <span class="nb">NULL</span><span class="p">,</span>           <span class="c1">// cbRow (not needed)
</span></span></span><span class="line"><span class="cl">        <span class="o">&amp;</span><span class="n">cRows</span><span class="p">,</span>         <span class="c1">// pcRows (number of methods)
</span></span></span><span class="line"><span class="cl">        <span class="nb">NULL</span><span class="p">,</span>           <span class="c1">// pcCols (not needed)
</span></span></span><span class="line"><span class="cl">        <span class="nb">NULL</span><span class="p">,</span>           <span class="c1">// piKey (not needed)
</span></span></span><span class="line"><span class="cl">        <span class="nb">NULL</span>            <span class="c1">// ppName (not needed)
</span></span></span><span class="line"><span class="cl">    <span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="n">FAILED</span><span class="p">(</span><span class="n">hr</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">cRows</span> <span class="o">=</span> <span class="n">LAST_METHODDEF_TOKEN</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>Now that you have the number of rows (i.e. number of methods defined in the metadata), it is easy and safe to get method information from symbols:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="k">for</span> <span class="p">(</span><span class="kt">uint32_t</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">i</span> <span class="o">&lt;=</span> <span class="n">cRows</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">mdMethodDef</span> <span class="n">token</span> <span class="o">=</span> <span class="n">TokenFromRid</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">mdtMethodDef</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">CComPtr</span><span class="o">&lt;</span><span class="n">ISymUnmanagedMethod</span><span class="o">&gt;</span> <span class="n">pMethod</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">hr</span> <span class="o">=</span> <span class="n">_pReader</span><span class="o">-&gt;</span><span class="n">GetMethod</span><span class="p">(</span><span class="n">token</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">pMethod</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="n">SUCCEEDED</span><span class="p">(</span><span class="n">hr</span><span class="p">)</span> <span class="o">&amp;&amp;</span> <span class="n">pMethod</span> <span class="o">!=</span> <span class="k">nullptr</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">MethodInfo</span> <span class="n">info</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="n">GetMethodInfoFromSymbol</span><span class="p">(</span><span class="n">pMethod</span><span class="p">,</span> <span class="n">info</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="n">_methods</span><span class="p">.</span><span class="n">push_back</span><span class="p">(</span><span class="n">info</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>Note that <strong>GetMethod</strong> might fail (returning <strong>E_FAIL</strong>) for P/Invoked functions, abstract methods, or methods decorated with <strong>DebuggerHidden</strong> attribute.</p>
<h2 id="give-me-line-and-sourcecode">Give me line and source code!</h2>
<p>For the other methods with symbol information, you can get its token via the <strong>GetToken</strong> method. The <strong>ISymUnmanagedMethod</strong> interface allows low level access to line/column mapping that is beyond the scope of this article. At a high level, positions in source file are named <em>sequence points</em>. Call <a href="https://learn.microsoft.com/en-us/dotnet/framework/unmanaged-api/diagnostics/isymunmanagedmethod-getsequencepointcount-method?WT.mc_id=DT-MVP-5003325"><strong>GetSequencePointCount</strong></a> to get… the number of sequence points for a given method.</p>
<p>The next step is to call <a href="https://learn.microsoft.com/en-us/dotnet/framework/unmanaged-api/diagnostics/isymunmanagedmethod-getsequencepoints-method?WT.mc_id=DT-MVP-5003325">GetSequencePoints</a> with the number of points you want and the corresponding arrays of offsets, lines, columns, end lines, end columns and <strong>ISymUnmanagedDocument</strong>. In my case, I’m only interested in where the method starts so the first sequence point is good enough:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="c1">// Get sequence points (source line information)
</span></span></span><span class="line"><span class="cl"><span class="n">ULONG32</span> <span class="n">cPoints</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="n">hr</span> <span class="o">=</span> <span class="n">pMethod</span><span class="o">-&gt;</span><span class="n">GetSequencePointCount</span><span class="p">(</span><span class="o">&amp;</span><span class="n">cPoints</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="p">(</span><span class="n">SUCCEEDED</span><span class="p">(</span><span class="n">hr</span><span class="p">)</span> <span class="o">&amp;&amp;</span> <span class="p">(</span><span class="n">cPoints</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">cPoints</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="c1">// We only need the first sequence point for start line
</span></span></span><span class="line"><span class="cl">    <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">ULONG32</span><span class="o">&gt;</span> <span class="n">offsets</span><span class="p">(</span><span class="n">cPoints</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">ULONG32</span><span class="o">&gt;</span> <span class="n">lines</span><span class="p">(</span><span class="n">cPoints</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">ULONG32</span><span class="o">&gt;</span> <span class="n">columns</span><span class="p">(</span><span class="n">cPoints</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">ULONG32</span><span class="o">&gt;</span> <span class="n">endLines</span><span class="p">(</span><span class="n">cPoints</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">ULONG32</span><span class="o">&gt;</span> <span class="n">endColumns</span><span class="p">(</span><span class="n">cPoints</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">ISymUnmanagedDocument</span><span class="o">*&gt;</span> <span class="n">documents</span><span class="p">(</span><span class="n">cPoints</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">ULONG32</span> <span class="n">actualCount</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">hr</span> <span class="o">=</span> <span class="n">pMethod</span><span class="o">-&gt;</span><span class="n">GetSequencePoints</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">        <span class="n">cPoints</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="o">&amp;</span><span class="n">actualCount</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">        <span class="o">&amp;</span><span class="n">offsets</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">        <span class="o">&amp;</span><span class="n">documents</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">        <span class="o">&amp;</span><span class="n">lines</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">        <span class="o">&amp;</span><span class="n">columns</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">        <span class="o">&amp;</span><span class="n">endLines</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span>
</span></span><span class="line"><span class="cl">        <span class="o">&amp;</span><span class="n">endColumns</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="n">SUCCEEDED</span><span class="p">(</span><span class="n">hr</span><span class="p">)</span> <span class="o">&amp;&amp;</span> <span class="p">(</span><span class="n">actualCount</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>The source file is described by <a href="https://learn.microsoft.com/en-us/dotnet/framework/unmanaged-api/diagnostics/isymunmanageddocument-interface?WT.mc_id=DT-MVP-5003325">ISymUnmanagedDocument</a> that provides its name when <a href="https://learn.microsoft.com/en-us/dotnet/framework/unmanaged-api/diagnostics/isymunmanageddocument-geturl-method?WT.mc_id=DT-MVP-5003325"><strong>GetURL</strong></a> is called:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-cpp" data-lang="cpp"><span class="line"><span class="cl"><span class="c1">// Get the first sequence point&#39;s document and line
</span></span></span><span class="line"><span class="cl">        <span class="n">ISymUnmanagedDocument</span><span class="o">*</span> <span class="n">pDoc</span> <span class="o">=</span> <span class="n">documents</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="n">pDoc</span> <span class="o">!=</span> <span class="k">nullptr</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="c1">// Get document URL (file path)
</span></span></span><span class="line"><span class="cl">            <span class="n">ULONG32</span> <span class="n">urlLen</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">            <span class="n">hr</span> <span class="o">=</span> <span class="n">pDoc</span><span class="o">-&gt;</span><span class="n">GetURL</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">urlLen</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">            <span class="k">if</span> <span class="p">(</span><span class="n">SUCCEEDED</span><span class="p">(</span><span class="n">hr</span><span class="p">)</span> <span class="o">&amp;&amp;</span> <span class="p">(</span><span class="n">urlLen</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">            <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="n">std</span><span class="o">::</span><span class="n">vector</span><span class="o">&lt;</span><span class="n">WCHAR</span><span class="o">&gt;</span> <span class="n">url</span><span class="p">(</span><span class="n">urlLen</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">                <span class="n">hr</span> <span class="o">=</span> <span class="n">pDoc</span><span class="o">-&gt;</span><span class="n">GetURL</span><span class="p">(</span><span class="n">urlLen</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">urlLen</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">url</span><span class="p">[</span><span class="mi">0</span><span class="p">]);</span>
</span></span><span class="line"><span class="cl">                <span class="k">if</span> <span class="p">(</span><span class="n">SUCCEEDED</span><span class="p">(</span><span class="n">hr</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">                <span class="p">{</span>
</span></span><span class="line"><span class="cl">                    <span class="c1">// Convert wide string to narrow string
</span></span></span><span class="line"><span class="cl">                    <span class="kt">int</span> <span class="n">len</span> <span class="o">=</span> <span class="n">WideCharToMultiByte</span><span class="p">(</span><span class="n">CP_UTF8</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">url</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">urlLen</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">                    <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">narrowUrl</span><span class="p">(</span><span class="n">len</span><span class="p">,</span> <span class="sc">&#39;\0&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">                    <span class="n">WideCharToMultiByte</span><span class="p">(</span><span class="n">CP_UTF8</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">url</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">urlLen</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">narrowUrl</span><span class="p">[</span><span class="mi">0</span><span class="p">],</span> <span class="n">len</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">                    <span class="n">info</span><span class="p">.</span><span class="n">sourceFile</span> <span class="o">=</span> <span class="n">narrowUrl</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">                <span class="p">}</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">            <span class="c1">// NOTE: 0xFEEFEE is a special value indicating hidden lines
</span></span></span><span class="line"><span class="cl">            <span class="n">info</span><span class="p">.</span><span class="n">lineNumber</span> <span class="o">=</span> <span class="n">lines</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">            <span class="n">pDoc</span><span class="o">-&gt;</span><span class="n">Release</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>The final interesting trick is that the line number might have the special <strong>0xFEEFEE</strong> value. It means that the line is hidden. I have seen it for methods generated by the C# compiler such as <strong>MoveNext</strong> for async state machines or anonymous methods:</p>
<p><img loading="lazy" src="/posts/2026-02-11_how-to-support-net/1_ZBXLm1oWWKp4pacMcX3g5Q.png"></p>
<p>The source code is available from <a href="https://github.com/chrisnas/DumpManagedMethodInfoFromSymbols">my Github repository</a>.</p>
<p>Happy coding!</p>
<h2 id="references">References</h2>
<ul>
<li><a href="https://github.com/microsoft/microsoft-pdb/tree/master">Archived Microsoft-pdb repository</a></li>
<li><a href="/posts/2025-12-08_how-to-dump-function/">DIA implementation article</a></li>
<li><a href="/posts/2026-01-16_but-where-is-my/">DbgHelp implementation article</a></li>
</ul>
]]></content:encoded></item><item><title>How to write your own commands in dotnet-dump (2/2)</title><link>https://chrisnas.github.io/posts/2020-11-09_how-to-write-commands/</link><pubDate>Mon, 09 Nov 2020 16:27:38 +0000</pubDate><guid>https://chrisnas.github.io/posts/2020-11-09_how-to-write-commands/</guid><description>This post describes the different steps, tips and tricks to write your own commands for dotnet-dump</description><content:encoded><![CDATA[<hr>
<p>In the <a href="/posts/2020-09-29_how-to-extend-dotnet/">previous post</a>, I presented the new commands that were added to dotnet-dump and how to use them. It is now time to show how to implement such a command.</p>
<p>But before jumping into the code, you should first ensure that you have a valid use case that the Diagnostics team is not currently working on. I recommend to create an issue in the Diagnostics repository to explain what is missing for which scenario and propose to implement the corresponding command.</p>
<h2 id="what-is-a-dotnet-dump-command">What is a dotnet-dump command?</h2>
<p>Here is the directory structure related to the dotnet-dump tool in the Diagnostics repository:</p>
<p><img loading="lazy" src="/posts/2020-11-09_how-to-write-commands/1_tlD3As6iHhwIWjL_FeyMSw.png"></p>
<p>The built binaries are generated under artifacts\bin\dotnet-dump&lt;Release or Debug&gt;\netcoreapp2.1 folder if you need to test them outside of Visual Studio.</p>
<p>The <strong>eng</strong> folder contains the <strong>versions.props</strong> file that lists the versions for nuget dependencies. In my case, I had to reference the ParallelStacks.Runtime nuget so I added the following line:<code>2.0.1</code></p>
<p>And in the <strong>dotnet-dump.csproj</strong>, this nuget is referenced with the same variable:
`</p>
<hr>
<p><strong>Missed the first part of the story? Read it here:</strong></p>
<p><a href="/posts/2020-09-29_how-to-extend-dotnet/"><strong>How to extend dotnet-dump (1/2) — What are the new commands?</strong>
*This first post describes the new commands, when to use them, and the git setup I used to implement them.*medium.com</a></p>
<p><strong>Want to work with Christophe or other teams? Check out our open positions:</strong></p>
<p><a href="http://careers.criteo.com"><strong>Careers at Criteo | Criteo jobs</strong>
*Find opportunities everywhere. ​Choose your next challenge. Find the job opportunities at Criteo in Product, research &amp;…*careers.criteo.com</a><a href="http://careers.criteo.com"></a></p>
]]></content:encoded></item><item><title>How to extend dotnet-dump (1/2) — What are the new commands?</title><link>https://chrisnas.github.io/posts/2020-09-29_how-to-extend-dotnet/</link><pubDate>Tue, 29 Sep 2020 14:26:16 +0000</pubDate><guid>https://chrisnas.github.io/posts/2020-09-29_how-to-extend-dotnet/</guid><description>This first post describes the new commands, when to use them, and the git setup I used to implement them.</description><content:encoded><![CDATA[<hr>
<h2 id="introduction">Introduction</h2>
<p>To ease our troubleshooting sessions at Criteo, new high level commands for WinDBG have been written and grouped in the <a href="https://github.com/chrisnas/DebuggingExtensions/blob/master/Documentation/gsose.md">gsose extension</a>. As we moved to Linux, <a href="https://twitter.com/KooKiz">Kevin</a> implemented the plumbing to be able to load gsose into LLDB. In both cases, our extension commands are based on ClrMD to dig into a memory dump.</p>
<p>As Microsoft pushed for dotnet-dump as the new cross-platform way to deal with memory dump, it was obvious that we would have to be able to use our extension commands in dotnet-dump. Unfortunately dotnet-dump does not support any extension mechanism. In May this year, Kevin updated <a href="https://github.com/kevingosse/diagnostics/commit/4abf635b6313bf733b2450a2ffee8fa06befd7b6">a minimum of code</a> to load a list of extension assemblies at the startup of dotnet-dump. I followed another direction by <a href="https://github.com/chrisnas/diagnostics/commit/235a3347fcf2369e408664137cd29a721879b42d">adding a “load” command</a> to dynamically add extensions commands.</p>
<p>However, the Diagnostics team was focusing on supporting .NET Core 5 release and adding extensibility was not planned before next year. Due to our own time constraints at Criteo, gsose extension commands were really needed so we agreed with the Diagnostics team to implement these commands directly into dotnet-dump as pull requests.</p>
<p>This first post describes the new commands, when to use them, and the git setup I used to implement them.</p>
<h2 id="commands-details-and-challenges">Commands details and challenges</h2>
<p>Here is the list of extension commands as shown by the <strong>help</strong> command:</p>
<p><img loading="lazy" src="/posts/2020-09-29_how-to-extend-dotnet/1_P1htQUvAxcJInIFQI_P8wg.png"></p>
<p>As of today with the last 3.1.141901 official version, only <strong>timerinfo</strong> is available but feel free to <a href="https://github.com/dotnet/diagnostics/">clone the repository</a> and rebuild it to get all commands.</p>
<h2 id="pstacks-almost-parallel-stacks-a-la-visualstudio">pstacks: almost Parallel Stacks a la Visual Studio</h2>
<p>When you start an investigation, you are usually interested in getting a high level view of what the running threads are doing and this is what <strong>pstacks</strong> provides. When hundreds of threads are running, commands such as <strong>clrthreads</strong> are useless. Instead, <strong>pstacks</strong> merges the common parts of each call stack and present them in a tree:</p>
<p><img loading="lazy" src="/posts/2020-09-29_how-to-extend-dotnet/1_2C3hvE-AQY0RfOQBMeEoYA.png"></p>
<p>Don’t be scared by the layout; here is a description of each section:</p>
<p><img loading="lazy" src="/posts/2020-09-29_how-to-extend-dotnet/1_L-MKjPDVEpW5g8nJ6aGvMg.png"></p>
<p>If you look at the threads 9c6c and 4020 (after the last ~~~~), it means that 2 threads (only the first 4 threads id are shown except if you pass — all as a parameter) share the same callstack:</p>
<pre tabindex="0"><code>~~~~ 9c6c,4020
2 System.Threading.Monitor.Wait(Object, Int32, Boolean)
4 System.Threading.Tasks.Task+c.cctor&gt;b__278_1(Object)
  ...
4 System.Threading.Tasks.Task.ExecuteEntryUnsafe()
4 System.Threading.Tasks.Task.ExecuteWorkItem()
7 System.Threading.ThreadPoolWorkQueue.Dispatch()
7 System.Threading._ThreadPoolWaitCallback.PerformWaitCallback()
</code></pre><p>Compared to the “list” representation, the “tree” representation is useful when you have a lot of threads to deal with and see the different branches in the groups of stack frames.</p>
<h2 id="ti-see-all-yourtimers">ti: see all your timers</h2>
<p>If you don’t find anything interesting in the running threads (i.e. not hundreds of threads with the same code stack blocked on a <strong>Wait</strong> call for example), you should look at what will run as timer callbacks with the <strong>ti</strong> command.</p>
<p>Here is example of what you will get:</p>
<pre tabindex="0"><code>&gt; ti
(S) 0x00007F7D84529CD0 @    1000 ms every     1000 ms |  0000000000000000 () -&gt; Kafka.Batching.AccumulatorByTopic&lt;Kafka.Routing.FetchMessage&gt;.Tick
    ...
(L) 0x00007F7D844FA7A0 @    1000 ms every     1000 ms |  0000000000000000 () -&gt; Kafka.Batching.AccumulatorByTopic&lt;Kafka.Routing.OffsetMessage&gt;.Tick
    ...
(L) 0x00007F7D842042F8 @     999 ms every     1000 ms |  0000000000000000 () -&gt; Criteo.DevKit.TimeStamp+&lt;&gt;c.cctor&gt;b__35_0
    ...
(L) 0x00007F7D846314C8 @     999 ms every     1000 ms |  00007F7D8462ED70 (Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure.Heartbeat) -&gt;
    ...
 
   190 timers
-----------------------------------------------
   1 | (S) @     999 ms every     1000 ms | 0000000000000000 () -&gt; Kafka.Batching.AccumulatorByTopic&lt;Kafka.Routing.FetchMessage&gt;.Tick
   1 | (L) @     996 ms every     1000 ms | 0000000000000000 () -&gt; Kafka.Batching.AccumulatorByTopic&lt;Kafka.Routing.OffsetMessage&gt;.Tick
   1 | (L) @     993 ms every     1000 ms | 0000000000000000 () -&gt; Kafka.Batching.AccumulatorByTopic&lt;Kafka.Routing.FetchMessage&gt;.Tick
   1 | (L) @     999 ms every     1000 ms | 0000000000000000 () -&gt; Criteo.DevKit.TimeStamp+&lt;&gt;c.cctor&gt;b__35_0
   ...
   9 | (L) @    1000 ms every     1000 ms | 0000000000000000 () -&gt; Kafka.Batching.AccumulatorByTopic&lt;Kafka.Routing.FetchMessage&gt;.Tick
  33 | (L) @     999 ms every     1000 ms | 0000000000000000 () -&gt; Kafka.Batching.AccumulatorByTopic&lt;Kafka.Routing.FetchMessage&gt;.Tick
  34 | (L) @    2000 ms every     2000 ms | 0000000000000000 () -&gt; Kafka.Batching.AccumulatorByTopicByPartition&lt;Kafka.Cluster.ProduceMessage&gt;.Tick
  38 | (L) @     999 ms every     1000 ms | 0000000000000000 () -&gt; Kafka.Batching.AccumulatorByTopic&lt;Kafka.Routing.OffsetMessage&gt;.Tick
</code></pre><p>The first part of the output lists each instance of <strong>Timer</strong> with start/repeat information followed by the callback parameter and callback if available. The second list groups timer so you could identify cases where the same timers have been created many times.</p>
<h2 id="tpq-what-is-in-the-threadpool-queues">tpq: what is in the ThreadPool queues</h2>
<p>If no culprit is identified in timers, it is time to look at what is in the ThreadPool with the <strong>tpq</strong> command.</p>
<pre tabindex="0"><code>&gt; tpq
 
global work item queue________________________________
0x000002AC3C1DDBB0 Work | (ASP.global_asax)System.Web.HttpApplication.ResumeStepsWaitCallback
                       ...
0x000002AABEC19148 Task | System.Threading.Tasks.Dataflow.Internal.TargetCore&lt;System.Action&gt;.&lt;ProcessAsyncIfNecessary_Slow&gt;b__3
 
local per thread work items_____________________________________
0x000002AE79D80A00 System.Threading.Tasks.ContinuationTaskFromTask
                       ...
0x000002AB7CBB84A0 Task | System.Net.Http.HttpClientHandler.StartRequest
 
   7 Task System.Threading.Tasks.Dataflow.Internal.TargetCore&lt;System.Action&gt;.&lt;ProcessAsyncIfNecessary_Slow&gt;b__3
                       ...
  84 Task System.Net.Http.HttpClientHandler.StartRequest
----
6039
 
1810 Work  (ASP.global_asax) System.Web.HttpApplication.ResumeStepsWaitCallback
----
1810
</code></pre><p>Both work items from the global queue and the local queues are displayed with each identified callback. The final summary spits work items and tasks.</p>
<h2 id="miscellaneous-commands">Miscellaneous commands</h2>
<p>Two other helper commands are also available.</p>
<h3 id="tks-taskstate">tks: Task State</h3>
<p>Pass a <strong>Task</strong> object reference to <strong>tks</strong> to get its human readable state.</p>
<pre tabindex="0"><code>&gt; help tks
-------------------------------------------------------------------------------
TaskState [hexa address] [-v &lt;decimal state value&gt;]
 
TaskState translates a Task m_stateFlags field value into human readable format.
It supports hexadecimal address corresponding to a task instance or -v &lt;decimal state value&gt;.
 
&gt; tks 000001db16cf98f0
Running
 
&gt; tks -v 73728
WaitingToRun
</code></pre><h3 id="dcq-dump-concurrentqueue">dcq : Dump ConcurrentQueue</h3>
<p>Dump elements stored in a <strong>ConcurrentQueue</strong>. Due to implementation details, more manual steps are required in case of value types.</p>
<pre tabindex="0"><code>&gt; help dcq
-------------------------------------------------------------------------------
DumpConcurrentQueue
 
Lists all items in the given concurrent queue.
 
For simple types such as numbers, boolean and string, values are shown.
&gt; dcq 00000202a79320e8
System.Collections.Concurrent.ConcurrentQueue&lt;System.Int32&gt;
   1 - 0
   2 - 1
   3 - 2
 
In case of reference types, the command to dump each object is shown.
&gt; dcq 00000202a79337f8
System.Collections.Concurrent.ConcurrentQueue&lt;ForDump.ReferenceType&gt;
   1 - dumpobj 0x202a7934e38
   2 - dumpobj 0x202a7934fd0
   3 - dumpobj 0x202a7935078
 
For value types, the command to dump each array segment is shown.
The next step is to manually dump each element with dumpvc &lt;the Element Methodtable&gt; &lt;[item] address&gt;.
&gt; dcq 00000202a7933370
System.Collections.Concurrent.ConcurrentQueue&lt;ForDump.ValueType&gt;
   1 - dumparray 202a79334e0
   2 - dumparray 202a7938a88
</code></pre><p>Note that for reference type items, the <strong>dumpobj</strong> command is provided to get the value of the item fields: you just copy and paste them to get instance fields.</p>
<h2 id="git-hell">GIT hell</h2>
<p>Before digging into the implementation details, I want to spend some time on how to properly create a pull request. Since the Diagnostics repository is hosted on Github, you have to <a href="https://docs.github.com/en/github/getting-started-with-github/fork-a-repo">create a fork</a> and push your changes on a dedicated branch to then submit a pull request.</p>
<p>Due to my previous Team Foundation Server experience, it seems that I have problems with Git commands: too many different ways to do simple things maybe. So I was faithfully relying on the documentation to <a href="https://help.github.com/en/articles/configuring-a-remote-for-a-fork">configure</a>/<a href="https://help.github.com/en/articles/syncing-a-fork">sync</a> a fork and I ended up merging the Microsoft Master branch to our Criteo fork Master before creating my own branch dedicated to my pull request:</p>
<p><img loading="lazy" src="/posts/2020-09-29_how-to-extend-dotnet/1_oxjINauTwluB-sNgP_zUUg.png"></p>
<p>After a while, in the next pull requests, I started to have unrelated commits in the pull requests:</p>
<p><img loading="lazy" src="/posts/2020-09-29_how-to-extend-dotnet/1_kSxd2DaV6y5EmFTNK6NzuA.png"></p>
<p>It was due to the fact that I was merging the Criteo fork master with Diagnostics master to stay in sync.</p>
<p>My coworker <a href="https://twitter.com/g_turri">Guillaume</a> explained to me that I should follow a different path. This time, I’m just creating a branch on the Microsoft repository (so no need to merge) and I’m passing by the Criteo fork just to push upstream:</p>
<pre tabindex="0"><code>git clone https://github.com/dotnet/diagnostics
cd diagnostics
git checkout -b PR_dotnet-dump_pstacks
</code></pre><p>Now I can change my local source code before pushing upstream to Criteo fork</p>
<pre tabindex="0"><code>git add/gui 
git commit
git remote add upstream https://github.com/criteo-forks/diagnostics
git push upstream PR_dotnet-dump_pstacks
</code></pre><p>That way, I can synchronize the Criteo fork without “impacting” the history of commits brought with my dedicated pull request branch.</p>
<p>The next episode will cover command implementation details.</p>
<hr>
<p><strong>What’s next? Read the second part of this article:</strong></p>
<p><a href="/posts/2020-11-09_how-to-write-commands/"><strong>How to write commands for dotnet-dump</strong>
<em>This post describes the different steps, tips and tricks to write your own commands for dotnet-dump</em>medium.com</a></p>
<p><strong>Like what you are reading? Check out more articles from Christophe on our medium account.</strong></p>
<p><a href="/posts/2020-07-31_the-net-core-journey/"><strong>The .NET Core Journey at Criteo</strong>
*This post shows the challenges we faced during the migration to .NET Core on containerized Linux for our main…*medium.com</a></p>
<p><strong>Are you interested to work with Christophe and other talented Engineers at Criteo? Take a look at our open positions:</strong></p>
<p><a href="https://careers.criteo.com/working-in-R&amp;D"><strong>Product, Research &amp; Development | Criteo Careers</strong>
careers.criteo.com</a><a href="https://careers.criteo.com/working-in-R&amp;D"></a></p>
]]></content:encoded></item><item><title>The .NET Core Journey at Criteo</title><link>https://chrisnas.github.io/posts/2020-07-31_the-net-core-journey/</link><pubDate>Fri, 31 Jul 2020 15:55:50 +0000</pubDate><guid>https://chrisnas.github.io/posts/2020-07-31_the-net-core-journey/</guid><description>This post shows the challenges we faced during the migration to .NET Core on containerized Linux for our main application.</description><content:encoded><![CDATA[<hr>
<p><img loading="lazy" src="/posts/2020-07-31_the-net-core-journey/1_WFbx_DPjik2EQydCiAahUA.jpeg"></p>
<h2 id="introduction">Introduction</h2>
<p>When I arrived at Criteo in late 2016, I joined the .NET Core “guild” (i.e. group of people from different teams dedicated to a specific topic). The first meeting I attended included Microsoft folks led by Scott Hunter (head of .NET program management) and including David Fowler (SignalR and ASP.NET Core). The goal for Criteo was simple: Moving a set of C# applications from Windows/.NET Framework to Linux/.NET Core. I guess that for Microsoft we were a customer with workloads that could be interesting to support with .NET Core. At that time, I did not realize how strong their commitment to work with us was. Our Open Source mindset was the selling point.</p>
<p>How complicated could it be? Well… this post will show you the challenges that we had to face to run, monitor and debug our applications.</p>
<hr>
<h2 id="try-it">Try it</h2>
<p>Once we got a build of all .NET Core assemblies (more on this in a forthcoming blog post), it was time to run a few applications. The first issues that we faced were related to missing features between .NET Framework and .NET Core. For example, we need cryptography support of <a href="https://github.com/dotnet/corefx/issues/4647">3DES and AES with cypher mode CFB</a> but it is (still) not available in .NET Core for Linux. Thanks to the Open Source status of .NET Core, we were able to <a href="https://github.com/criteo-forks/corefx/tree/aes_3des_cfb_mode_implementation_unix">add it to CoreFx</a>. However, since we did not implement it on MacOS/Windows as Microsoft requested for our change to be accepted as a Pull Request, we had to keep our Criteo-forked branch.</p>
<p>The second class of runtime problems we had to solve were due to differences between Windows and Linux but also with the “containerization” of the runtime environment. Let’s take two examples involving the .NET Garbage Collector. First, our containers were using Linux cgroups to manage quotas including memory and number of CPU cores usable by applications. However, at CLR startup, the GC was counting the <strong>total</strong> count of CPU cores to compute the number of heaps to allocate instead of the one defined at the cgroup level: We ended up with instant Out Of Memory automatic killing. This time our fix was done and merged in the CLR repository.</p>
<p>The second example is related to a GC optimization: During background generation 2 collections, the CLR threads working underneath are affinitized to each different CPU core to avoid locks. We were lucky enough to welcome <a href="https://twitter.com/@maoni0">Maoni Stephens</a> (Lead Dev on the GC) in our Paris office early 2018 to share our weird allocation patterns that impacted the GC. During her stay, she was kind enough to help us investigate a behavior on our servers: When <a href="https://docs.microsoft.com/en-us/sysinternals/downloads/process-explorer?WT.mc_id=DT-MVP-5003325">SysInternals ProcessExplorer</a> was running, the garbage collections were taking more time than usual. Maoni found out ProcessExplorer had an affinitized high priority thread conflicting with GC threads. During investigations related to longer response time on Linux compared to Windows. We realized that GC threads were not affinitized like it was the case on Windows and the issue was <a href="https://github.com/dotnet/coreclr/pull/24801">fixed by Jan Vorlicek</a>.</p>
<p><em>Here is our lesson: Sometimes fixes are merged into the official release and sometimes they are not. If your workloads are pushing .NET to its limits, you will probably have to build and manage your <em><a href="https://github.com/criteo-forks/coreclr"><em>own Core fork</em></a></em> and make it available to your deployments.</em></p>
<h2 id="monitor-it">Monitor it</h2>
<p>At Criteo, our Grafana dashboards measuring .NET Framework application health were based on metrics computed from Windows performance counters. Even without going to Linux, .NET Core is no more exposing performance counters so we had to entirely rebuild our metrics collection system!</p>
<p>Based on Microsoft feedbacks, we decided to listen to CLR events emitted via ETW on Windows and LTTng on Linux. In addition to work for both Operating Systems, these events are also providing accurate details about thread contention, exceptions and garbage collections not available with Performance counters. Please refer to our <a href="/posts/2019-10-17_how-to-expose-your/">series of blog posts</a> for more details and reusable code samples to integrate these events into your own systems.</p>
<p>Our first Linux metrics collection implementation was based on LTTng and we presented our journey during the <a href="https://www.youtube.com/watch?v=pMl9RM9h2eg&amp;list=PLuo4E47p5_7bfeZyYIyNYM-f-2tmr0neu&amp;index=6">Tracing Summit in 2017</a>. Microsoft already built <a href="https://github.com/microsoft/perfview/blob/master/documentation/TraceEvent/TraceEventLibrary.md">TraceEvent</a>, an assembly allowing .NET code to parse CLR events for both Windows and Linux. Unfortunately for us, the Linux part was only able to load traces files but we needed live session like on Windows where you can listen to events emitted by running applications. Since this code is Open Source, <a href="https://twitter.com/@GregoryLeocadie">Gregory</a> was able to add the <a href="https://github.com/microsoft/perfview/pull/340">live session feature</a> to TraceEvent.</p>
<p>With .NET Core 3.0 Microsoft provided a way to exchange events common to Linux and Windows called EventPipes. So… we moved our collection implementation from LTTng to EventPipe (look at our <a href="/posts/2019-10-17_how-to-expose-your/">blog series</a> and <a href="https://www.youtube.com/watch?v=Jpoy3O6x-wM">DotNext conference session</a> for more details and reusable code sample). With the new EventPipe implementation in the CLR came performance issues not seen by Microsoft. The reason is simple: Some of our applications are running hundreds of threads to process thousands of requests per second and allocate memory like crazy. In that kind of context, the CLR has a lot to do and so, has a lot of events to generate and emit via LTTng or EventPipes.</p>
<p><img loading="lazy" src="/posts/2020-07-31_the-net-core-journey/1_P_gRXkTbBaDLhsQSnWDJIQ.png"></p>
<p>The initial implementation was <a href="https://github.com/dotnet/runtime/issues/12204">lacking some</a> filtering and too many events were generated or expensive event payload was created even though the events were not emitted. Based on our feedback, the Microsoft Diagnostic team was very responsive and quickly fixed the problem.</p>
<p><em>Microsoft did not “just” move to Open Source, the teams are working deeply integrated with the issue/pull request model of GitHub. So don’t be shy and if you find a problem, create an issue with a detailed reproduction and even better, provide a pull request with the fix. Everyone in the community will benefit!</em></p>
<h2 id="run-it">Run it</h2>
<p>With these metrics, we started to investigate some performance differences (mostly response time) between Windows and containerized Linux.</p>
<p><img loading="lazy" src="/posts/2020-07-31_the-net-core-journey/1_h41QfdE5wVef3pD8DZ6twA.png"></p>
<p>We saw a huge performance difference on Linux: Both response time (x2) and scalability (timeout increase with QPS). Our team spent a lot of time to improve the situation up to the point where it was possible to send the applications to production.</p>
<p>In the new containerized environment we faced the same kind of <em>noisy neighbor</em> symptoms that we had with Process Explorer. If the CPU cores are not dedicated to a container (as it was for us at the beginning), this scenario happens a lot. So we updated the scheduling system to dedicate CPU cores to containers.</p>
<p>On a totally different area, we found out that the way .NET Core handles network I/O continuation had an impact on our main application. To give a bit of context, this application has to handle a lot of requests and is response-time driven. During the processing of a request, the current thread might have to send an HTTP request before continuing its processing. Since this is done asynchronously, the thread is now available to process more incoming requests and this is good for throughput. However, it means that when the inner HTTP request comes back, all available threads might be processing new incoming requests and it will take time to complete the old one. The net effect is to increase the median response time and this is not something we want!</p>
<p>The .NET Core implementation is relying on the .NET ThreadPool that shares its threads with all the async/await magic and the incoming requests processing (The .NET Framework implementation is using a totally different implementation based on I/O completion ports on Windows). To solve the issue, <a href="https://twitter.com/KooKiz">Kevin</a> <a href="https://github.com/criteo-forks/corefx/commit/dda2c4d80fd2d74b3dc7e0833e2a6794f1e290d3">implemented a custom thread pool</a> to handle network I/O and we keep on <a href="https://github.com/criteo-forks/corefx/commit/2acc917aef47798243cc221afc9b360c86ed60b7">optimizing it</a>. When you work on this kind of deep area of code-shared by so many different workloads, you realize that it is impossible to find the silver bullet.</p>
<h2 id="debug-it">Debug it</h2>
<p>What would you do if something would go wrong in an application? On Windows, with Visual Studio, we are able to remote debug a rogue application to set a breakpoint, look at fields and properties or even have a high-level view of what threads are doing with the ParallelStacks view. In the worst case, SysInternals <a href="https://docs.microsoft.com/en-us/visualstudio/debugger/remote-debugging-dotnet-core-linux-with-ssh?WT.mc_id=DT-MVP-5003325&amp;view=vs-2019">procdump </a>allows us to take a snapshot of the application and analyze it on our developer’s machine with WinDBG or Visual Studio.</p>
<p>In terms of remote debugging a Linux application, Microsoft provides an <a href="https://docs.microsoft.com/en-us/visualstudio/debugger/remote-debugging-dotnet-core-linux-with-ssh?WT.mc_id=DT-MVP-5003325">SSH-based solution</a> to attach to a running application. However, for security reasons, it is not allowed to run an SSH server in our Criteo containers. <em>The solution was to implement the communication protocol with VsDbg for Linux on top of WebSockets.</em></p>
<p><img loading="lazy" src="/posts/2020-07-31_the-net-core-journey/1_dBiRXngqIZIMqAyQQ1PryA.png"></p>
<p>Well… this was not enough. Hosting architecture (Marathon and Mesos in our case) ensures that applications in containers are running smoothly by sending requests to <em>health check</em> endpoints. If the application replies that everything is fine, then the container is safe. If the application does not answer as expected (including retries), then Marathon/Mesos kills the application and cleans up the container. Now think about what will happen if you set a breakpoint in the application and you dig into the data structures content in Visual Studio Watch/Quick Watch panels for a few minutes. Behind the scene, the debugger has to freeze all application threads, including the ones from the thread pool responsible to answer health checks. As you have probably guessed already, the debugging session will not end well.</p>
<p>This is why the previous figure shows an arrow between Marathon and the Remote Debugger which acts as a proxy for the application health check. When a debugging session starts (i.e. when the WebSockets code executes the protocol), the Remote Debugger knows that it should answer OK instead of calling the application endpoint that might never answer.</p>
<p>When remote debugging is not enough, how do you take a memory snapshot of the application? For example, if the health check does not answer after a series of retry, the Remote Debugger is calling the <a href="https://github.com/dotnet/runtime/blob/master/docs/design/coreclr/botr/xplat-minidump-generation.md">createdump tool</a> installed with the .NET Core runtime to generate a dump file. Again, since the memory dump creation of 40+ GB applications could take several minutes, the same health check proxy mechanism has been put in place.</p>
<p>Once the dump file is created, the remote debugger let Marathon kill the application. But wait! This is not enough because in that case, the container will be cleaned up and the disk storage will disappear. Not a problem, after a dump has been generated by createdump, the file is sent to a “Dump Navigator” application (one per data center). This application is providing a simple HTML user interface to get high-level details of the application state such as thread stacks or managed heap content.</p>
<p><img loading="lazy" src="/posts/2020-07-31_the-net-core-journey/1_jcwiOFsn6SN305A_f_vuxQ.png"></p>
<p>On Windows, we have built our own set of <a href="https://github.com/chrisnas/DebuggingExtensions/blob/master/Documentation/gsose.md">extension commands</a> that allow us to investigate memory, threadpool starvation, thread contention, or timer leak scenarios in a Windows memory dump with WinDBG as shown during this <a href="https://www.youtube.com/watch?v=biDJkJ4L_K8">NDC Oslo conference session</a>. Note that they are also <a href="https://github.com/kevingosse/LLDB-LoadManaged">usable with LLDB</a> on Linux. These commands are leveraging the <a href="https://github.com/microsoft/clrmd">ClrMD Microsoft library</a> that gives you access to a live process or a memory dump in C#. Thanks to the Linux support that has been added to this library by Microsoft developers, it was easy to reuse the code into our Dump Navigator application. I definitively recommend to look at the API provided by ClrMD to automate and build your own tools. The <a href="/posts/2019-12-31_getting-another-view-on/">long Criteo blog series</a> is a good start in addition to my <a href="https://www.youtube.com/watch?v=O8c5WwfbGFU">DotNext conference session</a>.</p>
<h2 id="conclusion">Conclusion</h2>
<p>Even though some of our main applications moved to .NET Core running on containerized Linux with a large set of monitoring/debugging tools, the journey is not over. We are now testing the preview of .NET Core 5.0 (like we did for 3.0) to check if it supports Criteo specific needs. If this is not the case, we will figure out why and find solutions to integrate into the code. Same for the tools: I have started to <a href="https://github.com/dotnet/diagnostics/pull/1376">add our extension commands</a> to Microsoft dotnet-dump CLI tool used to analyze both Windows and Linux dumps.</p>
<p>At least we could say that we not only helped ourselves but also Microsoft to understand how far .NET Core could go and even the whole .NET Windows and Linux community. This is where Open Source shines!</p>
<hr>
<p><strong>Stay tuned for the next article in our mini-series. Don’t forget to head over to our previous articles of this journey:</strong></p>
<p><a href="https://medium.com/criteo-labs/migrating-arbitrage-to-apache-mesos-3f474179ec0b"><strong>Migrating Arbitrage to Apache Mesos</strong>
*Lessons learned from migrating our largest application to our container platform.*medium.com</a><a href="https://medium.com/criteo-labs/migrating-arbitrage-to-apache-mesos-3f474179ec0b"></a><a href="https://medium.com/criteo-labs/moving-net-to-linux-at-scale-d8ff49b42661"><strong>Moving .NET to Linux at Scale</strong>
*The story of a multi-year migration: How we changed Criteo’s whole foundation.*medium.com</a><a href="https://medium.com/criteo-labs/moving-net-to-linux-at-scale-d8ff49b42661"></a></p>
<hr>
<p><strong>Interested in joining the challenge? Head over to our career site!</strong></p>
<p><a href="https://careers.criteo.com/working-in-R&amp;D"><strong>Product, Research &amp; Development | Criteo Careers</strong>
careers.criteo.com</a><a href="https://careers.criteo.com/working-in-R&amp;D"></a></p>
]]></content:encoded></item><item><title>Getting another view on thread stacks with ClrMD</title><link>https://chrisnas.github.io/posts/2019-12-31_getting-another-view-on/</link><pubDate>Tue, 31 Dec 2019 10:52:00 +0000</pubDate><guid>https://chrisnas.github.io/posts/2019-12-31_getting-another-view-on/</guid><description>This post of the series details how to look into your threads stack with ClrMD to get method calls, parameters and local variables.</description><content:encoded><![CDATA[<hr>
<p>This post of the series details how to look into your threads stack with ClrMD.</p>
<h2 id="introduction">Introduction</h2>
<p>It’s been a long time (see the resources at the end) since I’ve been discussing what ClrMD could bring to .NET developers/DevOps! My colleague <a href="https://twitter.com/KooKiz">Kevin</a> just wrote <a href="https://medium.com/@kevingosse/dumping-stack-objects-with-clrmd-c002dab4651b">an article about how to emulate SOS <strong>DumpStackObjects</strong></a> command both on Windows and Linux with ClrMD. This implementation lists the objects on the stack but without their values (like strings content for example) nor the stack frames corresponding to the method calls.</p>
<p>The rest of the post will show you, with ClrMD, how to get an higher view, closer to what the SOS <strong>ClrStack</strong> command could provide.</p>
<p>Let’s take this simple application as an example:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span><span class="lnt">35
</span><span class="lnt">36
</span><span class="lnt">37
</span><span class="lnt">38
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-csharp" data-lang="csharp"><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Program</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kd">static</span> <span class="k">void</span> <span class="n">Main</span><span class="p">(</span><span class="kt">string</span><span class="p">[]</span> <span class="n">args</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">Host</span> <span class="n">h</span> <span class="p">=</span> <span class="k">new</span> <span class="n">Host</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">        <span class="n">h</span><span class="p">.</span><span class="n">Base</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Host</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kd">public</span> <span class="k">void</span> <span class="n">Base</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="kt">int</span> <span class="n">iValue</span> <span class="p">=</span> <span class="n">Guid</span><span class="p">.</span><span class="n">NewGuid</span><span class="p">().</span><span class="n">GetHashCode</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">        <span class="kt">bool</span> <span class="n">bValue</span> <span class="p">=</span> <span class="p">(</span><span class="n">iValue</span> <span class="p">%</span> <span class="m">2</span><span class="p">)</span> <span class="p">==</span> <span class="m">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="kt">string</span> <span class="n">parameter</span> <span class="p">=</span> <span class="n">Guid</span><span class="p">.</span><span class="n">NewGuid</span><span class="p">().</span><span class="n">ToString</span><span class="p">().</span><span class="n">Substring</span><span class="p">(</span><span class="m">0</span><span class="p">,</span><span class="m">1</span><span class="p">)</span> <span class="p">+</span> <span class="s">&#34;_1234567890&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="n">Console</span><span class="p">.</span><span class="n">WriteLine</span><span class="p">(</span><span class="n">parameter</span> <span class="p">+</span> <span class="s">&#34; = &#34;</span> <span class="p">+</span> <span class="n">First</span><span class="p">(</span><span class="n">iValue</span><span class="p">,</span> <span class="n">bValue</span><span class="p">,</span> <span class="n">parameter</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="kd">private</span> <span class="kt">int</span> <span class="n">First</span><span class="p">(</span><span class="kt">int</span> <span class="n">iValue</span><span class="p">,</span> <span class="kt">bool</span> <span class="n">bValue</span><span class="p">,</span> <span class="kt">string</span> <span class="n">parameter</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">Guid</span> <span class="n">guid</span> <span class="p">=</span> <span class="n">Guid</span><span class="p">.</span><span class="n">NewGuid</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">Second</span><span class="p">(</span><span class="n">bValue</span><span class="p">,</span> <span class="n">guid</span><span class="p">)</span> <span class="p">/</span> <span class="m">2</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="kd">private</span> <span class="kt">int</span> <span class="n">Second</span><span class="p">(</span><span class="kt">bool</span> <span class="n">bValue</span><span class="p">,</span> <span class="n">Guid</span> <span class="n">guid</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">Third</span><span class="p">(</span><span class="n">guid</span><span class="p">).</span><span class="n">Length</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="kd">private</span> <span class="kt">string</span> <span class="n">Third</span><span class="p">(</span><span class="n">Guid</span> <span class="n">guid</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">Console</span><span class="p">.</span><span class="n">WriteLine</span><span class="p">(</span><span class="s">$&#34;call   procdump -ma {Process.GetCurrentProcess().Id}&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="n">Console</span><span class="p">.</span><span class="n">ReadLine</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="s">$&#34;{guid.GetHashCode()}#{guid.GetHashCode()}#{guid.GetHashCode()}&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>As you can see, I’ve mixed value and reference types as parameters and local variables up to the call to the <code>Third</code> method that displays the <a href="https://docs.microsoft.com/en-us/sysinternals/downloads/procdump"><strong>procdump</strong></a> command line to execute in order to generate a memory dump of the process.</p>
<h2 id="use-windbg--sosluke">Use WinDBG + SOS Luke!</h2>
<p>When you open it with WinDBG and load SOS, here is the result of the <strong>dso</strong> command:</p>
<p><img loading="lazy" src="/posts/2019-12-31_getting-another-view-on/1_LJ5KZ3Vymkcla6eJ3sug6Q.png"></p>
<p>The <strong>clrstack</strong> command shows the stacked method calls:</p>
<p><img loading="lazy" src="/posts/2019-12-31_getting-another-view-on/1_0lB0DVD8gCrEPYYQBHIUKQ.png"></p>
<p>And if you use the <strong>-a</strong> parameter, you will get methods with their parameters and local variables (or <strong>-p</strong> for parameters only and <strong>-l</strong> for local variables only):</p>
<p><img loading="lazy" src="/posts/2019-12-31_getting-another-view-on/1_PMv0oK5BqBCBDrI_bF1g5w.png"></p>
<p>It is weird that SOS implementation does not give the type of both the parameters and locals. But wait! While researching for this post, I looked at the SOS implementation (now in the strike.cs file moved from the <strong>coreclr</strong> to the <strong>diagnostics</strong> repository) to <a href="https://github.com/dotnet/diagnostics/blob/master/src/SOS/Strike/strike.cpp#L13165">find this nice comment</a>:</p>
<p><img loading="lazy" src="/posts/2019-12-31_getting-another-view-on/1_Rg0WDui494pjE9ari7U0FA.png"></p>
<p>So I tried <strong>clrstack</strong> with <strong>-i</strong> and I got the types for parameters (and locals unlike what the comments implies):</p>
<p><img loading="lazy" src="/posts/2019-12-31_getting-another-view-on/1_nrTH9uu64zU2MLxM8whBjQ.png"></p>
<p>Even though <strong>clrstack</strong> supports the <strong>-all</strong> flag to dump the call stack of all managed threads, you might need to do your own automatic analysis on hundreds of threads and this is where ClrMD shines.</p>
<h2 id="merging-methods-and-parameterslocals">Merging methods and parameters/locals</h2>
<p>When I read Kevin’s post, I immediately thought about adding the method call on the stack based on the <a href="https://github.com/chrisnas/DebuggingExtensions/commit/4061a2c885241edd2bf964db9b7af94fc7dcd778">work I’ve done in March 2019</a> to implement the <a href="https://github.com/chrisnas/DebuggingExtensions/releases/download/1.6.3/pstacks1.3.zip">pstacks tool</a>. At that time, my goal was to aggregate the call stacks of a large number of threads in order to find out pattern of blocked threads, sharing the “same” call stacks. Visual Studio provides a great “Parallel Stacks” pane but I needed it for both Windows and Linux.</p>
<p>To list all the call stack with ClrMD, you <a href="https://github.com/chrisnas/DebuggingExtensions/blob/master/src/ParallelStacks.Runtime/ParallelStack.cs#L11">simply</a> enumerate the managed threads and for each one, its <code>StackTrace</code> property contains the list of <code>StackFrame</code> objects corresponding to each method call.</p>
<p><img loading="lazy" src="/posts/2019-12-31_getting-another-view-on/1__F2Z31l2DikZkOVEr6SSmQ.png"></p>
<p>The <code>StackPointer</code> property of each frame contains the address of the frame in the call stack, allowing a mapping of the method call with its parameters and locals:</p>
<p><img loading="lazy" src="/posts/2019-12-31_getting-another-view-on/1_HQVchR6XY_1E18Wr7k_8ow.png"></p>
<p>As always with stacks, lower addresses correspond to the last things added to the stack (i.e. last called method). While checking between what is shown by SOS, the parameters/locals addresses and frame stack pointers, you realize that all objects at an address in the stack equal or below the <code>StackPointer</code> of a frame are either parameters or local variables of the frame method.</p>
<p>Even better, for non static method, you can guess what is the <em><strong>this</strong></em>* *implicit parameter if the address is the same as the frame <code>StackPointer</code>; shown with the green <strong>=</strong> sign in the previous screenshot and prefixed by <strong>&gt;</strong> in Kevin’s updated code that merges the method calls to the parameters and locals:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span><span class="lnt">35
</span><span class="lnt">36
</span><span class="lnt">37
</span><span class="lnt">38
</span><span class="lnt">39
</span><span class="lnt">40
</span><span class="lnt">41
</span><span class="lnt">42
</span><span class="lnt">43
</span><span class="lnt">44
</span><span class="lnt">45
</span><span class="lnt">46
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-csharp" data-lang="csharp"><span class="line"><span class="cl"><span class="k">for</span> <span class="p">(</span><span class="kt">ulong</span> <span class="n">ptr</span> <span class="p">=</span> <span class="n">stackTop</span><span class="p">;</span> <span class="n">ptr</span> <span class="p">&lt;=</span> <span class="n">stackLimit</span><span class="p">;</span> <span class="n">ptr</span> <span class="p">+=</span> <span class="p">(</span><span class="kt">ulong</span><span class="p">)</span><span class="n">runtime</span><span class="p">.</span><span class="n">PointerSize</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// look for the frame corresponding to the current position in the stack</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="n">currentFrame</span><span class="p">.</span><span class="n">StackPointer</span> <span class="p">&lt;=</span> <span class="n">ptr</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">Console</span><span class="p">.</span><span class="n">WriteLine</span><span class="p">(</span><span class="n">FormatFrame</span><span class="p">(</span><span class="n">currentFrame</span><span class="p">));</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="n">nFrame</span><span class="p">++;</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="n">nFrame</span> <span class="p">&lt;</span> <span class="n">frames</span><span class="p">.</span><span class="n">Count</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="n">currentFrame</span> <span class="p">=</span> <span class="n">frames</span><span class="p">[</span><span class="n">nFrame</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="k">else</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">break</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="kt">ulong</span> <span class="n">obj</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(!</span><span class="n">runtime</span><span class="p">.</span><span class="n">ReadPointer</span><span class="p">(</span><span class="n">ptr</span><span class="p">,</span> <span class="k">out</span> <span class="n">obj</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">break</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(!</span><span class="n">IsInHeap</span><span class="p">(</span><span class="n">heap</span><span class="p">,</span> <span class="n">obj</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">continue</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="kt">var</span> <span class="n">type</span> <span class="p">=</span> <span class="n">heap</span><span class="p">.</span><span class="n">GetObjectType</span><span class="p">(</span><span class="n">obj</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="n">type</span> <span class="p">==</span> <span class="kc">null</span> <span class="p">||</span> <span class="n">type</span><span class="p">.</span><span class="n">IsFree</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">continue</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">// try to find implicit &#34;this&#34; parameter in case of non-static method</span>
</span></span><span class="line"><span class="cl">    <span class="kt">var</span> <span class="n">myFrame</span> <span class="p">=</span> <span class="p">(</span><span class="n">nFrame</span> <span class="p">==</span> <span class="m">0</span><span class="p">)</span> <span class="p">?</span> <span class="n">currentFrame</span> <span class="p">:</span> <span class="n">frames</span><span class="p">[</span><span class="n">nFrame</span><span class="p">-</span><span class="m">1</span><span class="p">];</span>
</span></span><span class="line"><span class="cl">    <span class="n">separator</span> <span class="p">=</span> <span class="p">((</span><span class="n">myFrame</span><span class="p">.</span><span class="n">StackPointer</span> <span class="p">==</span> <span class="n">ptr</span><span class="p">)</span> <span class="p">&amp;&amp;</span>
</span></span><span class="line"><span class="cl">                 <span class="p">(</span><span class="n">myFrame</span><span class="p">.</span><span class="n">Method</span> <span class="p">!=</span> <span class="kc">null</span><span class="p">)</span> <span class="p">&amp;&amp;</span>
</span></span><span class="line"><span class="cl">                 <span class="p">(!</span><span class="n">myFrame</span><span class="p">.</span><span class="n">Method</span><span class="p">.</span><span class="n">IsStatic</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">        <span class="p">?</span> <span class="s">&#34;&gt;&#34;</span> 
</span></span><span class="line"><span class="cl">        <span class="p">:</span> <span class="s">&#34; &#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="n">Console</span><span class="p">.</span><span class="n">Write</span><span class="p">(</span><span class="s">$&#34;{ptr:x16}   {separator} &#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="n">DumpObject</span><span class="p">(</span><span class="n">heap</span><span class="p">,</span> <span class="n">type</span><span class="p">,</span> <span class="p">(</span><span class="kt">ulong</span><span class="p">)</span><span class="n">obj</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>The <code>FormatFrame</code> helper method simply prefix static methods with <strong>#</strong> instead of <strong>|</strong> for instance methods:</p>
<p>Unfortunately, I did not find any way with ClrMD to make the difference between parameters and locals. Based on what you can see in SOS implementation <a href="https://github.com/dotnet/diagnostics/blob/master/src/SOS/Strike/strike.cpp#L12916">of this part</a> of the <strong>clrstack</strong> command, it relies on the <code>EnumerateArguments</code> and <code>EnumetateLocalVariables</code> methods of <code>ICorDebugILFrame</code> which is not exposed by ClrMD. There is another undocumented implementation based on <a href="https://github.com/dotnet/coreclr/blob/master/src/pal/prebuilt/inc/xclrdata.h#L6067">private interfaces</a> I could not leverage neither. For a larger discussion around stack walking in .NET, read <a href="https://mattwarren.org/2019/01/21/Stackwalking-in-the-.NET-Runtime/">this great post</a> by Matt Warren.</p>
<p>Also, without any explicit access to specific parameter or local, I did not find a way to get the value of primitive and value type instances stored on the stack. However, it is still possible to get them for boxed ones and reference type instances such as string for example.</p>
<h2 id="getting-instances-from-thestack">Getting instances from the stack</h2>
<p>In the last code excerpt, I did not describe the <code>DumpObject</code> helper method used to display an object on the stack. The implementation provided by Kevin was used to show the address and the type of the object:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-csharp" data-lang="csharp"><span class="line"><span class="cl"><span class="n">Console</span><span class="p">.</span><span class="n">WriteLine</span><span class="p">(</span><span class="s">$&#34;{objAddress:x16} {type.Name}&#34;</span><span class="p">);</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>The next step would be to display value for primitive types such as numbers, boolean, string and even array size:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-csharp" data-lang="csharp"><span class="line"><span class="cl"><span class="kd">private</span> <span class="kd">static</span> <span class="k">void</span> <span class="n">DumpObject</span><span class="p">(</span><span class="n">ClrHeap</span> <span class="n">heap</span><span class="p">,</span> <span class="n">ClrType</span> <span class="n">type</span><span class="p">,</span> <span class="kt">ulong</span> <span class="n">objAddress</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// get value for simple types</span>
</span></span><span class="line"><span class="cl">    <span class="kt">string</span> <span class="n">valueOrAddress</span> <span class="p">=</span> 
</span></span><span class="line"><span class="cl">        <span class="p">(</span><span class="n">type</span><span class="p">.</span><span class="n">Name</span> <span class="p">==</span> <span class="s">&#34;System.Char&#34;</span><span class="p">)</span> <span class="p">?</span> <span class="s">$&#34;{type.GetValue(objAddress),16}&#34;</span> <span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="p">(</span><span class="n">type</span><span class="p">.</span><span class="n">Name</span> <span class="p">==</span> <span class="s">&#34;System.String&#34;</span><span class="p">)</span> <span class="p">?</span> <span class="s">$&#34;{FormatString(type.GetValue(objAddress).ToString())}&#34;</span> <span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="p">(</span><span class="n">type</span><span class="p">.</span><span class="n">Name</span> <span class="p">==</span> <span class="s">&#34;System.Bool&#34;</span><span class="p">)</span> <span class="p">?</span> <span class="s">$&#34;{FormatString(((bool)type.GetValue(objAddress)).ToString())}&#34;</span> <span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="p">(</span><span class="n">type</span><span class="p">.</span><span class="n">Name</span> <span class="p">==</span> <span class="s">&#34;System.Byte&#34;</span><span class="p">)</span> <span class="p">?</span> <span class="s">$&#34;{FormatString(((byte)type.GetValue(objAddress)).ToString())}&#34;</span> <span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="p">(</span><span class="n">type</span><span class="p">.</span><span class="n">Name</span> <span class="p">==</span> <span class="s">&#34;System.SByte&#34;</span><span class="p">)</span> <span class="p">?</span> <span class="s">$&#34;{FormatString(((sbyte)type.GetValue(objAddress)).ToString())}&#34;</span> <span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="p">(</span><span class="n">type</span><span class="p">.</span><span class="n">Name</span> <span class="p">==</span> <span class="s">&#34;System.Decimal&#34;</span><span class="p">)</span> <span class="p">?</span> <span class="s">$&#34;{FormatString(((decimal)type.GetValue(objAddress)).ToString())}&#34;</span> <span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="p">(</span><span class="n">type</span><span class="p">.</span><span class="n">Name</span> <span class="p">==</span> <span class="s">&#34;System.Double&#34;</span><span class="p">)</span> <span class="p">?</span> <span class="s">$&#34;{FormatString(((double)type.GetValue(objAddress)).ToString())}&#34;</span> <span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="p">(</span><span class="n">type</span><span class="p">.</span><span class="n">Name</span> <span class="p">==</span> <span class="s">&#34;System.Single&#34;</span><span class="p">)</span> <span class="p">?</span> <span class="s">$&#34;{FormatString(((float)type.GetValue(objAddress)).ToString())}&#34;</span> <span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="p">(</span><span class="n">type</span><span class="p">.</span><span class="n">Name</span> <span class="p">==</span> <span class="s">&#34;System.Int32&#34;</span><span class="p">)</span> <span class="p">?</span> <span class="s">$&#34;{FormatString(((int)type.GetValue(objAddress)).ToString())}&#34;</span> <span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="p">(</span><span class="n">type</span><span class="p">.</span><span class="n">Name</span> <span class="p">==</span> <span class="s">&#34;System.SInt32&#34;</span><span class="p">)</span> <span class="p">?</span> <span class="s">$&#34;{FormatString(((uint)type.GetValue(objAddress)).ToString())}&#34;</span> <span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="p">(</span><span class="n">type</span><span class="p">.</span><span class="n">Name</span> <span class="p">==</span> <span class="s">&#34;System.Int64&#34;</span><span class="p">)</span> <span class="p">?</span> <span class="s">$&#34;{FormatString(((long)type.GetValue(objAddress)).ToString())}&#34;</span> <span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="p">(</span><span class="n">type</span><span class="p">.</span><span class="n">Name</span> <span class="p">==</span> <span class="s">&#34;System.SInt64&#34;</span><span class="p">)</span> <span class="p">?</span> <span class="s">$&#34;{FormatString(((ulong)type.GetValue(objAddress)).ToString())}&#34;</span> <span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="p">(</span><span class="n">type</span><span class="p">.</span><span class="n">IsArray</span><span class="p">)</span> <span class="p">?</span> <span class="s">$&#34;{FormatString(GetArrayAsString(type, objAddress))}&#34;</span> <span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="s">$&#34;{objAddress:x16}&#34;</span><span class="p">;</span>  <span class="c1">// work also for IntPtr</span>
</span></span><span class="line"><span class="cl">    <span class="n">Console</span><span class="p">.</span><span class="n">WriteLine</span><span class="p">(</span><span class="s">$&#34;{valueOrAddress} {type.Name}&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>Most of this code is based on the <code>GetValue</code> helper from <code>ClrType</code>: it returns the right “thing” for simple types. Look at ClrMD <a href="https://github.com/microsoft/clrmd/blob/c35e2115241e7dc6f9c835b4c59b9e396ec6471b/src/Microsoft.Diagnostics.Runtime/src/Implementation/ValueReader.cs#L33">implementation details</a> to get a better understanding of how the value is rebuilt.</p>
<p>The <code>GetArrayAsString</code> simply returns the number of elements in the array:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-csharp" data-lang="csharp"><span class="line"><span class="cl"><span class="kd">private</span> <span class="kd">static</span> <span class="kt">string</span> <span class="n">GetArrayAsString</span><span class="p">(</span><span class="n">ClrType</span> <span class="n">type</span><span class="p">,</span> <span class="kt">ulong</span> <span class="n">objAddress</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kt">var</span> <span class="n">elementCount</span> <span class="p">=</span> <span class="n">type</span><span class="p">.</span><span class="n">GetArrayLength</span><span class="p">(</span><span class="n">objAddress</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="s">$&#34;length = {elementCount}&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>And the call stack is now complete!</p>
<p><img loading="lazy" src="/posts/2019-12-31_getting-another-view-on/1_-N5vbQ2oPCAath_WSutxKA.png"></p>
<p>Note that you may even get more locals or parameters than with WinDBG+SOS but don’t ask me why…</p>
<p>For more advanced object formatting cases such as dumping structs or enumerating fields and their value, I would highly recommend to look at the related <a href="https://github.com/microsoft/dotnet-samples/blob/master/Microsoft.Diagnostics.Runtime/CLRMD/docs/TypesAndFields.md">ClrMD documentation page</a> (just replace <code>GCHeapType</code> by <code>ClrType</code> and you’ll be safe).</p>
<h2 id="resources">Resources</h2>
<ul>
<li><a href="https://medium.com/@kevingosse/dumping-stack-objects-with-clrmd-c002dab4651b">Dumping stack objects with ClrMD</a> by <a href="https://twitter.com/KooKiz">Kevin Gosse</a></li>
<li><a href="https://mattwarren.org/2019/01/21/Stackwalking-in-the-.NET-Runtime/">Stack walking in the .NET Runtime</a> by <a href="https://twitter.com/matthewwarren">Matt Warren</a></li>
<li>Part 1: <a href="http://labs.criteo.com/2017/02/going-beyond-sos-clrmd-part-1">Bootstrap ClrMD to load a dump</a>.</li>
<li>Part 2: <a href="http://labs.criteo.com/2017/03/clrmd-part-2-clrruntime-clrheap-traverse-managed-heap/">Find duplicated strings with ClrMD heap traversing</a>.</li>
<li>Part 3: <a href="http://labs.criteo.com/2017/04/clrmd-part-3-dea%E2%80%A6s-to-list-timers/">List timers by following static fields links</a>.</li>
<li>Part 4: <a href="http://labs.criteo.com/2017/05/clrmd-part-4-callbacks-called-timers/">Identify timers callback and other properties</a>.</li>
<li>Part 5: <a href="http://labs.criteo.com/2017/06/clrmd-part-5-how-to-use-clrmd-to-extend-sos-in-windbg/">Use ClrMD to extend SOS in WinDBG</a>.</li>
<li>Part 6: <a href="http://labs.criteo.com/2017/08/clrmd-part-6-manipulate-memory-structures-like-real-objects/">Manipulate memory structures like real objects</a>.</li>
<li>Part 7: <a href="http://labs.criteo.com/2017/08/clrmd-part-7-manipulate-nested-structs-using-dynamic/">Manipulate nested structs using dynamic</a>.</li>
<li>Part 8: <a href="http://labs.criteo.com/2017/11/clrmd-part-8-spelunking-inside-the-net-thread-pool/">Spelunking inside the .NET Thread Pool</a></li>
<li>Part 9: <a href="https://labs.criteo.com/2017/12/clrmd-part-9-deciphering-tasks-thread-pool-items/">Deciphering Tasks and Thread Pool items</a></li>
</ul>
]]></content:encoded></item><item><title>ClrMD Part 8 – Spelunking inside the .NET Thread Pool</title><link>https://chrisnas.github.io/posts/2017-11-03_clrmd-part-8-net-thread-pool/</link><pubDate>Fri, 03 Nov 2017 10:57:24 +0000</pubDate><guid>https://chrisnas.github.io/posts/2017-11-03_clrmd-part-8-net-thread-pool/</guid><description>This post of the series shows how to easily list pending tasks and work items…</description><content:encoded><![CDATA[<p>This post of the series shows how to easily list pending tasks and work items managed by the .NET thread pool using DynaMD proxies.</p>
<p>Part 1: <a href="/posts/2017-02-21_clrmd-part-1-going-beyond/">Bootstrap ClrMD to load a dump</a>.</p>
<p>Part 2: <a href="/posts/2017-03-24_clrmd-part-2-from-clrruntime/">Find duplicated strings with ClrMD heap traversing</a>.</p>
<p>Part 3: <a href="/posts/2017-05-03_clrmd-part-3-static-instance-fields/">List timers by following static fields links</a>.</p>
<p>Part 4: <a href="/posts/2017-05-31_clrmd-part-4-timer-callbacks/">Identify timers callback and other properties</a>.</p>
<p>Part 5: <a href="/posts/2017-06-29_clrmd-part-5-extend-sos-windbg/">Use ClrMD to extend SOS in WinDBG</a>.</p>
<p>Part 6: <a href="/posts/2017-08-01_clrmd-part-6-memory-structures/">Manipulate memory structures like real objects</a>.</p>
<p>Part 7: <a href="/posts/2017-08-28_clrmd-part-7-nested-structs-dynamic/">Manipulate nested structs using dynamic</a>.</p>
<h3 id="introduction">Introduction</h3>
<p>The previous posts introduced the <a href="https://www.nuget.org/packages/DynaMD/">DynaMD nuget</a> that helps navigating among type instances using a C#-like syntax “instance.field”. Let’s see how to use it to enumerate the asynchronous items queued in the .NET thread pool. As a bonus, the running tasks and work items won’t be forgotten.</p>
<h3 id="threadpool-internals">ThreadPool internals</h3>
<p>The .NET ThreadPool is keeping track of the pending work items into <a href="http://www.danielmoth.com/Blog/New-And-Improved-CLR-4-Thread-Pool-Engine.aspx">two different data structures</a>:</p>
<ul>
<li>A global queue: stored as a <strong>ThreadPoolWorkQueue</strong> instance referenced by the <strong>workQueue</strong> static field</li>
</ul>
<p><img loading="lazy" src="/posts/2017-11-03_clrmd-part-8-net-thread-pool/GlobalThreadPoolQueue.png"></p>
<ul>
<li>several per-thread (TLS) local queues: stored in <strong>SparseArray&lt;ThreadPoolWorkQueue+WorkStealingQueue&gt;</strong> linked from the <strong>allThreadQueues</strong> static field</li>
</ul>
<p><img loading="lazy" src="/posts/2017-11-03_clrmd-part-8-net-thread-pool/LocalThradPoolQueues.png"></p>
<p>As you can see, the algorithm to list the pending tasks and work items starts from a static field and iterate on a linked list of <strong>QueueSegment</strong> for global queue and array of <strong>WorkStealingQueue</strong> for per thread queues. Both are storing arrays of <strong>IThreadPoolWorkItem</strong> that <strong>Task</strong> and <strong>QueueUserWorkItemCallback</strong> are implementing:</p>
<p><img loading="lazy" src="/posts/2017-11-03_clrmd-part-8-net-thread-pool/IThreadPoolWorkItem.png"></p>
<p>Too much theory… Let’s write some code!</p>
<h3 id="global-threadpool-queue">Global ThreadPool queue</h3>
<p>You have seen in a <a href="/posts/2017-05-03_clrmd-part-3-static-instance-fields/">previous post</a> how to access the value of a static field per application domain:</p>
<p><strong>EnumerateGlobalThreadPoolItems-1.cs</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-csharp" data-lang="csharp"><span class="line"><span class="cl"><span class="kd">public</span> <span class="n">IEnumerable</span><span class="p">&lt;</span><span class="n">ThreadPoolItem</span><span class="p">&gt;</span> <span class="n">EnumerateGlobalThreadPoolItems</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// look for the ThreadPoolGlobals.workQueue static field</span>
</span></span><span class="line"><span class="cl">    <span class="n">ClrModule</span> <span class="n">mscorlib</span> <span class="p">=</span> <span class="n">GetMscorlib</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="n">mscorlib</span> <span class="p">==</span> <span class="kc">null</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">throw</span> <span class="k">new</span> <span class="n">InvalidOperationException</span><span class="p">(</span><span class="s">&#34;Impossible to find mscorlib.dll&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">ClrType</span> <span class="n">queueType</span> <span class="p">=</span> <span class="n">mscorlib</span><span class="p">.</span><span class="n">GetTypeByName</span><span class="p">(</span><span class="s">&#34;System.Threading.ThreadPoolGlobals&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="n">queueType</span> <span class="p">==</span> <span class="kc">null</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">yield</span> <span class="k">break</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">ClrStaticField</span> <span class="n">workQueueField</span> <span class="p">=</span> <span class="n">queueType</span><span class="p">.</span><span class="n">GetStaticFieldByName</span><span class="p">(</span><span class="s">&#34;workQueue&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="n">workQueueField</span> <span class="p">==</span> <span class="kc">null</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">yield</span> <span class="k">break</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">// the CLR keeps one static instance per application domain</span>
</span></span><span class="line"><span class="cl">    <span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">appDomain</span> <span class="k">in</span> <span class="n">_clr</span><span class="p">.</span><span class="n">AppDomains</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>For an application domain in which the threadpool is not used, we need to check against null for the expected <strong>ThreadPoolWorkQueue</strong>:</p>
<p><strong>EnumerateGlobalThreadPoolItems-2.cs</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-csharp" data-lang="csharp"><span class="line"><span class="cl">        <span class="kt">object</span> <span class="n">workQueueValue</span> <span class="p">=</span> <span class="n">workQueueField</span><span class="p">.</span><span class="n">GetValue</span><span class="p">(</span><span class="n">appDomain</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="kt">ulong</span> <span class="n">workQueueRef</span> <span class="p">=</span> <span class="p">(</span><span class="n">workQueueValue</span> <span class="p">==</span> <span class="kc">null</span><span class="p">)</span> <span class="p">?</span> <span class="m">0L</span> <span class="p">:</span> <span class="p">(</span><span class="kt">ulong</span><span class="p">)</span><span class="n">workQueueValue</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="n">workQueueRef</span> <span class="p">==</span> <span class="m">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="k">continue</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="c1">// should be System.Threading.ThreadPoolWorkQueue</span>
</span></span><span class="line"><span class="cl">        <span class="n">ClrType</span> <span class="n">workQueueType</span> <span class="p">=</span> <span class="n">_heap</span><span class="p">.</span><span class="n">GetObjectType</span><span class="p">(</span><span class="n">workQueueRef</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="n">workQueueType</span> <span class="p">==</span> <span class="kc">null</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="k">continue</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="n">workQueueType</span><span class="p">.</span><span class="n">Name</span> <span class="p">!=</span> <span class="s">&#34;System.Threading.ThreadPoolWorkQueue&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="k">continue</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">item</span> <span class="k">in</span> <span class="n">EnumerateThreadPoolWorkQueue</span><span class="p">(</span><span class="n">workQueueRef</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">yield</span> <span class="k">return</span> <span class="n">item</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>The role of the <strong>EnumerateThreadPoolWorkQueue</strong> helper method is to iterate on each <strong>QueueSegment</strong> of the linked list pointed to by the <strong>queueTail</strong> field of the per appdomain <strong>ThreadPoolWorkQueue</strong> object.</p>
<p>At the beginning of the following code, note that <strong>dynamic</strong> allows writing C# code even though the <strong>queueTail</strong> and <strong>nodes</strong> fields are not known at compile time. Even more convenient, a <strong>foreach</strong> statement is possible when the instance behind the DynaMD proxy is an array:</p>
<p><strong>EnumerateThreadPoolWorkQueue.cs</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-csharp" data-lang="csharp"><span class="line"><span class="cl"><span class="kd">private</span> <span class="n">IEnumerable</span><span class="p">&lt;</span><span class="n">ThreadPoolItem</span><span class="p">&gt;</span> <span class="n">EnumerateThreadPoolWorkQueue</span><span class="p">(</span><span class="kt">ulong</span> <span class="n">workQueueRef</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// start from the tail and follow the Next</span>
</span></span><span class="line"><span class="cl">    <span class="kt">var</span> <span class="n">proxy</span> <span class="p">=</span> <span class="n">_heap</span><span class="p">.</span><span class="n">GetProxy</span><span class="p">(</span><span class="n">workQueueRef</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="kt">var</span> <span class="n">currentQueueSegment</span> <span class="p">=</span> <span class="n">proxy</span><span class="p">.</span><span class="n">queueTail</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">while</span> <span class="p">(</span><span class="n">currentQueueSegment</span> <span class="p">!=</span> <span class="kc">null</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// get the System.Threading.ThreadPoolWorkQueue+QueueSegment nodes array</span>
</span></span><span class="line"><span class="cl">        <span class="kt">var</span> <span class="n">nodes</span> <span class="p">=</span> <span class="n">currentQueueSegment</span><span class="p">.</span><span class="n">nodes</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="n">nodes</span> <span class="p">==</span> <span class="kc">null</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="k">continue</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">item</span> <span class="k">in</span> <span class="n">nodes</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">if</span> <span class="p">(</span><span class="n">item</span> <span class="p">==</span> <span class="kc">null</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">                <span class="k">continue</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">            <span class="k">yield</span> <span class="k">return</span> <span class="n">GetThreadPoolItem</span><span class="p">(</span><span class="n">item</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="n">currentQueueSegment</span> <span class="p">=</span> <span class="n">currentQueueSegment</span><span class="p">.</span><span class="n">Next</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>The <strong>GetThreadPoolItem</strong> helper method will be described soon but first, let’s see how to get the items from the thread local queues.</p>
<h3 id="local-threadpool-queues">Local ThreadPool queues</h3>
<p>The same static field driven operations are needed to access the sparse array containing… more arrays:</p>
<p><strong>EnumerateLocalThreadPoolItems.cs</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span><span class="lnt">35
</span><span class="lnt">36
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-csharp" data-lang="csharp"><span class="line"><span class="cl"><span class="kd">public</span> <span class="n">IEnumerable</span><span class="p">&lt;</span><span class="n">ThreadPoolItem</span><span class="p">&gt;</span> <span class="n">EnumerateLocalThreadPoolItems</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kt">var</span> <span class="n">queueType</span> <span class="p">=</span> <span class="n">GetMscorlib</span><span class="p">().</span><span class="n">GetTypeByName</span><span class="p">(</span><span class="s">&#34;System.Threading.ThreadPoolWorkQueue&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="n">queueType</span> <span class="p">==</span> <span class="kc">null</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">yield</span> <span class="k">break</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">ClrStaticField</span> <span class="n">threadQueuesField</span> <span class="p">=</span> <span class="n">queueType</span><span class="p">.</span><span class="n">GetStaticFieldByName</span><span class="p">(</span><span class="s">&#34;allThreadQueues&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="n">threadQueuesField</span> <span class="p">==</span> <span class="kc">null</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">yield</span> <span class="k">break</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">foreach</span> <span class="p">(</span><span class="n">ClrAppDomain</span> <span class="n">domain</span> <span class="k">in</span> <span class="n">_clr</span><span class="p">.</span><span class="n">AppDomains</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="kt">ulong?</span> <span class="n">threadQueueRef</span> <span class="p">=</span> <span class="p">(</span><span class="kt">ulong?</span><span class="p">)</span><span class="n">threadQueuesField</span><span class="p">.</span><span class="n">GetValue</span><span class="p">(</span><span class="n">domain</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(!</span><span class="n">threadQueueRef</span><span class="p">.</span><span class="n">HasValue</span> <span class="p">||</span> <span class="n">threadQueueRef</span><span class="p">.</span><span class="n">Value</span> <span class="p">==</span> <span class="m">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="k">continue</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="kt">var</span> <span class="n">threadQueue</span> <span class="p">=</span> <span class="n">_heap</span><span class="p">.</span><span class="n">GetProxy</span><span class="p">((</span><span class="kt">ulong</span><span class="p">)</span><span class="n">threadQueueRef</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="n">threadQueue</span> <span class="p">==</span> <span class="kc">null</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="k">continue</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="kt">var</span> <span class="n">sparseArray</span> <span class="p">=</span> <span class="n">threadQueue</span><span class="p">.</span><span class="n">m_array</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="n">sparseArray</span> <span class="p">==</span> <span class="kc">null</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="k">continue</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">stealingQueue</span> <span class="k">in</span> <span class="n">sparseArray</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">if</span> <span class="p">(</span><span class="n">stealingQueue</span> <span class="p">==</span> <span class="kc">null</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">                <span class="k">continue</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">            <span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">item</span> <span class="k">in</span> <span class="n">EnumerateThreadPoolStealingQueue</span><span class="p">(</span><span class="n">stealingQueue</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">            <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="k">yield</span> <span class="k">return</span> <span class="n">item</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>The spare arrays contain either null or a stealing queue that itself contains… an array:</p>
<p><strong>EnumerateThreadPoolStealingQueue.cs</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-csharp" data-lang="csharp"><span class="line"><span class="cl"><span class="kd">private</span> <span class="n">IEnumerable</span><span class="p">&lt;</span><span class="n">ThreadPoolItem</span><span class="p">&gt;</span> <span class="n">EnumerateThreadPoolStealingQueue</span><span class="p">(</span><span class="kt">dynamic</span> <span class="n">stealingQueue</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kt">var</span> <span class="n">array</span> <span class="p">=</span> <span class="n">stealingQueue</span><span class="p">.</span><span class="n">m_array</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="n">array</span> <span class="p">==</span> <span class="kc">null</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">yield</span> <span class="k">break</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">item</span> <span class="k">in</span> <span class="n">array</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="n">item</span> <span class="p">==</span> <span class="kc">null</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="k">continue</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="k">yield</span> <span class="k">return</span> <span class="n">GetThreadPoolItem</span><span class="p">(</span><span class="n">item</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>Now that we managed to retrieve the thread pool items, we can try to decipher them.</p>
<h3 id="deciphering-thread-pool-items">Deciphering thread pool items</h3>
<p>A thread pool item stored in the global or in the local queues could be a <strong>Task</strong>, a <strong>QueueUserWorkItemCallback</strong> or a simple method:</p>
<p><strong>GetThreadPoolItem.cs</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-csharp" data-lang="csharp"><span class="line"><span class="cl"><span class="kd">private</span> <span class="n">ThreadPoolItem</span> <span class="n">GetThreadPoolItem</span><span class="p">(</span><span class="kt">dynamic</span> <span class="n">item</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// get the ClrType directly from the dynamic proxy</span>
</span></span><span class="line"><span class="cl">    <span class="n">ClrType</span> <span class="n">itemType</span> <span class="p">=</span> <span class="n">item</span><span class="p">.</span><span class="n">GetClrType</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="n">itemType</span><span class="p">.</span><span class="n">Name</span> <span class="p">==</span> <span class="s">&#34;System.Threading.Tasks.Task&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">GetTask</span><span class="p">(</span><span class="n">item</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">itemType</span><span class="p">.</span><span class="n">Name</span> <span class="p">==</span> <span class="s">&#34;System.Threading.QueueUserWorkItemCallback&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">GetQueueUserWorkItemCallback</span><span class="p">(</span><span class="n">item</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">else</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// create a raw information</span>
</span></span><span class="line"><span class="cl">        <span class="n">ThreadPoolItem</span> <span class="n">tpi</span> <span class="p">=</span> <span class="k">new</span> <span class="n">ThreadPoolItem</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="n">Type</span> <span class="p">=</span> <span class="n">ThreadRoot</span><span class="p">.</span><span class="n">Raw</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="n">Address</span> <span class="p">=</span> <span class="p">(</span><span class="kt">ulong</span><span class="p">)</span><span class="n">item</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">            <span class="n">MethodName</span> <span class="p">=</span> <span class="n">itemType</span><span class="p">.</span><span class="n">Name</span>
</span></span><span class="line"><span class="cl">        <span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="n">tpi</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>The kind of item is computed from the <strong>ClrType</strong> of the object given by the <strong>ClrHeap.GetObjectType</strong> method. An <strong>ulong</strong> address is expected by this ClrMD method and it would be easy to get from the <strong>dynamic</strong> returned by DynaMD by just casting it to <strong>ulong</strong>. However, it is easier to simply call the <strong>GetClrType</strong> method on the dynamic proxy!</p>
<h2 id="next-step">Next step…</h2>
<p>The next and last episode of the ClrMD series will show you how to decipher tasks and thread pool items to know which of your methods will be called. As a bonus, the running tasks and work items won’t be forgotten.</p>
<hr>
<p><em>Co-authored with <a href="https://twitter.com/KooKiz">Kevin Gosse</a></em></p>
]]></content:encoded></item><item><title>ClrMD Part 7 – Manipulate nested structs using dynamic</title><link>https://chrisnas.github.io/posts/2017-08-28_clrmd-part-7-nested-structs-dynamic/</link><pubDate>Mon, 28 Aug 2017 14:45:58 +0000</pubDate><guid>https://chrisnas.github.io/posts/2017-08-28_clrmd-part-7-nested-structs-dynamic/</guid><description>In the previous post of the ClrMD series, we’ve seen how to use dynamic to…</description><content:encoded><![CDATA[<p>In the previous post of the ClrMD series, we’ve seen how to use <strong>dynamic</strong> to manipulate objects from a memory dump the same way as you would with actual objects. However, the code we wrote was limited to class instances. This time, we’re going to see how to extend it to structs. The associated code is part of the DynaMD library and is <a href="https://github.com/kevingosse/DynaMD">available on GitHub</a> and <a href="https://www.nuget.org/packages/DynaMD/">nuget</a>.</p>
<p>Part 1: <a href="/posts/2017-02-21_clrmd-part-1-going-beyond/">Bootstrap ClrMD to load a dump</a>.</p>
<p>Part 2: <a href="/posts/2017-03-24_clrmd-part-2-from-clrruntime/">Find duplicated strings with ClrMD heap traversing</a>.</p>
<p>Part 3: <a href="/posts/2017-05-03_clrmd-part-3-static-instance-fields/">List timers by following static fields links</a>.</p>
<p>Part 4: <a href="/posts/2017-05-31_clrmd-part-4-timer-callbacks/">Identify timers callback and other properties</a>.</p>
<p>Part 5: <a href="/posts/2017-06-29_clrmd-part-5-extend-sos-windbg/">Use ClrMD to extend SOS in WinDBG</a>.</p>
<p>Part 6: <a href="/posts/2017-08-01_clrmd-part-6-memory-structures/">Manipulate memory structures like real objects</a>.</p>
<p>Let’s start with a reminder of the object we’re manipulating via our proxy:</p>
<p><strong>Values.cs</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-csharp" data-lang="csharp"><span class="line"><span class="cl"><span class="kd">public</span> <span class="k">struct</span> <span class="nc">Size</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">   <span class="kd">public</span> <span class="kt">int</span> <span class="n">Width</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">   <span class="kd">public</span> <span class="kt">int</span> <span class="n">Height</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">public</span> <span class="k">struct</span> <span class="nc">Description</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">   <span class="kd">public</span> <span class="kt">int</span> <span class="n">Id</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">   <span class="kd">public</span> <span class="n">Size</span> <span class="n">Size</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">public</span> <span class="k">class</span> <span class="nc">Sample</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">   <span class="kd">public</span> <span class="kt">int</span> <span class="n">Value</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">   <span class="kd">public</span> <span class="kt">string</span> <span class="n">Name</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl">   <span class="kd">public</span> <span class="n">Description</span> <span class="n">Description</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">   <span class="kd">public</span> <span class="n">Sample</span> <span class="n">Child</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>Accessing the value of <strong>proxy.Description.Id</strong> is a special case. Why? Because <strong>Size</strong> is a struct, and therefore is embedded directly inside of <strong>Sample</strong> outside of the responsibility of the managed heap. This scenario isn’t directly supported by ClrMD, and calling <strong>GetValue</strong> on the <strong>Size</strong> field will return null instead of the address of the struct. We need to compute this address ourselves.</p>
<p>What is the layout of those objects in memory? To find out, we can create a <strong>Sample</strong> object and then check how the memory is structured within WinDBG</p>
<p><strong>Sample.cs</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-csharp" data-lang="csharp"><span class="line"><span class="cl"><span class="k">new</span> <span class="n">Sample</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">   <span class="n">Name</span> <span class="p">=</span> <span class="s">&#34;Test&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">   <span class="n">Value</span> <span class="p">=</span> <span class="m">1</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">   <span class="n">Child</span> <span class="p">=</span> <span class="k">new</span> <span class="n">Sample</span><span class="p">(),</span>
</span></span><span class="line"><span class="cl">   <span class="n">Description</span> <span class="p">=</span> <span class="k">new</span> <span class="n">Description</span>
</span></span><span class="line"><span class="cl">   <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="n">Id</span> <span class="p">=</span> <span class="m">2</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="n">Size</span> <span class="p">=</span> <span class="k">new</span> <span class="n">Size</span>
</span></span><span class="line"><span class="cl">      <span class="p">{</span>
</span></span><span class="line"><span class="cl">         <span class="n">Width</span> <span class="p">=</span> <span class="m">3</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">         <span class="n">Height</span> <span class="p">=</span> <span class="m">4</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="cl">   <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p><img loading="lazy" src="/posts/2017-08-28_clrmd-part-7-nested-structs-dynamic/windbg.png"></p>
<p>The first address (4 bytes because the dump was taken on a 32-bit process) points to the “method table”; some metadata used internally by the CLR to identify the strong type corresponding to this instance in the managed heap. Next, we get the “1” stored by the <strong>Value</strong> field, followed by a pointer to the “Test” string stored by the <strong>Name</strong> field. The field values of the <strong>Description</strong> structure (in dark blue) are then embedded directly inside of the <strong>Sample</strong> object. And inside of that structure, we find the values of the fields of the <strong>Size</strong> structure (in light blue). Finally, the reference to the <strong>Child</strong> field is stored last in the memory of the <strong>Sample</strong> object.</p>
<p>To sum it up, to get the address of the <strong>Description</strong> field, we need to take the address of the <strong>Sample</strong> instance, add 4 bytes for the method table (8 bytes for 64-bit memory dumps), then add the offset of the field (which counts the size of the previous fields and the padding if any):</p>
<p><strong>DynamicProxy.cs</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-csharp" data-lang="csharp"><span class="line"><span class="cl"><span class="kd">private</span> <span class="n">DynamicProxy</span> <span class="n">LinkToStruct</span><span class="p">(</span><span class="n">ClrField</span> <span class="n">field</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">   <span class="kt">var</span> <span class="n">childAddress</span> <span class="p">=</span> <span class="n">_address</span> <span class="p">+</span> <span class="p">(</span><span class="kt">ulong</span><span class="p">)</span><span class="n">field</span><span class="p">.</span><span class="n">Offset</span> <span class="p">+</span> <span class="p">(</span><span class="kt">ulong</span><span class="p">)</span><span class="n">_heap</span><span class="p">.</span><span class="n">PointerSize</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">   <span class="k">return</span> <span class="k">new</span> <span class="n">DynamicProxy</span><span class="p">(</span><span class="n">_heap</span><span class="p">,</span> <span class="n">childAddress</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>We call this method from <strong>TryGetMember</strong> when we have a struct that isn’t a primitive type. ClrMD gives that information thanks to the <strong>HasSimpleValue</strong> property of <strong>ClrField</strong>:</p>
<p><strong>DynamicProxy.cs</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-csharp" data-lang="csharp"><span class="line"><span class="cl"><span class="k">if</span> <span class="p">(!</span><span class="n">field</span><span class="p">.</span><span class="n">HasSimpleValue</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">   <span class="n">result</span> <span class="p">=</span> <span class="n">LinkToStruct</span><span class="p">(</span><span class="n">field</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">   <span class="k">return</span> <span class="kc">true</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>There’s another subtlety though. As we’ve seen in the layout, the <strong>Description</strong> struct, embedded inside of the <strong>Sample</strong> class, doesn’t have a method table of its own. The consequence is that we can’t find out its type by using <strong>ClrHeap.GetObjectType</strong>. As a workaround, we add a constructor allowing us to manually set the underlying ClrMD type of the object impersonated by the proxy:</p>
<p><strong>DynamicProxy.cs</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-csharp" data-lang="csharp"><span class="line"><span class="cl"><span class="kd">private</span> <span class="n">DynamicProxy</span><span class="p">(</span><span class="n">ClrHeap</span> <span class="n">heap</span><span class="p">,</span> <span class="kt">ulong</span> <span class="n">address</span><span class="p">,</span> <span class="n">ClrType</span> <span class="n">overrideType</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">:</span> <span class="k">this</span><span class="p">(</span><span class="n">heap</span><span class="p">,</span> <span class="n">address</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">   <span class="n">_type</span> <span class="p">=</span> <span class="n">overrideType</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>This constructor is called when we still have the type information (taken from the <strong>ClrField</strong>):</p>
<p><strong>DynamicProxy.cs</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-csharp" data-lang="csharp"><span class="line"><span class="cl"><span class="kd">private</span> <span class="n">DynamicProxy</span> <span class="n">LinkToStruct</span><span class="p">(</span><span class="n">ClrField</span> <span class="n">field</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">   <span class="kt">var</span> <span class="n">childAddress</span> <span class="p">=</span> <span class="n">_address</span> <span class="p">+</span> <span class="p">(</span><span class="kt">ulong</span><span class="p">)</span><span class="n">field</span><span class="p">.</span><span class="n">Offset</span> <span class="p">+</span> <span class="p">(</span><span class="kt">ulong</span><span class="p">)</span><span class="n">_heap</span><span class="p">.</span><span class="n">PointerSize</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">   <span class="k">return</span> <span class="k">new</span> <span class="n">DynamicProxy</span><span class="p">(</span><span class="n">_heap</span><span class="p">,</span> <span class="n">childAddress</span><span class="p">,</span> <span class="n">field</span><span class="p">.</span><span class="n">Type</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>Now we’re able to read the value of a field of a nested struct:</p>
<p><strong>Program.cs</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-csharp" data-lang="csharp"><span class="line"><span class="cl"><span class="n">Console</span><span class="p">.</span><span class="n">WriteLine</span><span class="p">(</span><span class="n">sample</span><span class="p">.</span><span class="n">Description</span><span class="p">.</span><span class="n">Id</span><span class="p">);</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>Are we done now? Almost. There is one last case to handle, the <strong>Size</strong> struct that is nested inside of <strong>Description</strong>, itself a struct nested inside of a <strong>Sample</strong> instance. How is that an issue? If we use the same code to compute the address of the <strong>Size</strong> struct, then we will be adding the 4/8 bytes for the method table. Except that, as we’ve seen, the nested <strong>Size</strong> struct doesn’t have a method table! We need to add a condition to the code to know whenever we are inside of a nested struct and handle this corner case:</p>
<p><strong>DynamicProxy.cs</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-csharp" data-lang="csharp"><span class="line"><span class="cl"><span class="kd">private</span> <span class="n">DynamicProxy</span> <span class="n">LinkToStruct</span><span class="p">(</span><span class="n">ClrField</span> <span class="n">field</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">   <span class="kt">var</span> <span class="n">childAddress</span> <span class="p">=</span> <span class="n">_address</span> <span class="p">+</span> <span class="p">(</span><span class="kt">ulong</span><span class="p">)</span><span class="n">field</span><span class="p">.</span><span class="n">Offset</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">   <span class="k">if</span> <span class="p">(!</span><span class="n">_interior</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">   <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="n">childAddress</span> <span class="p">+=</span> <span class="p">(</span><span class="kt">ulong</span><span class="p">)</span><span class="n">_heap</span><span class="p">.</span><span class="n">PointerSize</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">   <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">   <span class="k">return</span> <span class="k">new</span> <span class="n">DynamicProxy</span><span class="p">(</span><span class="n">_heap</span><span class="p">,</span> <span class="n">childAddress</span><span class="p">,</span> <span class="n">field</span><span class="p">.</span><span class="n">Type</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>The Boolean flag <strong>_interior</strong> is set in the second constructor that accepts a <strong>ClrType</strong>:</p>
<p><strong>DynamicProxy.cs</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-csharp" data-lang="csharp"><span class="line"><span class="cl"><span class="kd">private</span> <span class="n">DynamicProxy</span><span class="p">(</span><span class="n">ClrHeap</span> <span class="n">heap</span><span class="p">,</span> <span class="kt">ulong</span> <span class="n">address</span><span class="p">,</span> <span class="n">ClrType</span> <span class="n">overrideType</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">:</span> <span class="k">this</span><span class="p">(</span><span class="n">heap</span><span class="p">,</span> <span class="n">address</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">   <span class="n">_type</span> <span class="p">=</span> <span class="n">overrideType</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">   <span class="n">_interior</span> <span class="p">=</span> <span class="kc">true</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>We’re finally able to read the value of the nested-nested struct:</p>
<p><strong>Program.cs</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-csharp" data-lang="csharp"><span class="line"><span class="cl"><span class="n">Console</span><span class="p">.</span><span class="n">WriteLine</span><span class="p">(</span><span class="n">sample</span><span class="p">.</span><span class="n">Description</span><span class="p">.</span><span class="n">Size</span><span class="p">.</span><span class="n">Width</span> <span class="p">*</span> <span class="n">sample</span><span class="p">.</span><span class="n">Description</span><span class="p">.</span><span class="n">Size</span><span class="p">.</span><span class="n">Height</span><span class="p">);</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>Next time, we’ll see how to use the same mechanisms to manipulate arrays in a convenient way.</p>
<hr>
<p><em>Co-authored with <a href="https://twitter.com/KooKiz">Kevin Gosse</a></em></p>
]]></content:encoded></item><item><title>ClrMD Part 6 - Manipulate memory structures like real objects</title><link>https://chrisnas.github.io/posts/2017-08-01_clrmd-part-6-memory-structures/</link><pubDate>Tue, 01 Aug 2017 13:20:01 +0000</pubDate><guid>https://chrisnas.github.io/posts/2017-08-01_clrmd-part-6-memory-structures/</guid><description>This sixth post of the ClrMD series details how to make object fields navigation simple…</description><content:encoded><![CDATA[<p>This sixth post of the ClrMD series details how to make object fields navigation simple with C# like syntax thanks to the <strong>dynamic</strong> infrastructure. The associated code is part of the DynaMD library and is <a href="https://github.com/kevingosse/DynaMD">available on GitHub</a> and <a href="https://www.nuget.org/packages/DynaMD/">nuget</a>.</p>
<p>Part 1: <a href="/posts/2017-02-21_clrmd-part-1-going-beyond/">Bootstrap ClrMD to load a dump</a>.</p>
<p>Part 2: <a href="/posts/2017-03-24_clrmd-part-2-from-clrruntime/">Find duplicated strings with ClrMD heap traversing</a>.</p>
<p>Part 3: <a href="/posts/2017-05-03_clrmd-part-3-static-instance-fields/">List timers by following static fields links</a>.</p>
<p>Part 4: <a href="/posts/2017-05-31_clrmd-part-4-timer-callbacks/">Identify timers callback and other properties</a>.</p>
<p>Part 5: <a href="/posts/2017-06-29_clrmd-part-5-extend-sos-windbg/">Use ClrMD to extend SOS in WinDBG</a>.</p>
<p>As we’ve seen in the previous articles of the series, exploring a complex data structure using ClrMD can quickly become tedious.</p>
<p>Let’s take a concrete example. Imagine we have those types declared:</p>
<p><strong>Values.cs</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-csharp" data-lang="csharp"><span class="line"><span class="cl"><span class="kd">public</span> <span class="k">struct</span> <span class="nc">Size</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">   <span class="kd">public</span> <span class="kt">int</span> <span class="n">Width</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">   <span class="kd">public</span> <span class="kt">int</span> <span class="n">Height</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">public</span> <span class="k">struct</span> <span class="nc">Description</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">   <span class="kd">public</span> <span class="kt">int</span> <span class="n">Id</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">   <span class="kd">public</span> <span class="n">Size</span> <span class="n">Size</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">public</span> <span class="k">class</span> <span class="nc">Sample</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">   <span class="kd">public</span> <span class="kt">int</span> <span class="n">Value</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">   <span class="kd">public</span> <span class="kt">string</span> <span class="n">Name</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl">   <span class="kd">public</span> <span class="n">Description</span> <span class="n">Description</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">   <span class="kd">public</span> <span class="n">Sample</span> <span class="n">Child</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>Given the address of the <strong>Sample</strong> object in the memory dump, even with the <strong>GetFieldValue helper method</strong> to make it simpler, the code to navigate these recursive data types is still… verbose:</p>
<p><strong>Program.cs</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-csharp" data-lang="csharp"><span class="line"><span class="cl"><span class="n">Console</span><span class="p">.</span><span class="n">WriteLine</span><span class="p">((</span><span class="kt">uint</span><span class="p">)</span><span class="n">GetFieldValue</span><span class="p">(</span><span class="n">heap</span><span class="p">,</span> <span class="n">currentSampleRef</span><span class="p">,</span> <span class="s">&#34;Value&#34;</span><span class="p">));</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>And now, how to get the value of the <strong>Name</strong> property?</p>
<p>Same question for the inner <strong>Child</strong> fields or deeper <strong>Size</strong> field of its <strong>Description</strong>?</p>
<p>Wouldn’t that be great if we could navigate just like through real strongly typed instances? In short, to be able to write:</p>
<p><strong>Program.cs</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-csharp" data-lang="csharp"><span class="line"><span class="cl"><span class="kt">var</span> <span class="n">sample</span> <span class="p">=</span> <span class="n">heap</span><span class="p">.</span><span class="n">GetProxy</span><span class="p">(</span><span class="m">0x00001000</span><span class="p">);</span> <span class="c1">// Some address obtained by other ways</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">Console</span><span class="p">.</span><span class="n">WriteLine</span><span class="p">(</span><span class="n">sample</span><span class="p">.</span><span class="n">Value</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="n">Console</span><span class="p">.</span><span class="n">WriteLine</span><span class="p">(</span><span class="n">sample</span><span class="p">.</span><span class="n">Name</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="n">Console</span><span class="p">.</span><span class="n">WriteLine</span><span class="p">(</span><span class="n">sample</span><span class="p">.</span><span class="n">Child</span><span class="p">.</span><span class="n">Name</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="n">Console</span><span class="p">.</span><span class="n">WriteLine</span><span class="p">(</span><span class="n">sample</span><span class="p">.</span><span class="n">Description</span><span class="p">.</span><span class="n">Id</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="n">Console</span><span class="p">.</span><span class="n">WriteLine</span><span class="p">(</span><span class="n">sample</span><span class="p">.</span><span class="n">Description</span><span class="p">.</span><span class="n">Size</span><span class="p">.</span><span class="n">Width</span> <span class="p">*</span> <span class="n">sample</span><span class="p">.</span><span class="n">Description</span><span class="p">.</span><span class="n">Size</span><span class="p">.</span><span class="n">Height</span><span class="p">);</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>Instead of:</p>
<p><strong>Program.cs</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-csharp" data-lang="csharp"><span class="line"><span class="cl"><span class="n">Console</span><span class="p">.</span><span class="n">WriteLine</span><span class="p">(</span><span class="n">GetFieldValue</span><span class="p">(</span><span class="n">heap</span><span class="p">,</span> <span class="n">sampleRef</span><span class="p">,</span> <span class="s">&#34;Value&#34;</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"><span class="n">Console</span><span class="p">.</span><span class="n">WriteLine</span><span class="p">(</span><span class="n">GetFieldValue</span><span class="p">(</span><span class="n">heap</span><span class="p">,</span> <span class="n">sampleRef</span><span class="p">,</span> <span class="s">&#34;&lt;Name&gt;k__BackingField&#34;</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"><span class="n">Console</span><span class="p">.</span><span class="n">WriteLine</span><span class="p">(</span><span class="n">GetFieldValue</span><span class="p">(</span><span class="n">heap</span><span class="p">,</span> <span class="n">GetFieldValue</span><span class="p">(</span><span class="n">heap</span><span class="p">,</span> <span class="n">sampleRef</span><span class="p">,</span> <span class="s">&#34;Child&#34;</span><span class="p">),</span> <span class="s">&#34;Name&#34;</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"><span class="c1">// and so on...</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>The first issue is: what is the <strong>GetProxy</strong> method going to return? Since we don’t know at compilation time the properties of the object the code is going to manipulate, we need a way to support some kind of late-binding. Fortunately, this scenario is supported in C# through the usage of the <strong>dynamic</strong> keyword. As you will see in the rest of this post, this is not only a keyword but also an extensible mechanism that perfectly fits our need to define fields at runtime instead of compile time.</p>
<p>We start by creating a class inheriting from <strong>System.Dynamic.DynamicObject</strong>.</p>
<p><strong>DynamicProxy.cs</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-csharp" data-lang="csharp"><span class="line"><span class="cl"><span class="kd">internal</span> <span class="k">class</span> <span class="nc">DynamicProxy</span> <span class="p">:</span> <span class="n">DynamicObject</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>This base class provides all the facilities needed for late-binding:</p>
<p><img loading="lazy" src="/posts/2017-08-01_clrmd-part-6-memory-structures/clrmd.png"></p>
<p>As you will see, only a few of these virtual methods need to be overridden to support our scenario.</p>
<p>To construct our proxy, we need two parameters: the ClrMD <strong>ClrHeap</strong> object, that allows us to browse the objects in the memory, and the address of the object we want to impersonate.</p>
<p><strong>DynamicProxy.cs</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-csharp" data-lang="csharp"><span class="line"><span class="cl"><span class="kd">public</span> <span class="n">DynamicProxy</span><span class="p">(</span><span class="n">ClrHeap</span> <span class="n">heap</span><span class="p">,</span> <span class="kt">ulong</span> <span class="n">address</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">   <span class="n">_heap</span> <span class="p">=</span> <span class="n">heap</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">   <span class="n">_address</span> <span class="p">=</span> <span class="n">address</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>We also provide an extension method for convenience:</p>
<p><strong>Extensions.cs</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-csharp" data-lang="csharp"><span class="line"><span class="cl"><span class="k">namespace</span> <span class="nn">Microsoft.Diagnostics.Runtime</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">   <span class="kd">public</span> <span class="kd">static</span> <span class="k">class</span> <span class="nc">Extensions</span>
</span></span><span class="line"><span class="cl">   <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="kd">public</span> <span class="kd">static</span> <span class="kt">dynamic</span> <span class="n">GetProxy</span><span class="p">(</span><span class="k">this</span> <span class="n">ClrHeap</span> <span class="n">heap</span><span class="p">,</span> <span class="kt">ulong</span> <span class="n">address</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="p">{</span>
</span></span><span class="line"><span class="cl">         <span class="k">if</span> <span class="p">(</span><span class="n">address</span> <span class="p">==</span> <span class="m">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">         <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="kc">null</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">         <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">         <span class="k">return</span> <span class="k">new</span> <span class="n">DynamicProxy</span><span class="p">(</span><span class="n">heap</span><span class="p">,</span> <span class="n">address</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="cl">   <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>The next step is to override the virtual <strong>TryGetMember</strong> method, inherited from <strong>DynamicObject</strong>. It is automatically invoked whenever somebody tries to access a any member of the dynamic object, including its fields.</p>
<p><strong>DynamicProxy.cs</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-csharp" data-lang="csharp"><span class="line"><span class="cl"><span class="kd">public</span> <span class="kd">override</span> <span class="kt">bool</span> <span class="n">TryGetMember</span><span class="p">(</span><span class="n">GetMemberBinder</span> <span class="n">binder</span><span class="p">,</span> <span class="k">out</span> <span class="kt">object</span> <span class="n">result</span><span class="p">)</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>The <strong>Name</strong> property of the <strong>binder</strong> parameter provides the name of the accessed member and we are supposed to return the corresponding proxy object as the out <strong>result</strong> parameter.</p>
<p>We’re going to need the type of the object. For convenience, we store it in a property:</p>
<p><strong>DynamicProxy.cs</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-csharp" data-lang="csharp"><span class="line"><span class="cl"><span class="kd">protected</span> <span class="n">ClrType</span> <span class="n">Type</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">   <span class="k">get</span>
</span></span><span class="line"><span class="cl">   <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="k">if</span> <span class="p">(</span><span class="n">_type</span> <span class="p">==</span> <span class="kc">null</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="p">{</span>
</span></span><span class="line"><span class="cl">         <span class="n">_type</span> <span class="p">=</span> <span class="n">_heap</span><span class="p">.</span><span class="n">GetObjectType</span><span class="p">(</span><span class="n">_address</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">      <span class="k">return</span> <span class="n">_type</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">   <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>Using the binder.Name property containing the name of the field we’re trying to access, we retrieve the ClrMD field description:</p>
<p><strong>DynamicProxy.cs</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-csharp" data-lang="csharp"><span class="line"><span class="cl"><span class="kt">var</span> <span class="n">field</span> <span class="p">=</span> <span class="n">Type</span><span class="p">.</span><span class="n">GetFieldByName</span><span class="p">(</span><span class="n">binder</span><span class="p">.</span><span class="n">Name</span><span class="p">);</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>From there, we get the value marshalled by ClrMD and assign it to the <strong>result</strong> out parameter:</p>
<p><strong>DynamicProxy.cs</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-csharp" data-lang="csharp"><span class="line"><span class="cl"><span class="n">result</span> <span class="p">=</span> <span class="n">field</span><span class="p">.</span><span class="n">GetValue</span><span class="p">(</span><span class="n">_address</span><span class="p">);</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>Finally, we signal that we managed to bind the invoked member:</p>
<p><strong>DynamicProxy.cs</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-csharp" data-lang="csharp"><span class="line"><span class="cl"><span class="k">return</span> <span class="kc">true</span><span class="p">;</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>This is just a handful of lines of code, but it’s enough for the simple cases where field values are primitive types.. This covers the “Value” field for our Sample type. For the auto-property “Name”, that’s trickier, because the name of the underlying field has characters that are forbidden in C#: “<Name>k__BackingField”. If we write this, it won’t compile:</p>
<p><strong>Program.cs</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-csharp" data-lang="csharp"><span class="line"><span class="cl"><span class="n">Console</span><span class="p">.</span><span class="n">WriteLine</span><span class="p">(</span><span class="n">proxy</span><span class="p">.&lt;</span><span class="n">Name</span><span class="p">&gt;</span><span class="n">k__BackingField</span><span class="p">);</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>We can handle this case by guessing the name of the compiler-generated field, then accessing it:</p>
<p><strong>DynamicProxy.cs</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-csharp" data-lang="csharp"><span class="line"><span class="cl"><span class="kt">var</span> <span class="n">field</span> <span class="p">=</span> <span class="n">Type</span><span class="p">.</span><span class="n">GetFieldByName</span><span class="p">(</span><span class="n">binder</span><span class="p">.</span><span class="n">Name</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="p">(</span><span class="n">field</span> <span class="p">==</span> <span class="kc">null</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">   <span class="c1">// The field wasn&#39;t found, it could be an autoproperty</span>
</span></span><span class="line"><span class="cl">   <span class="n">field</span> <span class="p">=</span> <span class="n">Type</span><span class="p">.</span><span class="n">GetFieldByName</span><span class="p">(</span><span class="s">$&#34;&lt;{binder.Name}&gt;k__BackingField&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">   <span class="k">if</span> <span class="p">(</span><span class="n">field</span> <span class="p">==</span> <span class="kc">null</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">   <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="c1">// Still not found</span>
</span></span><span class="line"><span class="cl">      <span class="k">throw</span> <span class="k">new</span> <span class="n">InvalidOperationException</span><span class="p">(</span><span class="s">&#34;Field not found: &#34;</span> <span class="p">+</span> <span class="n">binder</span><span class="p">.</span><span class="n">Name</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">   <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>Thanks to this trick, we can write:</p>
<p><strong>Program.cs</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-csharp" data-lang="csharp"><span class="line"><span class="cl"><span class="n">Console</span><span class="p">.</span><span class="n">WriteLine</span><span class="p">(</span><span class="n">proxy</span><span class="p">.</span><span class="n">Name</span><span class="p">);</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>Great! The next challenge is to transparently manipulate the “Child” field as a reference to another “Sample” object. To achieve this goal, the field could simply return another <strong>DynamicProxy</strong> object that we can manipulate the same way as its parent.</p>
<p>First, we need a helper to find out whether a value is a reference or not:</p>
<p><strong>DynamicProxy.cs</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-csharp" data-lang="csharp"><span class="line"><span class="cl"><span class="kd">private</span> <span class="kd">static</span> <span class="kt">bool</span> <span class="n">IsReference</span><span class="p">(</span><span class="kt">object</span> <span class="n">result</span><span class="p">,</span> <span class="n">ClrType</span> <span class="n">type</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">   <span class="k">return</span> <span class="p">!(</span><span class="n">result</span> <span class="k">is</span> <span class="kt">string</span><span class="p">)</span> <span class="p">&amp;&amp;</span> <span class="n">type</span><span class="p">.</span><span class="n">IsObjectReference</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>We treat string as a special case, because ClrMD gives us the marshaled string rather than a reference like for all other types. That’s how we were able to retrieve the value of the <strong>Name</strong> field previously.</p>
<p>Now we call the helper and return a new proxy whenever we’re dealing with a reference:</p>
<p><strong>DynamicProxy.cs</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-csharp" data-lang="csharp"><span class="line"><span class="cl"><span class="k">if</span> <span class="p">(</span><span class="n">IsReference</span><span class="p">(</span><span class="n">result</span><span class="p">,</span> <span class="n">field</span><span class="p">.</span><span class="n">Type</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">   <span class="n">result</span> <span class="p">=</span> <span class="k">new</span> <span class="n">DynamicProxy</span><span class="p">(</span><span class="n">_heap</span><span class="p">,</span> <span class="p">(</span><span class="kt">ulong</span><span class="p">)</span><span class="n">result</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>We can now write:</p>
<p><strong>Program.cs</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-csharp" data-lang="csharp"><span class="line"><span class="cl"><span class="n">Console</span><span class="p">.</span><span class="n">WriteLine</span><span class="p">(</span><span class="n">proxy</span><span class="p">.</span><span class="n">Child</span><span class="p">.</span><span class="n">Name</span><span class="p">);</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>That’s it for accessing a referenced object allocated on the heap. However, this won’t work for accessing an embedded struct such as <strong>proxy.Description.Id</strong>. We’ll see in the next part how to handle this specific case.</p>
<hr>
<p><em>Co-authored with <a href="https://twitter.com/kookiz">Kevin Gosse</a></em></p>
]]></content:encoded></item><item><title>ClrMD Part 5 – How to use ClrMD to extend SOS in WinDBG</title><link>https://chrisnas.github.io/posts/2017-06-29_clrmd-part-5-extend-sos-windbg/</link><pubDate>Thu, 29 Jun 2017 15:04:00 +0000</pubDate><guid>https://chrisnas.github.io/posts/2017-06-29_clrmd-part-5-extend-sos-windbg/</guid><description>This fifth post of the ClrMD series shows how to leverage this API inside a WinDBG…</description><content:encoded><![CDATA[<p>This fifth post of the ClrMD series shows how to leverage this API inside a WinDBG extension. The <a href="https://github.com/criteo/criteo-dotnet-blog/tree/master/ClrMD-Part5_WinDBG-Extension">associated code</a> allows you to translate a task state into a human readable value.</p>
<p>Part 1: <a href="/posts/2017-02-21_clrmd-part-1-going-beyond/">Bootstrap ClrMD to load a dump</a>.</p>
<p>Part 2: <a href="/posts/2017-03-24_clrmd-part-2-from-clrruntime/">Find duplicated strings with ClrMD heap traversing</a>.</p>
<p>Part 3: <a href="/posts/2017-05-03_clrmd-part-3-static-instance-fields/">List timers by following static fields links</a>.</p>
<p>Part 4: <a href="/posts/2017-05-31_clrmd-part-4-timer-callbacks/">Identify timers callback and other properties</a>.</p>
<h3 id="introduction">Introduction</h3>
<p>Since the beginning of this series, you have seen how to use ClrMD to write your own tool to extract meaningful information from a dump file (or a live process). However, most of the time, you are also using WinDBG and SOS to navigate inside the .NET data structures.</p>
<p>It would be convenient if you could leverage the new .NET exploration features based on ClrMD the same way you are using SOS. This post will explain how to achieve this goal by implementing an extension that exports commands callable from within WinDBG.</p>
<h3 id="deciphering-a-task-status">Deciphering a Task status</h3>
<p>During one of our debugging investigations, we needed to get the value of the <strong>Status</strong> property for a few <strong>Task</strong> instances. If you take a look at the implementation of the property getter in a decompiler (or from <a href="https://referencesource.microsoft.com/#mscorlib/system/threading/Tasks/Task.cs">source code</a>), you will see that it is computed based on the value of the internal <strong>m_stateFlags</strong> field.</p>
<p>In WinDBG, the <strong>!DumpHeap -stat</strong> command lists all types with their instance count. If the <strong>.prefer_dml 1</strong> command has been set, you even get hyperlinks on some values such as the address or MT (for MethodTable). If you click the MT value for <strong>System.Threading.Tasks.Task</strong>, you get all instances of type <strong>Task</strong>:</p>
<p><img loading="lazy" src="/posts/2017-06-29_clrmd-part-5-extend-sos-windbg/TasksAddresses.png"></p>
<p>Click any address and look at the value of the <strong>m_stateFlags</strong> field:</p>
<p><img loading="lazy" src="/posts/2017-06-29_clrmd-part-5-extend-sos-windbg/TaskStateFlags.png"></p>
<p>It is easy to automate the retrieval of the <strong>m_stateFlags</strong> instance field value with ClrMD as explained <a href="/posts/2017-05-03_clrmd-part-3-static-instance-fields/">earlier</a>:</p>
<p><strong>GetTaskStateFromAddress.cs</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-csharp" data-lang="csharp"><span class="line"><span class="cl"><span class="kd">private</span> <span class="kd">static</span> <span class="kt">ulong</span> <span class="n">GetTaskStateFromAddress</span><span class="p">(</span><span class="kt">ulong</span> <span class="n">address</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kt">var</span> <span class="n">type</span> <span class="p">=</span> <span class="n">Runtime</span><span class="p">.</span><span class="n">GetHeap</span><span class="p">().</span><span class="n">GetObjectType</span><span class="p">(</span><span class="n">address</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">((</span><span class="n">type</span> <span class="p">!=</span> <span class="kc">null</span><span class="p">)</span> <span class="p">&amp;&amp;</span> <span class="p">(</span><span class="n">type</span><span class="p">.</span><span class="n">Name</span><span class="p">.</span><span class="n">StartsWith</span><span class="p">(</span><span class="s">&#34;System.Threading.Task&#34;</span><span class="p">)))</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// try to get the m_stateFlags field value</span>
</span></span><span class="line"><span class="cl">        <span class="n">ClrInstanceField</span> <span class="n">field</span> <span class="p">=</span> <span class="n">type</span><span class="p">.</span><span class="n">GetFieldByName</span><span class="p">(</span><span class="s">&#34;m_stateFlags&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="n">field</span> <span class="p">!=</span> <span class="kc">null</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="kt">var</span> <span class="n">val</span> <span class="p">=</span> <span class="n">field</span><span class="p">.</span><span class="n">GetValue</span><span class="p">(</span><span class="n">address</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">            <span class="k">if</span> <span class="p">(</span><span class="n">val</span> <span class="p">!=</span> <span class="kc">null</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="k">try</span>
</span></span><span class="line"><span class="cl">                <span class="p">{</span>
</span></span><span class="line"><span class="cl">                    <span class="k">return</span> <span class="p">(</span><span class="kt">ulong</span><span class="p">)(</span><span class="kt">int</span><span class="p">)</span><span class="n">val</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">                <span class="p">}</span>
</span></span><span class="line"><span class="cl">                <span class="k">catch</span> <span class="p">(</span><span class="n">InvalidCastException</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">                <span class="p">{</span>
</span></span><span class="line"><span class="cl">                <span class="p">}</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="m">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>The <strong>ClrType</strong> corresponding to the address is first checked to ensure that it represents a <strong>Task</strong> instance. Next, its <strong>GetFieldByname</strong> helper method returns a <strong>ClrInstanceField</strong> that provides the status via its <strong>GetValue</strong> function.</p>
<p>The next step is to transform this number into a <strong>TaskStatus</strong> enumeration value by simply using a decompiler and copying the logic from the <strong>Task</strong> getter code:</p>
<p><strong>GetTaskState.cs</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-csharp" data-lang="csharp"><span class="line"><span class="cl"><span class="kd">private</span> <span class="kd">static</span> <span class="kt">string</span> <span class="n">GetTaskState</span><span class="p">(</span><span class="kt">ulong</span> <span class="n">flag</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">TaskStatus</span> <span class="n">rval</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">((</span><span class="n">flag</span> <span class="p">&amp;</span> <span class="n">TASK_STATE_FAULTED</span><span class="p">)</span> <span class="p">!=</span> <span class="m">0</span><span class="p">)</span> <span class="n">rval</span> <span class="p">=</span> <span class="n">TaskStatus</span><span class="p">.</span><span class="n">Faulted</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">else</span> <span class="k">if</span> <span class="p">((</span><span class="n">flag</span> <span class="p">&amp;</span> <span class="n">TASK_STATE_CANCELED</span><span class="p">)</span> <span class="p">!=</span> <span class="m">0</span><span class="p">)</span> <span class="n">rval</span> <span class="p">=</span> <span class="n">TaskStatus</span><span class="p">.</span><span class="n">Canceled</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">else</span> <span class="k">if</span> <span class="p">((</span><span class="n">flag</span> <span class="p">&amp;</span> <span class="n">TASK_STATE_RAN_TO_COMPLETION</span><span class="p">)</span> <span class="p">!=</span> <span class="m">0</span><span class="p">)</span> <span class="n">rval</span> <span class="p">=</span> <span class="n">TaskStatus</span><span class="p">.</span><span class="n">RanToCompletion</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">else</span> <span class="k">if</span> <span class="p">((</span><span class="n">flag</span> <span class="p">&amp;</span> <span class="n">TASK_STATE_WAITING_ON_CHILDREN</span><span class="p">)</span> <span class="p">!=</span> <span class="m">0</span><span class="p">)</span> <span class="n">rval</span> <span class="p">=</span> <span class="n">TaskStatus</span><span class="p">.</span><span class="n">WaitingForChildrenToComplete</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">else</span> <span class="k">if</span> <span class="p">((</span><span class="n">flag</span> <span class="p">&amp;</span> <span class="n">TASK_STATE_DELEGATE_INVOKED</span><span class="p">)</span> <span class="p">!=</span> <span class="m">0</span><span class="p">)</span> <span class="n">rval</span> <span class="p">=</span> <span class="n">TaskStatus</span><span class="p">.</span><span class="n">Running</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">else</span> <span class="k">if</span> <span class="p">((</span><span class="n">flag</span> <span class="p">&amp;</span> <span class="n">TASK_STATE_STARTED</span><span class="p">)</span> <span class="p">!=</span> <span class="m">0</span><span class="p">)</span> <span class="n">rval</span> <span class="p">=</span> <span class="n">TaskStatus</span><span class="p">.</span><span class="n">WaitingToRun</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">else</span> <span class="k">if</span> <span class="p">((</span><span class="n">flag</span> <span class="p">&amp;</span> <span class="n">TASK_STATE_WAITINGFORACTIVATION</span><span class="p">)</span> <span class="p">!=</span> <span class="m">0</span><span class="p">)</span> <span class="n">rval</span> <span class="p">=</span> <span class="n">TaskStatus</span><span class="p">.</span><span class="n">WaitingForActivation</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">flag</span> <span class="p">==</span> <span class="m">0</span><span class="p">)</span> <span class="n">rval</span> <span class="p">=</span> <span class="n">TaskStatus</span><span class="p">.</span><span class="n">Created</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="k">else</span> <span class="k">return</span> <span class="kc">null</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">rval</span><span class="p">.</span><span class="n">ToString</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>It would be a time saver if this translation could be done by a command right inside WinDBG instead of relying on another tool based on ClrMD in which addresses are pasted.</p>
<h3 id="windbg-extension-101">WinDBG extension 101</h3>
<p>In addition of being a native Windows debugger, WinDBG supports extensions: .dll files that you load with the <strong>.load</strong> command. They are exporting commands that are callable from within WinDBG with the “<strong>!</strong>” prefix. These commands are usual native exports that can be seen with tools such as <a href="http://www.dependencywalker.com/">http://www.dependencywalker.com/</a> as shown by the next screenshot:</p>
<p><img loading="lazy" src="/posts/2017-06-29_clrmd-part-5-extend-sos-windbg/DWwithSOS.png"></p>
<p>As you can see, all SOS commands are functions exported by the sos.dll native binary. Before digging into the extension functions implementation, notice that a few other functions could also be exported. Among them, the <strong>DebugExtensionInitialize</strong> function provides version information (i.e. which version of the debugging API is expected) and must be exported to be called by WinDBG when the dll is loaded.</p>
<p>Read <a href="https://blogs.msdn.microsoft.com/sgajjela/2013/03/02/how-to-develop-windbg-extension-dll">this post</a> for more details about how to develop a native WinDBG extension.</p>
<p>All extension command functions take two parameters:</p>
<ul>
<li><strong>An IDebugClient</strong> instance to interact with WinDBG</li>
<li>An ANSI string for the arguments (such as “<em>-stat</em>” for !<em>dumpheap</em>)</li>
</ul>
<p>The bridge between your extension commands and WinDBG is provided by the <strong>IDebugClient</strong> COM interface. But don’t be scared: no need to manually deal with native COM interface with ClrMD! The <strong>DataTarget</strong>**.**<strong>CreateFromDebuggerInterface</strong> method takes an <strong>IDebugClient</strong> interface and returns an instance of <strong>DataTarget</strong>. As you might remember from <a href="/posts/2017-02-21_clrmd-part-1-going-beyond/">the initial post of this series</a>, <strong>DataTarget</strong> is the gateway to the dump (or live-debugged attached process): we are now back to the known ClrMD world.</p>
<h3 id="reuse-clrmd-samples">Reuse ClrMD Samples</h3>
<p>Hopefully, most of the glue to bind the native world to ClrMD is already available! You simply reuse the partial <strong>DebuggerExtensions</strong> class given <a href="https://github.com/Microsoft/clrmd/tree/master/src/Samples/WindbgExtension">in the samples</a>.</p>
<p>You extend the class with your extension methods that take the following signature:</p>
<p><strong>MyCommandSignature.cs</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-csharp" data-lang="csharp"><span class="line"><span class="cl"><span class="kd">public</span> <span class="kd">static</span> <span class="k">void</span> <span class="n">MyCommand</span><span class="p">(</span><span class="n">IntPtr</span> <span class="n">client</span><span class="p">,</span> <span class="p">[</span><span class="n">MarshalAs</span><span class="p">(</span><span class="n">UnmanagedType</span><span class="p">.</span><span class="n">LPStr</span><span class="p">)]</span> <span class="kt">string</span> <span class="n">args</span><span class="p">)</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>The first parameter is a pointer to the <strong>IDebugClient</strong> interface provided by WinDBG. The first thing to do in your extension command method is to call the <strong>InitApi</strong> static method with the interface pointer and let the magic happens.</p>
<p><strong>MyCommand-2.cs</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-csharp" data-lang="csharp"><span class="line"><span class="cl"><span class="c1">// Must be the first thing in our extension.</span>
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="p">(!</span><span class="n">InitApi</span><span class="p">(</span><span class="n">client</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span><span class="p">;</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>After that call, the output of the Console will be redirected to WinDBG and your code is free to use the following properties to access the dump via ClrMD:</p>
<p><strong>DebuggerExtensionPartial.cs</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-csharp" data-lang="csharp"><span class="line"><span class="cl"><span class="kd">public</span> <span class="kd">partial</span> <span class="k">class</span> <span class="nc">DebuggerExtensions</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kd">public</span> <span class="kd">static</span> <span class="n">IDebugClient</span> <span class="n">DebugClient</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="kd">private</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="kd">public</span> <span class="kd">static</span> <span class="n">DataTarget</span> <span class="n">DataTarget</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="kd">private</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="kd">public</span> <span class="kd">static</span> <span class="n">ClrRuntime</span> <span class="n">Runtime</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="kd">private</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>The second parameter <em>args</em> received by your method is a string that contains the parameters added by the user after the name of your command. For example, if the user types “MyCommand param1 param2”, the <em>args</em> parameter will be “param1 param2”.</p>
<h3 id="exposing-native-functions">Exposing native functions</h3>
<p>The last part of magic glue is how to export a native function from a .NET assembly. This is made possible by the UnmanagedExports nuget package by Robert Giesecke.</p>
<p><img loading="lazy" src="/posts/2017-06-29_clrmd-part-5-extend-sos-windbg/ExportNuGet.png"></p>
<p>Once added to your project, decorate the functions to export with the <strong>DllExport</strong> attribute and the native name of the function that will be visible in WinDBG as a command.</p>
<p>There is a little trick here: the names of exported functions are case sensitive for WinDBG. If you take a look again at sos.dll in Dependency Walker and sort exports by Function column, you will notice a few duplicates such as <em>CLRStack</em>/ <em>ClrStack</em>/ <em>clrstack</em> as shown in the following screenshot:</p>
<p><img loading="lazy" src="/posts/2017-06-29_clrmd-part-5-extend-sos-windbg/MultipleExportsSOS.png"></p>
<p>For usability sake, it is a good practice to provide several syntaxes for the same command, including short version such as !<em>dso</em> for <em>!DumpStackObject</em>in SOS. Unfortunately the <strong>DllExport</strong> attribute does not allow multiple applications on the same method with different exported names. You need to define a different method per exported name and all of them will call the same internal helper method.</p>
<p><strong>MultipleDllExport.cs</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-csharp" data-lang="csharp"><span class="line"><span class="cl"><span class="na">[DllExport(&#34;tks&#34;)]</span>
</span></span><span class="line"><span class="cl"><span class="kd">public</span> <span class="kd">static</span> <span class="k">void</span> <span class="n">tks</span><span class="p">(</span><span class="n">IntPtr</span> <span class="n">client</span><span class="p">,</span> <span class="p">[</span><span class="n">MarshalAs</span><span class="p">(</span><span class="n">UnmanagedType</span><span class="p">.</span><span class="n">LPStr</span><span class="p">)]</span> <span class="kt">string</span> <span class="n">args</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">OnTkState</span><span class="p">(</span><span class="n">client</span><span class="p">,</span> <span class="n">args</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="na">
</span></span></span><span class="line"><span class="cl"><span class="na">[DllExport(&#34;tkstate&#34;)]</span>
</span></span><span class="line"><span class="cl"><span class="kd">public</span> <span class="kd">static</span> <span class="k">void</span> <span class="n">tkstate</span><span class="p">(</span><span class="n">IntPtr</span> <span class="n">client</span><span class="p">,</span> <span class="p">[</span><span class="n">MarshalAs</span><span class="p">(</span><span class="n">UnmanagedType</span><span class="p">.</span><span class="n">LPStr</span><span class="p">)]</span> <span class="kt">string</span> <span class="n">args</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">OnTkState</span> <span class="p">(</span><span class="n">client</span><span class="p">,</span> <span class="n">args</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="na">
</span></span></span><span class="line"><span class="cl"><span class="na">[DllExport(&#34;tkState&#34;)]</span>
</span></span><span class="line"><span class="cl"><span class="kd">public</span> <span class="kd">static</span> <span class="k">void</span> <span class="n">tkState</span><span class="p">(</span><span class="n">IntPtr</span> <span class="n">client</span><span class="p">,</span> <span class="p">[</span><span class="n">MarshalAs</span><span class="p">(</span><span class="n">UnmanagedType</span><span class="p">.</span><span class="n">LPStr</span><span class="p">)]</span> <span class="kt">string</span> <span class="n">args</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="n">OnTkState</span> <span class="p">(</span><span class="n">client</span><span class="p">,</span> <span class="n">args</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">public</span> <span class="kd">static</span> <span class="k">void</span> <span class="n">OnTkState</span> <span class="p">(</span><span class="n">IntPtr</span> <span class="n">client</span><span class="p">,</span> <span class="p">[</span><span class="n">MarshalAs</span><span class="p">(</span><span class="n">UnmanagedType</span><span class="p">.</span><span class="n">LPStr</span><span class="p">)]</span> <span class="kt">string</span> <span class="n">args</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// Must be the first thing in our extension.</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(!</span><span class="n">InitApi</span><span class="p">(</span><span class="n">client</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="p">...</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>Thanks to the <strong>GetTaskStateFromAddress</strong> and <strong>GetTaskState</strong> helper methods described earlier, the implementation of the <strong>OnTkState</strong> method is straightforward once the address or the value has been extracted from the <strong>args</strong> parameter.</p>
<h3 id="dont-forget-your-user-implement-help">Don’t forget your user: implement help</h3>
<p>A good extension always provides an help command that (1) lists the available commands with shortcuts and (2) additional details on each command. Simply add a new file that defines the exports for help/Help and parses the string argument if needed.</p>
<p><strong>DebuggerExtensionImpl.cs</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span><span class="lnt">33
</span><span class="lnt">34
</span><span class="lnt">35
</span><span class="lnt">36
</span><span class="lnt">37
</span><span class="lnt">38
</span><span class="lnt">39
</span><span class="lnt">40
</span><span class="lnt">41
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-csharp" data-lang="csharp"><span class="line"><span class="cl"><span class="kd">public</span> <span class="kd">partial</span> <span class="k">class</span> <span class="nc">DebuggerExtensions</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="na">    [DllExport(&#34;Help&#34;)]</span>
</span></span><span class="line"><span class="cl">    <span class="kd">public</span> <span class="kd">static</span> <span class="k">void</span> <span class="n">Help</span><span class="p">(</span><span class="n">IntPtr</span> <span class="n">client</span><span class="p">,</span> <span class="p">[</span><span class="n">MarshalAs</span><span class="p">(</span><span class="n">UnmanagedType</span><span class="p">.</span><span class="n">LPStr</span><span class="p">)]</span> <span class="kt">string</span> <span class="n">args</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">OnHelp</span><span class="p">(</span><span class="n">client</span><span class="p">,</span> <span class="n">args</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="na">
</span></span></span><span class="line"><span class="cl"><span class="na">   [DllExport(&#34;help&#34;)]</span>
</span></span><span class="line"><span class="cl">   <span class="kd">public</span> <span class="kd">static</span> <span class="k">void</span> <span class="n">help</span><span class="p">(</span><span class="n">IntPtr</span> <span class="n">client</span><span class="p">,</span> <span class="p">[</span><span class="n">MarshalAs</span><span class="p">(</span><span class="n">UnmanagedType</span><span class="p">.</span><span class="n">LPStr</span><span class="p">)]</span> <span class="kt">string</span> <span class="n">args</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">   <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">OnHelp</span><span class="p">(</span><span class="n">client</span><span class="p">,</span> <span class="n">args</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">   <span class="p">}</span>
</span></span><span class="line"><span class="cl"> 
</span></span><span class="line"><span class="cl">    <span class="kd">const</span> <span class="kt">string</span> <span class="n">_help</span> <span class="p">=</span> <span class="s">&#34;...&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">    <span class="kd">const</span> <span class="kt">string</span> <span class="n">_tksHelp</span> <span class="p">=</span> <span class="s">&#34;...&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="kd">private</span> <span class="kd">static</span> <span class="k">void</span> <span class="n">OnHelp</span><span class="p">(</span><span class="n">IntPtr</span> <span class="n">client</span><span class="p">,</span> <span class="kt">string</span> <span class="n">args</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="c1">// Must be the first thing in our extension.</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(!</span><span class="n">InitApi</span><span class="p">(</span><span class="n">client</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="kt">string</span> <span class="n">command</span> <span class="p">=</span> <span class="n">args</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="n">args</span> <span class="p">!=</span> <span class="kc">null</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="n">command</span> <span class="p">=</span> <span class="n">args</span><span class="p">.</span><span class="n">ToLower</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">        <span class="k">switch</span> <span class="p">(</span><span class="n">command</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="k">case</span> <span class="s">&#34;tks&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">            <span class="k">case</span> <span class="s">&#34;tkstate&#34;</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">                <span class="n">Console</span><span class="p">.</span><span class="n">WriteLine</span><span class="p">(</span><span class="n">_tksHelp</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">            <span class="k">break</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> 
</span></span><span class="line"><span class="cl">            <span class="k">default</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">                <span class="n">Console</span><span class="p">.</span><span class="n">WriteLine</span><span class="p">(</span><span class="n">_help</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">            <span class="k">break</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">        <span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="tips-to-use-the-extension">Tips to use the extension</h3>
<p>Don’t forget that you might need two versions of your assembly: one for the x86 version of WinDBG if your applications are 32 bit and one for the x64 version of WinDBG in the 64 bit case. If you want to be able to easily load your extension with the .load <myextension> command, copy it with Microsoft.Diagnostics.Runtime.dll (i.e. ClrMD assembly) to the winext subfolder of x64/x86 WinDBG folders:</p>
<p><img loading="lazy" src="/posts/2017-06-29_clrmd-part-5-extend-sos-windbg/WinDbgFolders.png"></p>
<p>Before being able to use any of its commands, you must load SOS with the well-known <strong>.loadby sos clr</strong> mantra. But this is not enough: you also have to run at least one SOS command. You are now ready to call any of your extension commands!</p>
<h3 id="next-step">Next step…</h3>
<p>The next episodes will bring you into the mysteries under the <strong>dynamic</strong> keyword and how to simplify the syntax to leverage ClrMD.</p>
<hr>
<p><em>Co-authored with <a href="https://twitter.com/KooKiz">Kevin Gosse</a></em></p>
]]></content:encoded></item><item><title>ClrMD Part 4 – What callbacks are called by my timers?</title><link>https://chrisnas.github.io/posts/2017-05-31_clrmd-part-4-timer-callbacks/</link><pubDate>Wed, 31 May 2017 18:13:58 +0000</pubDate><guid>https://chrisnas.github.io/posts/2017-05-31_clrmd-part-4-timer-callbacks/</guid><description>This fourth post of the ClrMD series digs into the details of figuring out which…</description><content:encoded><![CDATA[<p>This fourth post of the ClrMD series digs into the details of figuring out which method gets called when a timer triggers. The <a href="https://github.com/criteo/criteo-dotnet-blog/tree/master/ClrMD-Parts3%2B4_Timers">associated code</a> lists all timers in a dump.</p>
<p>Part 1: <a href="/posts/2017-02-21_clrmd-part-1-going-beyond/">Bootstrapping ClrMD to load a dump</a>.</p>
<p>Part 2: <a href="/posts/2017-03-24_clrmd-part-2-from-clrruntime/">Finding duplicated strings with ClrMD heap traversing</a>.</p>
<p>Part 3: <a href="/posts/2017-05-03_clrmd-part-3-static-instance-fields/">List timers by following static fields links</a>.</p>
<h3 id="looking-at-my-timer">Looking at my timer</h3>
<p>In the previous post, we explained how to access a static field of <strong>TimerQueue</strong> to start iterating the list of <strong>TimerQueueTimer</strong> wrapping the created timers. Now that the <strong>currentPointer</strong> variable contains the address of each <strong>TimerQueueTimer</strong>, it is time to extract the details of the timer we have created.</p>
<p><img loading="lazy" src="/posts/2017-05-31_clrmd-part-4-timer-callbacks/TimerQueueTimerClass.png"></p>
<p>The following code extracts the value of the <strong>TimerQueueTimer</strong> fields corresponding to each Timer thanks to the GetFieldValue helper <a href="/posts/2017-05-03_clrmd-part-3-static-instance-fields/">presented in the previous post</a>:</p>
<p><strong>TimerQueueTimerFields.cs</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-csharp" data-lang="csharp"><span class="line"><span class="cl"><span class="kt">var</span> <span class="n">val</span> <span class="p">=</span> <span class="n">GetFieldValue</span><span class="p">(</span><span class="n">heap</span><span class="p">,</span> <span class="n">currentTimerQueueTimerRef</span><span class="p">,</span> <span class="s">&#34;m_dueTime&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="n">ti</span><span class="p">.</span><span class="n">DueTime</span> <span class="p">=</span> <span class="p">(</span><span class="kt">uint</span><span class="p">)</span><span class="n">val</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">val</span> <span class="p">=</span> <span class="n">GetFieldValue</span><span class="p">(</span><span class="n">heap</span><span class="p">,</span> <span class="n">currentTimerQueueTimerRef</span><span class="p">,</span> <span class="s">&#34;m_period&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="n">ti</span><span class="p">.</span><span class="n">Period</span> <span class="p">=</span> <span class="p">(</span><span class="kt">uint</span><span class="p">)</span><span class="n">val</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">val</span> <span class="p">=</span> <span class="n">GetFieldValue</span><span class="p">(</span><span class="n">heap</span><span class="p">,</span> <span class="n">currentTimerQueueTimerRef</span><span class="p">,</span> <span class="s">&#34;m_canceled&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="n">ti</span><span class="p">.</span><span class="n">Cancelled</span> <span class="p">=</span> <span class="p">(</span><span class="kt">bool</span><span class="p">)</span><span class="n">val</span><span class="p">;</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>Note that the value for <strong>m_dueTime</strong> is always the same as the value of <strong>m_period</strong>. This is not a bug but it seems that .NET is only keeping the due time during construction but use the corresponding field for other purpose after.</p>
<p>The <strong>m_state</strong> field case is a little bit more complicated to decipher because the type of the object passed to the timer needs to be figured out in addition to its address, if the latter is not null:</p>
<p><strong>TimerQueueTimerState.cs</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-csharp" data-lang="csharp"><span class="line"><span class="cl"><span class="n">val</span> <span class="p">=</span> <span class="n">GetFieldValue</span><span class="p">(</span><span class="n">heap</span><span class="p">,</span> <span class="n">currentTimerQueueTimerRef</span><span class="p">,</span> <span class="s">&#34;m_state&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="n">ti</span><span class="p">.</span><span class="n">StateTypeName</span> <span class="p">=</span> <span class="s">&#34;&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="p">(</span><span class="n">val</span> <span class="p">==</span> <span class="kc">null</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">   <span class="n">ti</span><span class="p">.</span><span class="n">StateAddress</span> <span class="p">=</span> <span class="m">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="k">else</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">   <span class="n">ti</span><span class="p">.</span><span class="n">StateAddress</span> <span class="p">=</span> <span class="p">(</span><span class="kt">ulong</span><span class="p">)</span><span class="n">val</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">   <span class="kt">var</span> <span class="n">stateType</span> <span class="p">=</span> <span class="n">heap</span><span class="p">.</span><span class="n">GetObjectType</span><span class="p">(</span><span class="n">ti</span><span class="p">.</span><span class="n">StateAddress</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">   <span class="k">if</span> <span class="p">(</span><span class="n">stateType</span> <span class="p">!=</span> <span class="kc">null</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">   <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="n">ti</span><span class="p">.</span><span class="n">StateTypeName</span> <span class="p">=</span> <span class="n">stateType</span><span class="p">.</span><span class="n">Name</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">   <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>As usual with ClrMD, you need to get the <strong>ClrType</strong> corresponding to the object referenced by an address before being able to access its fields or to get its name. However, instead of looking into a module as it has been done for <strong>TimerQueue</strong>, it is easier and more efficient to call the <strong>GetObjectType</strong> from <strong>ClrHeap</strong>. Remember that the mandatory test against a null value for the <strong>ClrType</strong> might seem overkill but the ClrMD implementation states that it is possible that the internal CLR state could be corrupted.</p>
<h3 id="what-is-the-timer-callback">What is the timer callback?</h3>
<p>The last piece of information to retrieve is the callback the timer will call when it triggers. The <strong>_timerCallback</strong> field references a <strong>TimerCallback</strong> instance that stores these details.</p>
<p><strong>GetTimerCallBackDetails.cs</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span><span class="lnt">31
</span><span class="lnt">32
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-csharp" data-lang="csharp"><span class="line"><span class="cl"><span class="c1">// decypher the callback details</span>
</span></span><span class="line"><span class="cl"><span class="n">val</span> <span class="p">=</span> <span class="n">GetFieldValue</span><span class="p">(</span><span class="n">heap</span><span class="p">,</span> <span class="n">currentTimerQueueTimerRef</span><span class="p">,</span> <span class="s">&#34;m_timerCallback&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="p">(</span><span class="n">val</span> <span class="p">!=</span> <span class="kc">null</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">   <span class="kt">ulong</span> <span class="n">elementAddress</span> <span class="p">=</span> <span class="p">(</span><span class="kt">ulong</span><span class="p">)</span><span class="n">val</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">   <span class="k">if</span> <span class="p">(</span><span class="n">elementAddress</span> <span class="p">==</span> <span class="m">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="k">continue</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">   <span class="kt">var</span> <span class="n">elementType</span> <span class="p">=</span> <span class="n">_heap</span><span class="p">.</span><span class="n">GetObjectType</span><span class="p">(</span><span class="n">elementAddress</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">   <span class="k">if</span> <span class="p">(</span><span class="n">elementType</span> <span class="p">!=</span> <span class="kc">null</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">   <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="k">if</span> <span class="p">(</span><span class="n">elementType</span><span class="p">.</span><span class="n">Name</span> <span class="p">==</span> <span class="s">&#34;System.Threading.TimerCallback&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="p">{</span>
</span></span><span class="line"><span class="cl">         <span class="n">ti</span><span class="p">.</span><span class="n">MethodName</span> <span class="p">=</span> <span class="n">BuildTimerCallbackMethodName</span><span class="p">(</span><span class="n">runtime</span><span class="p">,</span> <span class="n">elementAddress</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="cl">      <span class="k">else</span>
</span></span><span class="line"><span class="cl">      <span class="p">{</span>
</span></span><span class="line"><span class="cl">         <span class="n">ti</span><span class="p">.</span><span class="n">MethodName</span> <span class="p">=</span> <span class="s">&#34;&lt;&#34;</span> <span class="p">+</span> <span class="n">elementType</span><span class="p">.</span><span class="n">Name</span> <span class="p">+</span> <span class="s">&#34;&gt;&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="cl">   <span class="p">}</span>
</span></span><span class="line"><span class="cl">   <span class="k">else</span>
</span></span><span class="line"><span class="cl">   <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="n">ti</span><span class="p">.</span><span class="n">MethodName</span> <span class="p">=</span> <span class="s">&#34;{no callback type?}&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">   <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="k">else</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">   <span class="n">ti</span><span class="p">.</span><span class="n">MethodName</span> <span class="p">=</span> <span class="s">&#34;???&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="k">yield</span> <span class="k">return</span> <span class="n">ti</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">currentPointer</span> <span class="p">=</span> <span class="n">GetFieldValue</span><span class="p">(</span><span class="n">heap</span><span class="p">,</span> <span class="n">currentTimerQueueTimerRef</span><span class="p">,</span> <span class="s">&#34;m_next&#34;</span><span class="p">);</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>But how to get the name of the method just with the address of a <strong>TimerCallback</strong> object? Again, open up your favorite decompiler and look at the type hierarchy:</p>
<p><img loading="lazy" src="/posts/2017-05-31_clrmd-part-4-timer-callbacks/TimerCallbackClass.png"></p>
<p>Here are the two fields of the <strong>Delegate</strong> type that are interesting:</p>
<p><img loading="lazy" src="/posts/2017-05-31_clrmd-part-4-timer-callbacks/DelegateClass.png"></p>
<p>The <strong>_methodPtr</strong> field stores the pointer to the method. By chance, the <strong>ClrRuntime</strong> <strong>GetMethodByAddress</strong> method takes this address and returns the name of the method!</p>
<p>If this method is static, the <strong>_target</strong> fields is null. Otherwise, it stores the value of this, the hidden parameter received by all instance methods. In case of type inheritance, it is interesting to know which override will be called. All these steps are wrapped in the following helper function:</p>
<p><strong>BuildTimerCallbackMethodName.cs</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span><span class="lnt">27
</span><span class="lnt">28
</span><span class="lnt">29
</span><span class="lnt">30
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-csharp" data-lang="csharp"><span class="line"><span class="cl"><span class="kd">private</span> <span class="kt">string</span> <span class="n">BuildTimerCallbackMethodName</span><span class="p">(</span><span class="n">ClrRuntime</span> <span class="n">runtime</span><span class="p">,</span> <span class="kt">ulong</span> <span class="n">timerCallbackRef</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">   <span class="kt">var</span> <span class="n">heap</span> <span class="p">=</span> <span class="n">runtime</span><span class="p">.</span><span class="n">GetHeap</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">   <span class="kt">var</span> <span class="n">methodPtr</span> <span class="p">=</span> <span class="n">GetFieldValue</span><span class="p">(</span><span class="n">heap</span><span class="p">,</span> <span class="n">timerCallbackRef</span><span class="p">,</span> <span class="s">&#34;_methodPtr&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">   <span class="k">if</span> <span class="p">(</span><span class="n">methodPtr</span> <span class="p">!=</span> <span class="kc">null</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">   <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="n">ClrMethod</span> <span class="n">method</span> <span class="p">=</span> <span class="n">runtime</span><span class="p">.</span><span class="n">GetMethodByAddress</span><span class="p">((</span><span class="kt">ulong</span><span class="p">)(</span><span class="kt">long</span><span class="p">)</span><span class="n">methodPtr</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">      <span class="k">if</span> <span class="p">(</span><span class="n">method</span> <span class="p">!=</span> <span class="kc">null</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="p">{</span>
</span></span><span class="line"><span class="cl">         <span class="c1">// figure out the real callback implementor type thanks to _target</span>
</span></span><span class="line"><span class="cl">         <span class="kt">string</span> <span class="n">thisTypeName</span> <span class="p">=</span> <span class="s">&#34;?&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">         <span class="kt">var</span> <span class="n">thisPtr</span> <span class="p">=</span> <span class="n">GetFieldValue</span><span class="p">(</span><span class="n">heap</span><span class="p">,</span> <span class="n">timerCallbackRef</span><span class="p">,</span> <span class="s">&#34;_target&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">         <span class="k">if</span> <span class="p">((</span><span class="n">thisPtr</span> <span class="p">!=</span> <span class="kc">null</span><span class="p">)</span> <span class="p">&amp;&amp;</span> <span class="p">((</span><span class="kt">ulong</span><span class="p">)</span> <span class="n">thisPtr</span><span class="p">)</span> <span class="p">!=</span> <span class="m">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">         <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="kt">ulong</span> <span class="n">thisRef</span> <span class="p">=</span> <span class="p">(</span><span class="kt">ulong</span><span class="p">)</span> <span class="n">thisPtr</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">            <span class="kt">var</span> <span class="n">thisType</span> <span class="p">=</span> <span class="n">heap</span><span class="p">.</span><span class="n">GetObjectType</span><span class="p">(</span><span class="n">thisRef</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">            <span class="k">if</span> <span class="p">(</span><span class="n">thisType</span> <span class="p">!=</span> <span class="kc">null</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="p">{</span>
</span></span><span class="line"><span class="cl">               <span class="n">thisTypeName</span> <span class="p">=</span> <span class="n">thisType</span><span class="p">.</span><span class="n">Name</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">            <span class="p">}</span>
</span></span><span class="line"><span class="cl">         <span class="p">}</span>
</span></span><span class="line"><span class="cl">         <span class="k">else</span>
</span></span><span class="line"><span class="cl">         <span class="p">{</span>
</span></span><span class="line"><span class="cl">            <span class="n">thisTypeName</span> <span class="p">=</span> <span class="p">(</span><span class="n">method</span><span class="p">.</span><span class="n">Type</span> <span class="p">!=</span> <span class="kc">null</span><span class="p">)</span> <span class="p">?</span> <span class="n">method</span><span class="p">.</span><span class="n">Type</span><span class="p">.</span><span class="n">Name</span> <span class="p">:</span> <span class="s">&#34;?&#34;</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">         <span class="p">}</span>
</span></span><span class="line"><span class="cl">         <span class="k">return</span> <span class="kt">string</span><span class="p">.</span><span class="n">Format</span><span class="p">(</span><span class="s">&#34;{0}.{1}&#34;</span><span class="p">,</span> <span class="n">thisTypeName</span><span class="p">,</span> <span class="n">method</span><span class="p">.</span><span class="n">Name</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">      <span class="p">}</span>
</span></span><span class="line"><span class="cl">   <span class="p">}</span>
</span></span><span class="line"><span class="cl">   <span class="k">return</span> <span class="kt">string</span><span class="p">.</span><span class="n">Empty</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><h3 id="building-a-usable-summary">Building a usable summary</h3>
<p>Even though the <strong>EnumerateTimers</strong> helper provides a way to list all timers, you often don’t want to show them all; especially when thousands exist and most of them are duplicates. The <a href="https://github.com/criteo/criteo-dotnet-blog/tree/master/ClrMD-Parts3%2B4_Timers">sample code associated to this post</a> lists the different timers, count the duplicates and sort the result by duplicate count as shown in the following screenshot:</p>
<p><img loading="lazy" src="/posts/2017-05-31_clrmd-part-4-timer-callbacks/TimerListOutput.png"></p>
<h3 id="next-step">Next step…</h3>
<p>After timers, the next post will show how to integrate your ClrMD-based code into an extension for WinDBG to help decyphering <strong>Task</strong> state.</p>
<hr>
<p><em>Co-authored with <a href="https://twitter.com/KooKiz">Kevin Gosse</a></em></p>
]]></content:encoded></item><item><title>ClrMD Part 3 - Dealing with static and instance fields to list timers</title><link>https://chrisnas.github.io/posts/2017-05-03_clrmd-part-3-static-instance-fields/</link><pubDate>Wed, 03 May 2017 12:08:14 +0000</pubDate><guid>https://chrisnas.github.io/posts/2017-05-03_clrmd-part-3-static-instance-fields/</guid><description>This third post of the ClrMD series focuses on how to retrieve value of static…</description><content:encoded><![CDATA[<p>This third post of the ClrMD series focuses on how to retrieve value of static and instance fields by taking timers as an example. The next post will dig into the details of figuring out which method gets called when a timer triggers. As an example, the <a href="https://github.com/criteo/criteo-dotnet-blog/tree/master/ClrMD-Parts3%2B4_Timers">associated code</a> lists all timers in a dump and covers both articles.</p>
<p>Part 1: <a href="/posts/2017-02-21_clrmd-part-1-going-beyond/">Bootstrapping ClrMD</a></p>
<p>Post 2: <a href="/posts/2017-03-24_clrmd-part-2-from-clrruntime/">Finding duplicated strings with ClrMD</a></p>
<h3 id="marshaling-data-from-a-dump">Marshaling data from a dump</h3>
<p>Beyond heap navigation shown in <a href="/posts/2017-03-24_clrmd-part-2-from-clrruntime/">the previous post</a>, the big thing to understand about ClrMD is that the retrieved information is often an <strong>address</strong>. An address from another address space because the dump is seen as another process just like if you were debugging it live. Your code will need to access the other process memory corresponding to this address; not directly with a pointer/reference indirection or with the raw Win32 <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/ms680553.aspx">ReadProcessMemory</a> API function but via APIs like <strong>GetObjectType</strong> or <strong>GetValue</strong>.</p>
<p>To illustrate how to navigate into the dump address space with ClrMD, we will show how to list the timers that have been started. This can be useful to investigate various issues, such as leaks or timers being stuck.</p>
<h3 id="know-your-framework">Know your framework</h3>
<p>A naive implementation, like <a href="/posts/2017-03-24_clrmd-part-2-from-clrruntime/">the string example of the previous post</a>, would try to list all object instances in the CLR heap and look at <strong>Timer</strong> instances only. However, as it has been mentioned already, this is very inefficient in terms of performance; especially for 10+ GB dumps…</p>
<p>It is time to figure out what happens in the .NET runtime when your code creates a new timer. If the <a href="https://referencesource.microsoft.com/#mscorlib/system/threading/timer.cs">source code of the version of the CLR you are using</a> is not available, start your favorite IL decompiler and look at the <strong>System.Threading.Timer</strong> implementation details. The parameters given to the <a href="https://msdn.microsoft.com/en-us/library/system.threading.timer.aspx#Anchor_2">constructors</a> (such as the due time, period, and callback method, in addition to its optional parameter if any) are not stored in the class itself but in the <strong>TimerQueueTimer</strong> helper class.</p>
<p><img loading="lazy" src="/posts/2017-05-03_clrmd-part-3-static-instance-fields/TimerQueueTimerClass.png"></p>
<p>The <strong>Timer</strong> constructor code, after a few sanity checks, calls the <strong>TimerSetup</strong> method to wrap a <strong>TimerQueueTimer</strong> in a <strong>TimerHolder</strong> that is stored in the <strong>Timer</strong> <strong>m_timer</strong> field.</p>
<p>This is where things start to become interesting: this <strong>TimerQueueTimer</strong> class adds each new instance into a linked list kept by a singleton object stored in the static <strong>s_queue</strong> field of the <strong>TimerQueue</strong> class. The following figure shows the relation between instances after three timers are created:</p>
<p><img loading="lazy" src="/posts/2017-05-03_clrmd-part-3-static-instance-fields/TimerClassDependencies.png"></p>
<p>So… a fast way to list the timers would be to get the unique static instance of <strong>TimerQueue</strong>, look at its <strong>m_timers</strong> field and iterate on each <strong>TimerQueueTimer</strong> by following their <strong>m_next</strong> field until it contains null. The rest of the post details the following operations with ClrMD:</p>
<ul>
<li>quickly getting a <strong>ClrType</strong></li>
<li>reading a static field</li>
<li>reading an instance field</li>
</ul>
<p>to fill up a collection of our own <strong>TimerInfo</strong> used to easily create a summary:</p>
<p><strong>TimerInfo.cs</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-csharp" data-lang="csharp"><span class="line"><span class="cl"><span class="kd">public</span> <span class="k">class</span> <span class="nc">TimerInfo</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">   <span class="kd">public</span> <span class="kt">ulong</span> <span class="n">TimerQueueTimerAddress</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl">   <span class="kd">public</span> <span class="kt">uint</span> <span class="n">DueTime</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl">   <span class="kd">public</span> <span class="kt">uint</span> <span class="n">Period</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl">   <span class="kd">public</span> <span class="kt">bool</span> <span class="n">Cancelled</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl">   <span class="kd">public</span> <span class="kt">ulong</span> <span class="n">StateAddress</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl">   <span class="kd">public</span> <span class="kt">string</span> <span class="n">StateTypeName</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl">   <span class="kd">public</span> <span class="kt">ulong</span> <span class="n">ThisAddress</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl">   <span class="kd">public</span> <span class="kt">string</span> <span class="n">MethodName</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>This is wrapped inside a helper method described in the next few sections:</p>
<p><strong>EnumerateTimers-1</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-csharp" data-lang="csharp"><span class="line"><span class="cl"><span class="kd">public</span> <span class="n">IEnumerable</span><span class="p">&lt;</span><span class="n">TimerInfo</span><span class="p">&gt;</span> <span class="n">EnumerateTimers</span><span class="p">(</span><span class="n">ClrRuntime</span> <span class="n">runtime</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">   <span class="n">ClrHeap</span> <span class="n">heap</span> <span class="p">=</span> <span class="n">runtime</span><span class="p">.</span><span class="n">GetHeap</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">   <span class="k">if</span> <span class="p">(!</span><span class="n">heap</span><span class="p">.</span><span class="n">CanWalkHeap</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="k">yield</span> <span class="k">break</span><span class="p">;</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>As explained in <a href="/posts/2017-03-24_clrmd-part-2-from-clrruntime/">the previous post</a>, you need to ensure that the process was not in the middle of a garbage collection when the dump was taken by checking the value of the <strong>ClrHeap.CanWalkHeap</strong> property.</p>
<h3 id="standing-on-the-shoulders-of-giants">Standing on the shoulders of giants</h3>
<p>I have found the different steps to get access to the static fields of classes in the <a href="https://github.com/Microsoft/clrmd/tree/master/src/Microsoft.Diagnostics.Runtime">ClrMD implementation from GitHub</a>. In addition, I highly recommend that you take a look at the <a href="https://github.com/Microsoft/dotnetsamples/tree/master/Microsoft.Diagnostics.Runtime/CLRMD">samples</a>.</p>
<p>Let’s go back to our first goal: getting the value of the static <strong>s_queue</strong> field of the <strong>TimerQueue</strong> class. One of the very efficient optimization found in the ClrMD implementation is to directly get a <strong>ClrType</strong> from a module and call its <strong>GetTypeByName</strong> method instead of iterating the heap until an instance of the type is found. In our case, we need to access <strong>TimerQueue</strong> which is a type from mscorlib. Here is the code of the helper function from Desktop\threadpool.cs to get a <strong>ClrModule</strong> for mscorlib:</p>
<p><strong>GetMscorlib.cs</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-csharp" data-lang="csharp"><span class="line"><span class="cl"><span class="kd">private</span> <span class="n">ClrModule</span> <span class="n">GetMscorlib</span><span class="p">(</span><span class="n">ClrRuntime</span> <span class="n">runtime</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="k">foreach</span> <span class="p">(</span><span class="n">ClrModule</span> <span class="n">module</span> <span class="k">in</span> <span class="n">runtime</span><span class="p">.</span><span class="n">Modules</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="n">module</span><span class="p">.</span><span class="n">AssemblyName</span><span class="p">.</span><span class="n">Contains</span><span class="p">(</span><span class="s">&#34;mscorlib.dll&#34;</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="n">module</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">// Uh oh, this shouldn&#39;t have happened.  Let&#39;s look more carefully (slowly).</span>
</span></span><span class="line"><span class="cl">    <span class="k">foreach</span> <span class="p">(</span><span class="n">ClrModule</span> <span class="n">module</span> <span class="k">in</span> <span class="n">runtime</span><span class="p">.</span><span class="n">Modules</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">if</span> <span class="p">(</span><span class="n">module</span><span class="p">.</span><span class="n">AssemblyName</span><span class="p">.</span><span class="n">ToLower</span><span class="p">().</span><span class="n">Contains</span><span class="p">(</span><span class="s">&#34;mscorlib&#34;</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">            <span class="k">return</span> <span class="n">module</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1">// Ok...not sure why we couldn&#39;t find it.</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="kc">null</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>The following line sets <strong>timerQueueType</strong> with the <strong>ClrType</strong> corresponding to <strong>TimerQueue</strong>:</p>
<p><strong>EnumerateTimers-2.cs</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-csharp" data-lang="csharp"><span class="line"><span class="cl"><span class="kt">var</span> <span class="n">timerQueueType</span> <span class="p">=</span> <span class="n">GetMscorlib</span><span class="p">(</span><span class="n">runtime</span><span class="p">).</span><span class="n">GetTypeByName</span><span class="p">(</span><span class="s">&#34;System.Threading.TimerQueue&#34;</span><span class="p">);</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>Next, get the <strong>ClrStaticField</strong> corresponding to the static field <strong>s_queue</strong>:</p>
<p><strong>EnumerateTimers-3.cs</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-csharp" data-lang="csharp"><span class="line"><span class="cl"><span class="n">ClrStaticField</span> <span class="n">staticField</span> <span class="p">=</span> <span class="n">timerQueueType</span><span class="p">.</span><span class="n">GetStaticFieldByName</span><span class="p">(</span><span class="s">&#34;s_queue&#34;</span><span class="p">);</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>The <strong>staticField</strong> variable is not the static instance but rather a way to access it… or them.</p>
<h3 id="but-where-are-my-statics">But where are my statics!</h3>
<p>Let’s take some time to explain a “detail” of the .NET Framework to help you understand how to get the static <strong>TimerQueue</strong> instance. Unlike previous Windows frameworks, .NET allows a process to contain several running environments called <a href="https://learn.microsoft.com/en-us/dotnet/framework/app-domains/application-domains?WT.mc_id=DT-MVP-5003325">application domains</a> (a.k.a. AppDomains). For a better isolation, each AppDomain has its own set of static variables: this is why you need to iterate on each AppDomain with ClrMD to access the static instances:</p>
<p><strong>EnumerateTimers-4.cs</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-csharp" data-lang="csharp"><span class="line"><span class="cl"><span class="k">foreach</span> <span class="p">(</span><span class="n">ClrAppDomain</span> <span class="n">domain</span> <span class="k">in</span> <span class="n">runtime</span><span class="p">.</span><span class="n">AppDomains</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kt">ulong?</span> <span class="n">timerQueue</span> <span class="p">=</span> <span class="p">(</span><span class="kt">ulong?</span><span class="p">)</span><span class="n">staticField</span><span class="p">.</span><span class="n">GetValue</span><span class="p">(</span><span class="n">domain</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(!</span><span class="n">timerQueue</span><span class="p">.</span><span class="n">HasValue</span> <span class="p">||</span> <span class="n">timerQueue</span><span class="p">.</span><span class="n">Value</span> <span class="p">==</span> <span class="m">0</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">continue</span><span class="p">;</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>The address returned by <strong>ClrStaticField.GetValue</strong> is nullable because, in an AppDomain where no <strong>TimerQueue</strong> has ever been used, its fields won’t be initialized.</p>
<p>We don’t really need to map this address from the dump address space into something usable in the tool. Instead, only the value of the <strong>m_timers</strong> field is interesting to be able to start iterating on the list of timers.</p>
<h3 id="how-to-get-the-values-of-instance-fields">How to get the values of instance fields?</h3>
<p>Now that we have an address in the dump and the <strong>ClrType</strong> describing the type of the corresponding object (<strong>TimerQueue</strong> here), it is easy to retrieve the value of one of its instance fields. Since this action is needed again and again to move from one <strong>TimerQueueTimer</strong> object to the next, it is valuable to create a helper method:</p>
<p><strong>GetFieldValue.cs</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span><span class="lnt">5
</span><span class="lnt">6
</span><span class="lnt">7
</span><span class="lnt">8
</span><span class="lnt">9
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-csharp" data-lang="csharp"><span class="line"><span class="cl"><span class="kd">private</span> <span class="kt">object</span> <span class="n">GetFieldValue</span><span class="p">(</span><span class="n">ClrHeap</span> <span class="n">heap</span><span class="p">,</span> <span class="kt">ulong</span> <span class="n">address</span><span class="p">,</span> <span class="kt">string</span> <span class="n">fieldName</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="kt">var</span> <span class="n">type</span> <span class="p">=</span> <span class="n">heap</span><span class="p">.</span><span class="n">GetObjectType</span><span class="p">(</span><span class="n">address</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="n">ClrInstanceField</span> <span class="n">field</span> <span class="p">=</span> <span class="n">type</span><span class="p">.</span><span class="n">GetFieldByName</span><span class="p">(</span><span class="n">fieldName</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="p">(</span><span class="n">field</span> <span class="p">==</span> <span class="kc">null</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="kc">null</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">field</span><span class="p">.</span><span class="n">GetValue</span><span class="p">(</span><span class="n">address</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>The address of the object in the dump is used to get its <strong>ClrType.</strong> The <strong>ClrInstanceField</strong> (instead of a <strong>ClrStaticField</strong> as for the <strong>s_queue</strong> case) describing the property exposes the expected <strong>GetValue</strong> method. Note that the return value of <strong>GetValue</strong> is defined as <strong>System.Object</strong> but you should understand it as the numeric value stored in the dump (or the other process address space) at the given address. For the simple value types such as boolean, number and even ulong address, a cast will be enough to transparently marshal the value into the tool with ClrMD.</p>
<p>Let’s go back to writing the code to access to head of the <strong>TimerQueueTimer</strong> list from the <strong>TimerQueue</strong> static instance:</p>
<p><strong>EnumerateTimers-5.cs</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-csharp" data-lang="csharp"><span class="line"><span class="cl"><span class="c1">// m_timers is the start of the list of TimerQueueTimer</span>
</span></span><span class="line"><span class="cl"><span class="kt">var</span> <span class="n">currentPointer</span> <span class="p">=</span> <span class="n">GetFieldValue</span><span class="p">(</span><span class="n">heap</span><span class="p">,</span> <span class="n">timerQueue</span><span class="p">.</span><span class="n">Value</span><span class="p">,</span> <span class="s">&#34;m_timers&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">while</span> <span class="p">((</span><span class="n">currentPointer</span> <span class="p">!=</span> <span class="kc">null</span><span class="p">)</span> <span class="p">&amp;&amp;</span> <span class="p">(((</span><span class="kt">ulong</span><span class="p">)</span><span class="n">currentPointer</span><span class="p">)</span> <span class="p">!=</span> <span class="m">0</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="c1">// currentPointer points to a TimerQueueTimer instance</span>
</span></span><span class="line"><span class="cl">    <span class="kt">ulong</span> <span class="n">currentTimerQueueTimerRef</span> <span class="p">=</span> <span class="p">(</span><span class="kt">ulong</span><span class="p">)</span><span class="n">currentPointer</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">TimerInfo</span> <span class="n">ti</span> <span class="p">=</span> <span class="k">new</span> <span class="n">TimerInfo</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">        <span class="n">TimerQueueTimerAddress</span> <span class="p">=</span> <span class="n">currentTimerQueueTimerRef</span>
</span></span><span class="line"><span class="cl">    <span class="p">};</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="p">...</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="n">currentPointer</span> <span class="p">=</span> <span class="n">GetFieldValue</span><span class="p">(</span><span class="n">heap</span><span class="p">,</span> <span class="n">currentTimerQueueTimerRef</span><span class="p">,</span> <span class="s">&#34;m_next&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p><strong>currentPointer</strong> holds the address of each <strong>TimerQueueTimer</strong> in the list kept by the static <strong>TimerQueue</strong>.</p>
<p>Note the ((ulong)currentPointer) != 0) test in the <strong>while</strong> loop to detect the end of the list when the <strong>m_next</strong> field is <strong>null</strong>.</p>
<h3 id="next-step">Next step…</h3>
<p>After enumerating each timer, the next post will show how to extract details such as the due time, the period, and even which method is called when it ticks.</p>
<hr>
<p><em>Co-authored with <a href="https://twitter.com/KooKiz">Kevin Gosse</a></em></p>
]]></content:encoded></item><item><title>ClrMD Part 2 - From ClrRuntime to ClrHeap or how to traverse the managed heap</title><link>https://chrisnas.github.io/posts/2017-03-24_clrmd-part-2-from-clrruntime/</link><pubDate>Fri, 24 Mar 2017 09:55:15 +0000</pubDate><guid>https://chrisnas.github.io/posts/2017-03-24_clrmd-part-2-from-clrruntime/</guid><description>This second post in the ClrMD series details the basics of parsing the CLR heaps.…</description><content:encoded><![CDATA[<p>This second post in the ClrMD series details the basics of parsing the CLR heaps. The <a href="https://github.com/criteo/criteo-dotnet-blog/tree/master/ClrMD-Part2">associated code</a> checks string duplicates as sample.</p>
<p>Part 1: <a href="/posts/2017-02-21_clrmd-part-1-going-beyond/">Bootstrapping ClrMD to load a dump</a>.</p>
<h3 id="from-clrruntime-to-clrheap-or-how-to-traverse-the-managed-heap">From ClrRuntime to ClrHeap or how to traverse the managed heap</h3>
<p>In <a href="/posts/2017-02-21_clrmd-part-1-going-beyond/">the previous post</a>, we have boostrapped the code needed to load a memory dump and get an instance of <strong>ClrRuntime</strong>. This type is the starting point for accessing the content of a managed process with <a href="https://github.com/microsoft/clrmd">ClrMD</a>:</p>
<p><img loading="lazy" src="/posts/2017-03-24_clrmd-part-2-from-clrruntime/ClrMD1.png"></p>
<p>Most of the memory and heap management is well described in the <a href="https://github.com/microsoft/clrmd/blob/main/doc/GettingStarted.md#the-gc-heap">ClrMD documentation</a>, you are able to:</p>
<ul>
<li>list the application domains with <strong>AppDomains</strong>,</li>
<li>dig into the memory regions with <strong>EnumerateMemoryRegions</strong>,</li>
<li>access the managed heap with <strong>GetHeap</strong></li>
</ul>
<p>As shown in the <a href="https://github.com/microsoft/clrmd/blob/main/src/Samples/DumpHeap/DumpHeap.cs">ClrMD samples</a>, the <strong>ClrHeap</strong> type helps you traversing the managed memory:</p>
<p><img loading="lazy" src="/posts/2017-03-24_clrmd-part-2-from-clrruntime/ClrMD2.jpg"></p>
<p>Before doing any heap exploration with <strong>ClrHeap</strong>, you need to ensure that the process was not in the middle of a garbage collection when the dump was taken. This can be done by checking <strong>CanWalkHeap</strong>:</p>
<p><strong>clrmd.cs</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span><span class="lnt">4
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-csharp" data-lang="csharp"><span class="line"><span class="cl"><span class="kt">var</span> <span class="n">heap</span> <span class="p">=</span> <span class="n">clr</span><span class="p">.</span><span class="n">GetHeap</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="p">(!</span><span class="n">heap</span><span class="p">.</span><span class="n">CanWalkHeap</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">   <span class="k">return</span><span class="p">;</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>Then, you can start browsing the objects in memory with the following code:</p>
<p><strong>clrmd.cs</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-csharp" data-lang="csharp"><span class="line"><span class="cl"><span class="k">foreach</span> <span class="p">(</span><span class="n">ClrObject</span> <span class="n">obj</span> <span class="k">in</span> <span class="n">heap</span><span class="p">.</span><span class="n">EnumerateObjects</span><span class="p">())</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">   <span class="k">try</span>
</span></span><span class="line"><span class="cl">   <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="kt">var</span> <span class="n">objType</span> <span class="p">=</span> <span class="n">obj</span><span class="p">.</span><span class="n">Type</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">      <span class="k">if</span> <span class="p">(</span><span class="n">objType</span> <span class="p">==</span> <span class="kc">null</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">         <span class="k">continue</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">      <span class="p">...</span>
</span></span><span class="line"><span class="cl">   <span class="p">}</span>
</span></span><span class="line"><span class="cl">   <span class="k">catch</span> <span class="p">(</span><span class="n">Exception</span> <span class="n">x</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">   <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="n">WriteLine</span><span class="p">(</span><span class="n">x</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">      <span class="c1">// some InvalidOperationException might occur sometimes</span>
</span></span><span class="line"><span class="cl">   <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>As you can see, each reference to an object is enumerated as ClrObject used to get the type of the corresponding instance via <strong>GetObjectType</strong>. Note that the <strong>Type</strong> property might return null in some memory corruption scenario (as commented in the ClrMD samples) so don’t forget to check it in your own code. This kind of simple loop is not really efficient in term of performance when you are dealing with multi-GB dump files. Unfortunately, as the rest of the post explains, sometimes, you don’t have a choice.</p>
<h3 id="how-duplicated-are-your-strings">How duplicated are your strings?</h3>
<p>Internally at Criteo, we are always trying to improve the performance of the code that runs in production. Lately, one of the leads to limit the memory consumption was to leverage the <a href="https://msdn.microsoft.com/en-us/library/system.string.intern.aspx">interningfeature of strings</a>. Since string instances are immutable (i.e. once created, you can’t change their value), The idea is to ask the CLR to keep a single instance of each repeated string in an internal cache. Then, this instance can be shared whenever a string would be duplicated, thus saving memory. This would be especially efficient if an object model is stored as a dictionary where the keys and most of the string fields of the value data share the same values: even if millions of items are stored, their fields points to the very few different hundreds of strings.</p>
<p>But before starting any major refactoring, it is mandatory to have metrics about the current status and being able to measure the possible gains. In that context, it would be interesting to get a summary of which strings are the most repeated with their corresponding size in memory: something close to <strong>!sos.dumpheap -stat</strong>.</p>
<p>The code to achieve this goal is simple and straightforward from the loop previously listed: you just have to check if the type is System.String and count every different value in a dictionary.</p>
<p><strong>Clrmd.cs</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-csharp" data-lang="csharp"><span class="line"><span class="cl"><span class="n">Dictionary</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">,</span> <span class="kt">int</span><span class="p">&gt;</span> <span class="n">strings</span> <span class="p">=</span> <span class="k">new</span> <span class="n">Dictionary</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">,</span> <span class="kt">int</span><span class="p">&gt;();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">obj</span> <span class="k">in</span> <span class="n">heap</span><span class="p">.</span><span class="n">EnumerateObjects</span><span class="p">())</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">   <span class="p">...</span>
</span></span><span class="line"><span class="cl">   <span class="k">if</span> <span class="p">(</span><span class="n">obj</span><span class="p">.</span><span class="n">Type</span><span class="p">.</span><span class="n">Name</span> <span class="p">!=</span> <span class="s">&#34;System.String&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="k">continue</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">   <span class="kt">string</span> <span class="n">s</span> <span class="p">=</span> <span class="n">obj</span> <span class="k">as</span> <span class="kt">string</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">   <span class="k">if</span> <span class="p">(!</span><span class="n">strings</span><span class="p">.</span><span class="n">ContainsKey</span><span class="p">(</span><span class="n">s</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">   <span class="p">{</span>
</span></span><span class="line"><span class="cl">      <span class="n">strings</span><span class="p">[</span><span class="n">s</span><span class="p">]</span> <span class="p">=</span> <span class="m">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">   <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">   <span class="n">strings</span><span class="p">[</span><span class="n">s</span><span class="p">]</span> <span class="p">=</span> <span class="n">strings</span><span class="p">[</span><span class="n">s</span><span class="p">]</span> <span class="p">+</span> <span class="m">1</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">   <span class="p">...</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>The formatting of the results is also simple. The strings are sorted by the size in bytes of all duplicated instances (hence the x2 multiplier factor because a character is UTF-16 encoded on 2 bytes):</p>
<p><strong>Clrmd.cs</strong></p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt"> 1
</span><span class="lnt"> 2
</span><span class="lnt"> 3
</span><span class="lnt"> 4
</span><span class="lnt"> 5
</span><span class="lnt"> 6
</span><span class="lnt"> 7
</span><span class="lnt"> 8
</span><span class="lnt"> 9
</span><span class="lnt">10
</span><span class="lnt">11
</span><span class="lnt">12
</span><span class="lnt">13
</span><span class="lnt">14
</span><span class="lnt">15
</span><span class="lnt">16
</span><span class="lnt">17
</span><span class="lnt">18
</span><span class="lnt">19
</span><span class="lnt">20
</span><span class="lnt">21
</span><span class="lnt">22
</span><span class="lnt">23
</span><span class="lnt">24
</span><span class="lnt">25
</span><span class="lnt">26
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-csharp" data-lang="csharp"><span class="line"><span class="cl"><span class="kt">int</span> <span class="n">totalSize</span> <span class="p">=</span> <span class="m">0</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// Sort by size taken by the instances of string</span>
</span></span><span class="line"><span class="cl"><span class="kt">var</span> <span class="n">query</span> <span class="p">=</span> <span class="n">strings</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="n">Where</span><span class="p">(</span><span class="n">s</span> <span class="p">=&gt;</span> <span class="n">s</span><span class="p">.</span><span class="n">Value</span> <span class="p">&gt;</span> <span class="n">minCountThreshold</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="n">Select</span><span class="p">(</span><span class="n">e</span> <span class="p">=&gt;</span> <span class="k">new</span>
</span></span><span class="line"><span class="cl">    <span class="p">{</span>
</span></span><span class="line"><span class="cl">       <span class="n">Count</span> <span class="p">=</span> <span class="n">e</span><span class="p">.</span><span class="n">Value</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">       <span class="n">Size</span> <span class="p">=</span> <span class="m">2</span> <span class="p">*</span> <span class="n">e</span><span class="p">.</span><span class="n">Value</span> <span class="p">*</span> <span class="n">e</span><span class="p">.</span><span class="n">Key</span><span class="p">.</span><span class="n">Length</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="n">Key</span> <span class="p">=</span> <span class="n">e</span><span class="p">.</span><span class="n">Key</span>
</span></span><span class="line"><span class="cl">    <span class="p">})</span>
</span></span><span class="line"><span class="cl">    <span class="p">.</span><span class="n">OrderBy</span><span class="p">(</span><span class="n">ai</span> <span class="p">=&gt;</span> <span class="n">ai</span><span class="p">.</span><span class="n">Size</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">aggregatedInfo</span> <span class="k">in</span> <span class="n">query</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl">   <span class="n">WriteLine</span><span class="p">(</span><span class="kt">string</span><span class="p">.</span><span class="n">Format</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">      <span class="s">&#34;{0,8} {1,12} {2}&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="n">aggregatedInfo</span><span class="p">.</span><span class="n">Count</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="n">aggregatedInfo</span><span class="p">.</span><span class="n">Size</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">      <span class="n">aggregatedInfo</span><span class="p">.</span><span class="n">Key</span><span class="p">.</span><span class="n">Replace</span><span class="p">(</span><span class="s">&#34;\n&#34;</span><span class="p">,</span> <span class="s">&#34;## &#34;</span><span class="p">).</span><span class="n">Replace</span><span class="p">(</span><span class="s">&#34;\r&#34;</span><span class="p">,</span> <span class="s">&#34; ##&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="p">));</span>
</span></span><span class="line"><span class="cl">   <span class="n">totalSize</span> <span class="p">+=</span> <span class="n">aggregatedInfo</span><span class="p">.</span><span class="n">Size</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">WriteLine</span><span class="p">(</span><span class="s">&#34;-------------------------------------------------------------------------&#34;</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"><span class="n">WriteLine</span><span class="p">(</span><span class="kt">string</span><span class="p">.</span><span class="n">Format</span><span class="p">(</span><span class="s">&#34;         {0,12} MB&#34;</span><span class="p">,</span> <span class="n">totalSize</span><span class="p">/(</span><span class="m">1024</span><span class="p">*</span><span class="m">1024</span><span class="p">)));</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>Note that a <strong>minCountThreshold</strong> parameter is used here as a minimum number of instances of the same string to avoid listing strings not so duplicated in memory. For a better formatting, the \r\n are transformed into “##” so each string stays on one line. Here is the result for a simple sample app:</p>
<p><img loading="lazy" src="/posts/2017-03-24_clrmd-part-2-from-clrruntime/ClrMD3.png"></p>
<p>The gain would be less than a MB here…</p>
<h3 id="next-step">Next step…</h3>
<p>In this example, we let ClrMD transparently marshal the strings instances from the dump address space into our tool. However, sometimes, you need to directly and explicitly access the value of type fields. This will be the subject of the next post where we describe how to list the timers running in a process.</p>
<hr>
<p><em>Co-authored with <a href="https://twitter.com/KooKiz">Kevin Gosse</a></em></p>
]]></content:encoded></item><item><title>ClrMD Part 1 - Going beyond SOS</title><link>https://chrisnas.github.io/posts/2017-02-21_clrmd-part-1-going-beyond/</link><pubDate>Tue, 21 Feb 2017 15:50:21 +0000</pubDate><guid>https://chrisnas.github.io/posts/2017-02-21_clrmd-part-1-going-beyond/</guid><description>A little bit of context Thousands of servers are closely monitored at Criteo and when…</description><content:encoded><![CDATA[<h3 id="a-little-bit-of-context">A little bit of context</h3>
<p>Thousands of servers are closely monitored at Criteo and when inconsistent behaviors are detected, an investigation is started based on these deviant machines. The level of details provided by the monitoring is close to what is provided by performance counters. Our team is using them to guess where the problem could come from. The next step is to have a closer look to one of the faulting machines in order to figure out whether our guess is valid… or not.</p>
<p>Lately, we got a few situations where the number of running threads was growing up to hundreds, even thousands. To limit the impact on production machines, we are taking dumps with <a href="https://technet.microsoft.com/en-us/sysinternals/dd996900">procdump</a> from SysInternals and we are loading them into WinDBG to dig into the CLR data structures with SOS commands. However, when you are dealing with 20+ GB dumps and thousands of threads, the investigation starts to become complicated simply due to the mass of data, the performance hit and the complexity of the highly multi-threaded code.</p>
<h2 id="sizing-and-tooling-limits">Sizing and tooling limits</h2>
<p>The magic of using sos with WinDBG on a .NET dump is the ability to navigate among your data; either your types, BCL or other libraries types. With !do, you are able to see the values of the fields in the instances of objects manipulated by your application. However, it is clearly less efficient than the navigation provided by the Watch or QuickWatch panes in Visual Studio. In addition, you first need to find the instance(s) you are interested in and it usually means calling !dumpheap -stat and !dumpheap -mt to narrow down the search. On multi-GB dumps, it will cost you minutes just before being able to !do one of the possibly interesting instances.</p>
<p>One solution is to build tools that leverage sos commands textual output to automate well known scenari. The <a href="https://codenasarre.wordpress.com/2011/05/18/leakshell-or-how-to-automatically-find-managed-leaks/">LeakShell tool</a> has been built as a WinDBG companion application to ease a memory leaks hunt. Even if LeakShell has been enhanced to <a href="https://codenasarre.wordpress.com/2011/07/20/leakshell-1-4-use-the-dumps-luke/">directly consume dumps</a>, parsing text outputs from !dumpheap -stat might be fragile if it changes but also not very scalable in large dumps.</p>
<p>As developers, we would definitively prefer to write our own tool based on clean and easy to use APIs instead of parsing cryptic textual output. This is exactly the purpose of ClrMD as stated by its first line of documentation: <a href="https://github.com/microsoft/clrmd">CLR MD</a> <em>is a C# API used to build diagnostics tools</em>. This Microsoft project (thank you so much <a href="https://github.com/leculver">Lee Culver</a>!) is available from <a href="https://github.com/Microsoft/clrmd">Github</a> and provides a managed wrapper that brings the power of sos and symbol engine to your C# code. Take the time to <a href="https://github.com/microsoft/clrmd/blob/main/doc/GettingStarted.md">follow the tutorials</a> and open the <a href="https://github.com/microsoft/clrmd/tree/main/src/Samples">samples code</a>: you have everything you need!</p>
<p>This series of posts will detail how to write your own tool with ClrMD and describe some of the code we had to write to help our investigations for real world production machines servicing millions of requests per second worldwide.</p>
<h3 id="bootstrapping-a-tool-based-on-clrmd">Bootstrapping a tool based on ClrMD</h3>
<p>The basic scenario that our tool needs to support is opening a dump file and automate CLR data structures analysis to provide high level summaries.</p>
<p>When you start a project that will use ClrMD, you should tell Nuget to get the official version for you. Right-click the References node of your project and select Manage NuGet Packages. Look for microsoft.diagnostics.runtime (don’t forget the “Include prerelease” check) and install it</p>
<p><img loading="lazy" src="/posts/2017-02-21_clrmd-part-1-going-beyond/NUGpost.png"></p>
<p>As stated by the last line of the description: no other dependency is required.</p>
<p>Note: this version 0.8.31 is still in beta but you could get the latest level of code from <a href="https://github.com/Microsoft/clrmd">Github</a> (more on this in a later post).</p>
<p>The root class you’re starting with in ClrMD is DataTarget:</p>
<p><img loading="lazy" src="/posts/2017-02-21_clrmd-part-1-going-beyond/DataTarget.png"></p>
<p>This class wraps a debugging session, either a live one by calling AttachToProcess or a post-mortem analysis on a dump file with the LoadCrashDump. For the rest of the series, we will focus on the dump analysis.</p>
<h3 id="loading-a-dump">Loading a dump</h3>
<p>The first step is to tell ClrMD to open a .dmp file and use it to create the DataTarget:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-csharp" data-lang="csharp"><span class="line"><span class="cl"><span class="n">target</span> <span class="p">=</span> <span class="n">DataTarget</span><span class="p">.</span><span class="n">LoadCrashDump</span><span class="p">(</span><span class="n">dumpFilename</span><span class="p">);</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>Since .NET 4.0, it is possible to <a href="https://msdn.microsoft.com/en-us/library/ee518876">load “several” versions of the CLR</a> in the same process at the same time. The list of the loaded CLR runtimes is provided by the DataTarget.ClrVersions property and for simplicity sake, only the first one will be taken into account in the rest of the series. This property returns a list of ClrInfo:</p>
<p><img loading="lazy" src="/posts/2017-02-21_clrmd-part-1-going-beyond/clrInfo.png"></p>
<p>Several members of this class relate to “Dac”: this makes reference to the data access layer provided by mscordacwks.dll. As most of you should know (if this is not the case, <a href="https://codenasarre.wordpress.com/2011/06/22/sending-an-sos/">read this detailed post</a>), this library is used by sos.dll and ClrMD to access the internal CLR data structures. This sos/mscordacwks pair is unique per version of the CLR and therefore unique to the dumps you download from a server.</p>
<h3 id="loading-the-right-dac">Loading the right Dac</h3>
<p>The symbol engine API used by WinDBG and ClrMD behind the scene are slightly different in figuring how to get the right version; i.e. the version corresponding to your dump (which might be different from the one your machine). An easy way to load the right dac is to copy the sos/mscordacwks dlls from the server (from C:\Windows\Microsoft.NET\Framework64&lt;v4.0.30319&gt;) where the dump was taken and paste them in the dump folder.</p>
<p>You tell WinDBG where to find mscordacwks.dll with the following command:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">.cordll -lp &lt;path&gt;
</span></span></code></pre></td></tr></table>
</div>
</div><p>Next, here is the command to explicitly load sos from a folder:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">.load &lt;path&gt;\sos
</span></span></code></pre></td></tr></table>
</div>
</div><p>The story is a little bit different for ClrMD: you have to manually simulate the work WinDBG is doing. The ClrInfo instance will help getting the right version of the Runtime instance corresponding to the right version of mscordacwks.dll that you copied from the dump machine:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span><span class="lnt">2
</span><span class="lnt">3
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-csharp" data-lang="csharp"><span class="line"><span class="cl"><span class="n">Clr</span> <span class="p">=</span> <span class="n">target</span><span class="p">.</span><span class="n">ClrVersions</span><span class="p">[</span><span class="m">0</span><span class="p">].</span><span class="n">CreateRuntime</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="n">Path</span><span class="p">.</span><span class="n">Combine</span><span class="p">(</span><span class="n">Path</span><span class="p">.</span><span class="n">GetDirectoryName</span><span class="p">(</span><span class="n">dumpFilename</span><span class="p">),</span> <span class="s">&#34;mscordacwks.dll&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="p">);</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>If you were not able to copy the dll with the dump file, you could leverage the symbol engine to automatically retrieve it (with the risks of not finding the exact same version if your machines have been patched and the symbols/mscordacwks.dll are not available from the Microsoft servers):</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-csharp" data-lang="csharp"><span class="line"><span class="cl"><span class="n">Clr</span> <span class="p">=</span> <span class="n">target</span><span class="p">.</span><span class="n">ClrVersions</span><span class="p">[</span><span class="m">0</span><span class="p">].</span><span class="n">CreateRuntime</span><span class="p">();</span>
</span></span></code></pre></td></tr></table>
</div>
</div><p>As explained in the <a href="https://github.com/microsoft/clrmd/blob/main/doc/GettingStarted.md">getting started page</a>, this call will try to use the “local” mscordacwks.dll from current machine Windows subfolder and if there is no matching version, it will use the DataTarget.SymbolLocator.Find method to download this dll from the Microsoft public servers.</p>
<p>WinDBG and Visual Studio are taking two environment variables into account when time comes to load .pdb symbols files (_NT_SYMBOL_PATH) and sos.dll/mscordacwks.dll (_NT_EXECUTABLE_IMAGE_PATH).</p>
<p>The <a href="https://msdn.microsoft.com/en-us/library/windows/desktop/ee416588.aspx">syntax is simple</a>:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">srv*c:\symbols*http://msdl.microsoft.com/download/symbols
</span></span></code></pre></td></tr></table>
</div>
</div><p>After the srv prefix, the different locations where the files could be found are listed in order, prefixed by the * character; from a local one to the Microsoft remote web site.</p>
<p>The ClrMD SymbolLocator also leverages the _NT_SYMBOL_PATH environment variable (unlike what the documentation states). Note that secure <em>https</em> syntax for the web site is not supported by the SymbolLocator implementation so be very careful on checking the value stored in your environment variables…</p>
<p>If this environment variable is not set, the following default values will be used by the symbol locator (exposed by its SymbolPath property) to download the .pdb symbol files:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">SRV*http://msdl.microsoft.com/download/symbols;SRV*http://referencesource.microsoft.com/symbols
</span></span></code></pre></td></tr></table>
</div>
</div><p>and they are stored locally into:</p>
<div class="highlight"><div class="chroma">
<table class="lntable"><tr><td class="lntd">
<pre tabindex="0" class="chroma"><code><span class="lnt">1
</span></code></pre></td>
<td class="lntd">
<pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">C:\Users\&lt;user&gt;\AppData\Local\Temp\symbols (exposed by its SymbolCache property).
</span></span></code></pre></td></tr></table>
</div>
</div><p>Unlike WinDBG, to find binary files such as mscordacwks.dll, ClrMD does not take into account the _NT_EXECUTABLE_IMAGE_PATH environment variable. Even worse, if the dll has not been downloaded into the local cache, the CreateRuntime() call throws a FileNotFoundException with the name of the searched dac as its Message property value (ex: mscordacwks_Amd64_Amd64_4.6.1076.00.dll). Note that the deprecated TryDownloadDac method does not throw an exception but returns null instead.</p>
<h3 id="next-step">Next step…</h3>
<p>Once a runtime has been created from the DataTarget, it is now possible to dig into the dump… to detect string duplicates as the next post will present.</p>
<hr>
<p><em>Co-authored with <a href="https://twitter.com/KooKiz">Kevin Gosse</a></em></p>
]]></content:encoded></item></channel></rss>