Piotr Shatalin
Piotr Shatalin

Reputation: 453

What do directory names like D0C3BDDD4ADD4E87B2B5E803303B8D772 in Visual Studio symbol cache mean?

I have a symbol cache directory set to D:\symbols in Visual Studio options:

Options

Within this directory Visual Studio creates a hierarchy with top-level directories matching PDB file names (e.g. ole32.pdb), on the next level are one or more directories like D0C3BDDD4ADD4E87B2B5E803303B8D772 (looking like 33-digit hexadecimal numbers) and inside them are PDB files themselves, presumably, downloaded from Microsoft Symbol Servers.

I suppose that these hexadecimal numbers represent versions of PDB files. I wonder, whether these numbers have any structure or meaning, and how they can be extracted from PDB files (ideally, using C#)?

Given a PDB file in some other folder, is it possible to find a directory in the symbol cache where Visual Studio debugger would look for it?

Upvotes: 14

Views: 699

Answers (2)

Nick Gotch
Nick Gotch

Reputation: 9407

This value is a GUID that's embedded in both the assembly and the symbol file so they can be synced up.

https://www.atmosera.com/blog/pdb-files-what-every-developer-must-know/

You can run dumpbin /headers on your assembly to see the embedded GUID.

Upvotes: 4

Vladimir Reshetnikov
Vladimir Reshetnikov

Reputation: 11932

The first 32 digits is just a GUID that is baked both into PE file (DLL, EXE, ...) and a corresponding PDB, next digits are so-called age in hexadecimal representation without leading zeros (it might be incremented during a build process by linking, signing, etc). In most cases an age fits into a single hex digit, hence 33 digits in total, sometimes called signature. You can extract a signature from a PDB file using the Debug Interface Access SDK. An example in C#:

using System;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;

static class Program
{
    // Pass a PDB file name as a command-line parameter
    static void Main(string[] args)
    {
        var pdbFile = args.FirstOrDefault();
        if (!File.Exists(pdbFile))
            return;

        try
        {
            var dataSource = (IDiaDataSource)Activator.CreateInstance(Marshal.GetTypeFromCLSID(new Guid("83AB22C8-993A-4D14-A0E0-37BC0AAEA793")));
            dataSource.LoadDataFromPdb(pdbFile);

            IDiaSession session;
            dataSource.OpenSession(out session);

            var globalScope = session.GlobalScope;
            Console.WriteLine(globalScope.Guid.ToString("N").ToUpperInvariant() + globalScope.Age.ToString("X"));
        }
        catch (COMException) { } // May happen for corrupted PDB files
    }
}


[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("79F1BB5F-B66E-48E5-B6A9-1545C323CA3D")]
interface IDiaDataSource
{
    void _VtblGap_1();
    void LoadDataFromPdb(string pdbFile);
    void _VtblGap_3();
    void OpenSession(out IDiaSession session);
}

[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("6FC5D63F-011E-40C2-8DD2-E6486E9D6B68")]
interface IDiaSession
{
    void _VtblGap_2();
    IDiaSymbol GlobalScope { get; }
}

[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("CB787B2F-BD6C-4635-BA52-933126BD2DCD")]
interface IDiaSymbol
{
    void _VtblGap_43();
    Guid Guid { get; }
    void _VtblGap_28();
    uint Age { get; }
}

Upvotes: 9

Related Questions