I downloaded Microsoft’s newly released Visual Studio 2010 CTP virtual machine disk image hoping for a few surprises, but I certainly didn’t expect this…

The Visual Studio 2010 CTP is a huge multi-gigabyte VM running Windows Server 2008. The first thing I did with it is start up Visual C++ 2010, create a Win32 console application and run it in the debugger. I looked at the stack trace and saw the following:



vc10app.exe!wmain(int argc=1, wchar_t * * argv=0x000d1470) Line 8

vc10app.exe!__tmainCRTStartup() Line 564 + 0x19 bytes

vc10app.exe!wmainCRTStartup() Line 392

kernel32.dll!BaseThreadInitThunk(unsigned long RunProcessInit=0, long (void *)* StartAddress=0x00000000, void * Argument=0x7ffdf000) Line 66 + 0x5 bytes

ntdll.dll!__RtlUserThreadStart(long (void *)* StartAddress=0x013b1073, void * Argument=0x7ffdf000) Line 2740

ntdll.dll!_RtlUserThreadStart(long (void *)* StartAddress=0x013b1073, void * Argument=0x7ffdf000) Line 2672 + 0xb bytes

vc10app is the name of my test console application. I go over stack traces on a daily basis so the special thing about this one immediately caught my attention. Notice that the wmain() function of my console application has full debugging information (as expected for something I wrote) and the parameter names argc and argv are visible in the stack trace. Under normal circumstances, only public debugging symbols are available for Microsoft OS components like kernel32 and ntdll. In this CTP VM, however, the StartAddress and Argument parameters were visible as well.

Public debugging symbols are stripped versions of the original private symbols generated by the build process. They do not contain parameter information and do not contain the names of local variables in functions. Note however that for C++ functions, name mangling results in parameter types being visible in public symbols as well. Normally, when running the debugger in a system configured to use Microsoft’s public symbols, names for internal functions are visible in stack traces, but the names of arguments and locals never are.

I opened the Modules tab of the Visual Studio debugger to determine where the debugger is picking up these symbols for kernel32 and ntdll. The debugger was using C:\ppa\symstore as the symbol store. I opened the C:\ppa directory and saw that a Visual Studio Profiler session for a matrix multiplication application was stored there.

Apparently someone with access to Microsoft’s internal symbol store ran a profiling session on this matrix multiplication application, perhaps to ensure profiling is functional on the CTP VM. The private symbols retrieved for the session were persisted in the CTP’s disk and made their way to the public release. To ensure my hypothesis was correct, I installed Windbg on the machine, opened ntdll.dll as a crash dump and loaded symbols from the store directory:



Microsoft (R) Windows Debugger Version 6.9.0003.113 X86

Copyright (c) Microsoft Corporation. All rights reserved.

Loading Dump File [C:\Windows\System32

tdll.dll]

Symbol search path is: SRV*c:\ppa\symcache;.

Executable search path is:

ModLoad: 77ed0000 77ff7000 C:\Windows\System32

tdll.dll

eax=00000000 ebx=00000000 ecx=00000000 edx=00000000 esi=00000000 edi=00000000

eip=77ed0000 esp=00000000 ebp=00000000 iopl=0 nv up di pl nz na po nc

cs=0000 ss=0000 ds=0000 es=0000 fs=0000 gs=0000 efl=00000000

ntdll!`string'

(ntdll+0x0):

77ed0000 4d dec ebp

0:000> .reload /f

.

Loading unloaded module list

0:000> lm

start end module name

77ed0000 77ff7000 ntdll (private pdb symbols) c:\ppa\symcache

tdll.pdb\B958B2F91A5A46B889DAFAB4D140CF252

tdll.pdb

0:000> x ntdll!RtlAllocateHeap

77f358a6 ntdll!RtlAllocateHeap (void *, unsigned long, unsigned long)

0:000> dv /f ntdll!RtlAllocateHeap

@ebp+0x08 HeapHandle

@ebp+0x0c Flags

@ebp+0x10 Size

@ebp+0x08 ExtraSize

@ebp-0x04 AllocationSize

@ebp-0x08 Interceptor

@ebp-0x58 ExceptionRecord

The private PDB for ntdll.dll found in this CTP VM image notes how HeapHandle, Flags, Size and ExtraSize are the parameter names for RtlAllocateHeap. Furthermore, AllocationSize, Interceptor and ExceptionRecord are used as local names in this API.

Private PDBs also feature source information. This is also visible in this case:



0:000> ln ntdll!RtlAllocateHeap

d:\rtm\base

tos\rtl\heap.c(1508)

Source Depot: basedepot.sys-ntgroup.ntdev.microsoft.com:2003 //depot/longhorn_rtm/base/ntos/rtl/heap.c#1

(77f358a6) ntdll!RtlAllocateHeap | (77f35997) ntdll!RtlpLowFragHeapFree

Exact matches:

ntdll!RtlAllocateHeap (void *, unsigned long, unsigned long)

The PDB features references to the source file from the Windows source tree for RtlAllocateHeap and the other APIs. Additionally, it appears to contain a custom reference to Microsoft’s internal source control system, Source Depot, presumably to facilitate the debugger retrieving up to date sources automatically when those are not available locally.

It’s interesting how scattered bits of information in a debugging symbols file provide a fascinating insight into Windows. Hope you enjoyed the surprise as much as I did…