How to identify which ASP page is being processed on a specific thread

I’ve been teaching one of our workshops offerings (Workshop Plus: IIS6 Critical Problem Management) and when we go through some debugging samples, one thing I like to demo is how to find which Asp.Net pages are being processed in which threads. Well, the SOS.dll extension supports the “!aspxpages” command that will make your life really easier in a sense that all you need to do is run the command and it will return a list of the threads and their respective IDs as well as which Asp.Net page is being processed by such threads (aspx, asmx).

And then the students try to use the same command to identify classic Active Server Pages (.asp). This will not work since the commands implemented by the SOS.dll are specifically for managed code (.Net) and ASP pages will be processed by threads running native code. Well, the easiest way to accomplish that would be just feedback the memory dump to the Debug Diagnostics Tool (DebugDiag) and run the hang/crash analysis scripts against it. But how about when you don’t have Debug Diagnostics Tool (DebugDiag) or any other extension available for some reason to do that for you? Can you still do that manually through the Windbg from Debugging Tools For Windows? The answer is YES! And you don’t even need symbols for that ;-).

Here is what you can do to find out what ASP page is being processed in a specific thread:

First verify the thread call stack:

0:032> kb

ChildEBP RetAddr

0235fa88 709e2d54 0235fb0c 00000000 00000000 asp!CallScriptFunctionOfEngine+0x5b

0235fadc 709e2c7f 01911e90 00000000 0235fb68 asp!ExecuteRequest+0x17e

0235fb44 709e2a4d 01911e90 014123e8 0235fb68 asp!Execute+0x249

0235fb98 709e271a 00000000 00000000 00114c28 asp!CHitObj::ViperAsyncCallback+0x3e8

0235fbb4 75bd748e 01493048 00097be8 0235fd74 asp!CViperAsyncRequest::OnCall+0x92

0235fbd0 7770f153 00114c28 000a4178 00000000 COMSVCS!CSTAActivityWork::STAActivityWorkHelper+0x32

0235fc1c 7770fba0 00000000 000a4178 75bd745c ole32!EnterForCallback+0xc4

0235fd7c 777100aa 0235fc54 75bd745c 00114c28 ole32!SwitchForCallback+0x1a3

0235fda8 7769408c 000a4178 75bd745c 00114c28 ole32!PerformCallback+0x54

0235fe40 77712865 00097be8 75bd745c 00114c28 ole32!CObjectContext::InternalContextCallback+0x159

0235fe60 75bd7831 00097be8 75bd745c 00114c28 ole32!CObjectContext::DoCallback+0x1c

0235fecc 75bd7b95 00114e18 00114df8 001147c4 COMSVCS!CSTAActivityWork::DoWork+0x12d

0235fee4 75bd852e 00114c28 00000001 00114df8 COMSVCS!CSTAThread::DoWork+0x18

0235ff04 75bd897a 00000000 01eefcb0 00039608 COMSVCS!CSTAThread::ProcessQueueWork+0x37

0235ff84 77bcb530 00114df8 00000000 00000000 COMSVCS!CSTAThread::WorkerLoop+0x17c

0235ffb8 77e66063 00039608 00000000 00000000 msvcrt!_endthreadex+0xa3

0235ffec 00000000 77bcb4bc 00039608 00000000 kernel32!BaseThreadStart+0x34

Identify the function asp!Execute or asp!ExecuteRequest as above. If you have no symbols available and can’t see the function names in the stack, try to grab the third ASP function call loaded in the stack (that will be probably the one we need).

Now, grab the first parameter passed to this function (notice that for the functions Execute and ExecuteRequest it’s pretty much the same and that’s why it doesn’t really matter which function we will work with). Execute the following command on that:

0:032> du poi(poi(poi(01911e90 +9c)))

01ba32e8 "/WebSite001/mypage.asp"

As you can notice, it returns the relative path in the URL of the web site with the ASP page info there!

Now, if you just dump it with an offset of 4 bytes as below:

0:032> du poi(poi(poi(01911e90 +9c))+4)


It will return then the absolute path where the page is located in the file system.

So now you can identify which classic ASP page is being processed in a specific thread J  Have fun!