The Importance of Symbols

This post looks at incorrect stack traces in more detail and provides an example and explanation of why WinDbg is not able to get them right and why we need symbol files to beautify them. Consider the following stack trace from !analyze -v command:

00c0ecc8 0042fa36 0190483c 4d445443 0032422c msvcrt!wcscmp+0×18
WARNING: Stack unwind information not available. Following frames may be wrong.
00c0ecec 0043045d Application!Array::operator=+0×2ea1b
00c0ed08 0042d7fb Application!Array::operator=+0×2f442
00c0ed38 0042d87a Application!Array::operator=+0×2c7e0
00c0ed58 0040f393 Application!Array::operator=+0×2c85f
00c0efc8 0040b2c1 Application!Array::operator=+0xe378
00c0eff8 0040c104 Application!Array::operator=+0xa2a6
00c0f038 004192e0 Application!Array::operator=+0xb0e9
00c0f0f0 7c829f5d Application!Array::operator=+0×182c5
01c3f138 00000000 00000000 00000000 00000000 ntdll!RtlFreeHeap+0×20e

Although string comparison function could be called from Application code, it has a semantic inconsistency: FreeHeap surely wouldn’t call Application code. So why it appears on the stack trace? To find out, we look at the thread raw stack data from ESP up to the base and try to do a manual descent to reconstruct that stack trace, starting from EBP value (EIP points to wcscmp):

0:000> r
eax=4d445443 ebx=00000013 ecx=018fe8a0 edx=0190483c esi=4d445443 edi=018fa148
eip=77bd8e21 esp=00c0ecc0 ebp=00c0ecc8 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010202
77bd8e21 668b0e          mov     cx,word ptr [esi]        ds:0023:4d445443=????

0:000> !teb
TEB at 7ffdc000
    ExceptionList:        00c0efbc
    StackBase:            00c10000
    StackLimit:           00c0a000
    SubSystemTib:         00000000
    FiberData:            00001e00
    ArbitraryUserPointer: 00000000
    Self:                 7ffdc000
    EnvironmentPointer:   00000000
    ClientId:             00005d68 . 0000503c
    RpcHandle:            00000000
    Tls Storage:          00000000
    PEB Address:          7ffd7000
    LastErrorValue:       0
    LastStatusValue:      0
    Count Owned Locks:    0
    HardErrorMode:        0

0:000> dds 00c0ecc0 00c10000
00c0ecc0  018fa148
00c0ecc4  018f9ff0
00c0ecc8  00c0ecec
00c0eccc  0042fa36 Application!Array::operator=+0×2ea1b
00c0ecd0  0190483c
00c0ecec  00c0ed08
00c0ecf0  0043045d Application!Array::operator=+0×2f442
00c0ecf4  0190483c
00c0ed08  00c0ed38
00c0ed0c  0042d7fb Application!Array::operator=+0×2c7e0
00c0ed10  01bb4914
00c0ed38  00c0ed58
00c0ed3c  0042d87a Application!Array::operator=+0×2c85f
00c0ed40  00000000
00c0ed58  00c0efc8
00c0ed5c  0040f393 Application!Array::operator=+0xe378
00c0ed60  01bb467c
00c0efc8  00c0eff8
00c0efcc  0040b2c1 Application!Array::operator=+0xa2a6
00c0efd0  00c0f014
00c0eff8  00c0f038
00c0effc  0040c104 Application!Array::operator=+0xb0e9
00c0f000  00c0f014
00c0f038  00c0f0d8
00c0f03c  004192e0 Application!Array::operator=+0×182c5
00c0f040  01902380
00c0f0d8  01c3f138
00c0f0dc  01c037a8
00c0f0e0  00000002
00c0f0e4  01c316d8
00c0f0e8  001402f8
00c0f0ec  01c3eab0
00c0f0f0  00c0f1d0
00c0f0f4  7c829f5d ntdll!RtlFreeHeap+0×20e
00c0f0f8  00140c28
00c0f1d0  00000000
00c0f1d4  00000001

What we can see that 00c0f0d8 points to 01c3f138 which is outside stack data range so WinDbg searches for the next symbol and it is ntdll!RtlFreeHeap+0×20e.

After applying correct symbols the magic occurs:

0:000> kl 100
ChildEBP RetAddr 
00c0ecc8 0042fa36 msvcrt!wcscmp+0x18
00c0ecec 0043045d Application!foo17+0x5d
00c0ed08 0042d7fb Application!foo16+0x69
00c0ed38 0042d87a Application!foo15+0xe1
00c0ed58 0040f393 Application!foo14+0x64
00c0ef7c 0040a4fe Application!foo13+0x8a
00c0efc8 0040b2c1 Application!foo12+0x76a
00c0eff8 0040c104 Application!foo11+0x126
00c0f038 004192e0 Application!foo10+0x11e
00c0f280 004193dd Application!foo9+0x34c
00c0f2b4 0041953d Application!foo8+0xc3
00c0f2e8 00415abd Application!foo7+0xb7
00c0f304 0040c19a Application!foo6+0x36
00c0f81c 0040ca44 Application!foo5+0x6a
00c0f834 0040cb04 Application!foo4+0x7e
00c0f874 00415cc6 Application!foo3+0x83
00c0f884 00403839 Application!foo2+0x26
00c0f898 77c80193 Application!foo+0x56
00c0f8b4 77ce33e1 rpcrt4!Invoke+0x30
00c0fcb4 77ce35c4 rpcrt4!NdrStubCall2+0x299
00c0fcd0 77c7ff7a rpcrt4!NdrServerCall2+0x19
00c0fd04 77c8042d rpcrt4!DispatchToStubInCNoAvrf+0x38
00c0fd58 77c80353 rpcrt4!RPC_INTERFACE::DispatchToStubWorker+0x11f
00c0fd7c 77c7e0d4 rpcrt4!RPC_INTERFACE::DispatchToStub+0xa3
00c0fdbc 77c7e080 rpcrt4!RPC_INTERFACE::DispatchToStubWithObject+0xc0
00c0fdfc 77c812f0 rpcrt4!LRPC_SCALL::DealWithRequestMessage+0x41e
00c0fe20 77c88678 rpcrt4!LRPC_ADDRESS::DealWithLRPCRequest+0x127
00c0ff84 77c88792 rpcrt4!LRPC_ADDRESS::ReceiveLotsaCalls+0x430
00c0ff8c 77c8872d rpcrt4!RecvLotsaCallsWrapper+0xd
00c0ffac 77c7b110 rpcrt4!BaseCachedThreadRoutine+0x9d
00c0ffb8 77e6482f rpcrt4!ThreadStartRoutine+0x1b
00c0ffec 00000000 kernel32!BaseThreadStart+0x34

- Dmitry Vostokov @ -

Leave a Reply

You must be logged in to post a comment.