I have a symbol cache directory set to D:\symbols
in Visual Studio 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?
Visual Studio offers two modes of automatic symbol loading: **Automatically load symbols for all modules unless excluded: **As the title indicates, unless you add a module to the exclude list by clicking “Specify excluded modules”, Visual Studio will try to load symbols for all modules in the process.
pdb file holds debugging and project state information that allows incremental linking of a Debug configuration of your app. The Visual Studio debugger uses . pdb files to determine two key pieces of information while debugging: The source file name and line number to display in the Visual Studio IDE.
PDB Path in CodeView Debug Information In both cases, the name of the PDB file with the . pdb extension is included to ensure the debugger locates the correct PDB for the program. A partially qualified PDB path would list only the PDB file name, such as: Test.pdb.
From Visual Studio, select Tools > Options > Debugging. Select Symbols from the list, and then select the + sign to add a new Azure DevOps symbol server location.
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; }
}
This value is a GUID that's embedded in both the assembly and the symbol file so they can be synced up.
http://www.wintellect.com/blogs/jrobbins/pdb-files-what-every-developer-must-know
You can run dumpbin /headers
on your assembly to see the embedded GUID.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With