[Windbg Script] Serviced Components
A few days ago a friend of mine, Fabrício Catae, a SQL Server Ranger here at Microsoft, gave me an idea: to create a script that shows if Serviced Components are or are not disposed.
I thought it was a great idea, so I decided to create a script for it. During the development I added more features related to Serviced Components.
Basically this script gives you the following information related to Serviced Components:
- Object Pooled (Not Pooled)
- Jit Activated (Not Activated)
- Use Interface IDispatch (Not using IDispatch)
- Server Activated (Not Activated)
- Active (Not Active)
- Finalized (Not Finalized)
- Returned By Finalizer (Not Returned By Finalizer)
- Disposed (Not Disposed)
Note: I didn’t have an opportunity to stress this script in the trenches. It might have hidden bugs. If you find something, please, let me know and I’ll fix it.
Note 2: The next article will be about books to help you improve or acquire debugging skills.
Screenshots:
Source code for SERVICED_COMPONENTS.TXT:
$$
$$ =============================================================================
$$ Get details from Serviced Components, like:
$$ - Object Pooled
$$ - Jit Activated
$$ - Use Interface IDispatch
$$ - Server Activated
$$ - Active
$$ - Finalized
$$ - Returned By Finalizer
$$ - Disposed
$$
$$ Compatibility: Win32.
$$
$$ Usage: $$>< to run the program.
$$
$$ Attention! If you get a syntax error if calling it a 2nd time, run ad /q * then
$$ call the script again.
$$
$$ Requirements: Public symbols.
$$
$$ If necessary change the filename below to include your path and filename.
$$ By default it uses the WinDbg path and the default file name is SERVICED_COMPONENTS.TXT
$$
$$ Roberto Alexis Farah
$$ Blog: https://blogs.msdn.com/debuggingtoolbox/
$$
$$ All my scripts are provided "AS IS" with no warranties, and confer no rights.
$$ =============================================================================
$$
r @$t0 = 0
ad /q *
.block
{
as ScriptName MYSCRIPTS\\SERVICED_COMPONENTS.TXT
}
.block
{
.block
{
as ObjectPooled .block
{
.block
{
j (0 = @$t0) '.printf /D "<b>\nObjects Pooled\n\n</b>"';'.printf /D "<b>\nObjects NOT Pooled\n\n</b>"'
}
.foreach(obj { !dumpheap -type *ServicedComponentProxy -short })
{
r @$t1 = poi(${obj}+0xC)
.if(0 != @$t1)
{
r @$t2 = poi(${obj}+0x34)
.if(0 = @$t0)
{
.if(@$t2 & 0x1)
{
.printf /D "<b>\nObject address: 0x%x\n</b>", ${obj}
!do @$t1
.printf "\n###############################################################################\n"
}
}
.else
{
.if(0 = (@$t2 & 0x1))
{
.printf /D "<b>\nObject address: 0x%x\n</b>", ${obj}
!do @$t1
.printf "\n###############################################################################\n"
}
}
}
}
}
}
.block
{
as IsJitActivated .block
{
.block
{
j (0 = @$t0) '.printf /D "<b>\nJIT Activated\n\n</b>"';'.printf /D "<b>\nJIT NOT Activated\n\n</b>"'
}
.foreach(obj { !dumpheap -type *ServicedComponentProxy -short })
{
r @$t1 = poi(${obj}+0xC)
.if(0 != @$t1)
{
r @$t2 = poi(${obj}+0x35)
.if(0 = @$t0)
{
.if(@$t2 & 0x1)
{
.printf /D "<b>\nObject address: 0x%x\n</b>", ${obj}
!do @$t1
.printf "\n###############################################################################\n"
}
}
.else
{
.if(0 = (@$t2 & 0x1))
{
.printf /D "<b>\nObject address: 0x%x\n</b>", ${obj}
!do @$t1
.printf "\n###############################################################################\n"
}
}
}
}
}
}
.block
{
as UseInterfaceIDispatch .block
{
.block
{
j (0 = @$t0) '.printf /D "<b>\nUsing Interface IDispatch\n\n</b>"';'.printf /D "<b>\nNOT Using Interface IDispatch\n\n</b>"'
}
.foreach(obj { !dumpheap -type *ServicedComponentProxy -short })
{
r @$t1 = poi(${obj}+0xC)
.if(0 != @$t1)
{
r @$t2 = poi(${obj}+0x37)
.if(0 = @$t0)
{
.if(@$t2 & 0x1)
{
.printf /D "<b>\nObject address: 0x%x\n</b>", ${obj}
!do @$t1
.printf "\n###############################################################################\n"
}
}
.else
{
.if(0 = (@$t2 & 0x1))
{
.printf /D "<b>\nObject address: 0x%x\n</b>", ${obj}
!do @$t1
.printf "\n###############################################################################\n"
}
}
}
}
}
}
.block
{
as IsServerActivated .block
{
.block
{
j (0 = @$t0) '.printf /D "<b>\nServer Is Activated\n\n</b>"';'.printf /D "<b>\nServer Is NOT Activated\n\n</b>"'
}
.foreach(obj { !dumpheap -type *ServicedComponentProxy -short })
{
r @$t1 = poi(${obj}+0xC)
.if(0 != @$t1)
{
r @$t2 = poi(${obj}+0x38)
.if(0 = @$t0)
{
.if(@$t2 & 0x1)
{
.printf /D "<b>Object address: 0x%x\n</b>", ${obj}
!do @$t1
.printf "\n###############################################################################\n"
}
}
.else
{
.if(0 = (@$t2 & 0x1))
{
.printf /D "<b>Object address: 0x%x\n</b>", ${obj}
!do @$t1
.printf "\n###############################################################################\n"
}
}
}
}
}
}
.block
{
as IsActive .block
{
.block
{
j (0 = @$t0) '.printf /D "<b>\nIs Active\n\n</b>"';'.printf /D "<b>\nIs NOT Active\n\n</b>"'
}
.foreach(obj { !dumpheap -type *ServicedComponentProxy -short })
{
r @$t1 = poi(${obj}+0xC)
.if(0 != @$t1)
{
r @$t2 = poi(${obj}+0x39)
.if(0 = @$t0)
{
.if(@$t2 & 0x1)
{
.printf /D "<b>Object address: 0x%x\n</b>", ${obj}
!do @$t1
.printf "\n###############################################################################\n"
}
}
.else
{
.if(0 = (@$t2 & 0x1))
{
.printf /D "<b>Object address: 0x%x\n</b>", ${obj}
!do @$t1
.printf "\n###############################################################################\n"
}
}
}
}
}
}
.block
{
as IsFinalized .block
{
.block
{
j (0 = @$t0) '.printf /D "<b>\nIs Finalized\n\n</b>"';'.printf /D "<b>\nIs NOT Finalized\n\n</b>"'
}
.foreach(obj { !dumpheap -type *ServicedComponentProxy -short })
{
r @$t1 = poi(${obj}+0xC)
.if(0 != @$t1)
{
r @$t2 = poi(${obj}+0x3B)
.if(0 = @$t0)
{
.if(@$t2 & 0x1)
{
.printf /D "<b>Object address: 0x%x\n</b>", ${obj}
!do @$t1
.printf "\n###############################################################################\n"
}
}
.else
{
.if(0 = (@$t2 & 0x1))
{
.printf /D "<b>Object address: 0x%x\n</b>", ${obj}
!do @$t1
.printf "\n###############################################################################\n"
}
}
}
}
}
}
.block
{
as ReturnedByFinalizer .block
{
.block
{
j (0 = @$t0) '.printf /D "<b>\nReturned by Finalizer\n\n</b>"';'.printf /D "<b>\nNOT Returned by Finalizer\n\n</b>"'
}
.foreach(obj { !dumpheap -type *ServicedComponentProxy -short })
{
r @$t1 = poi(${obj}+0xC)
.if(0 != @$t1)
{
r @$t2 = poi(${obj}+0x3B)
.if(0 = @$t0)
{
.if(@$t2 & 0x1)
{
.printf /D "<b>Object address: 0x%x\n</b>", ${obj}
!do @$t1
.printf "\n###############################################################################\n"
}
}
.else
{
.if(0 = (@$t2 & 0x1))
{
.printf /D "<b>Object address: 0x%x\n</b>", ${obj}
!do @$t1
.printf "\n###############################################################################\n"
}
}
}
}
}
}
.block
{
as Disposed .block
{
.block
{
j (0 = @$t0) '.printf /D "<b>\nDisposed\n\n</b>"';'.printf /D "<b>\nNOT Disposed\n\n</b>"'
}
.foreach(obj { !dumpheap -type *ServicedComponentProxy -short })
{
r @$t1 = poi(${obj}+0xC)
.if(0 != @$t1)
{
r @$t2 = poi(@$t1+0xD)
.if(0 = @$t0)
{
.if(@$t2 & 0x1)
{
.printf /D "<b>Object address: 0x%x\n</b>", ${obj}
!do @$t1
.printf "\n###############################################################################\n"
}
}
.else
{
.if(0 = (@$t2 & 0x1))
{
.printf /D "<b>Object address: 0x%x\n</b>", ${obj}
!do @$t1
.printf "\n###############################################################################\n"
}
}
}
}
}
}
}
.printf /D "\n\n<b>Select the filters below to see the Serviced Components that match the selection:</b>\n\n"
.printf /D "<link cmd=\"r @$t0 = 0; ${ObjectPooled} ad /q *; $$><${ScriptName}\"><b>Objects Pooled</b></link>"
.printf /D "\t\t\t\t<link cmd=\"r @$t0 = 1; ${ObjectPooled} ad /q *; $$><${ScriptName}\"><b>Objects NOT Pooled</b></link>\n\n"
.printf /D "<link cmd=\"r @$t0 = 0; ${IsJitActivated} ad /q *; $$><${ScriptName}\"><b>JIT Activated</b></link>"
.printf /D "\t\t\t\t<link cmd=\"r @$t0 = 1; ${IsJitActivated} ad /q *; $$><${ScriptName}\"><b>JIT NOT Activated</b></link>\n\n"
.printf /D "<link cmd=\"r @$t0 = 0; ${UseInterfaceIDispatch} ad /q *; $$><${ScriptName}\"><b>Using Interface IDispatch</b></link>"
.printf /D "\t\t<link cmd=\"r @$t0 = 1; ${UseInterfaceIDispatch} ad /q *; $$><${ScriptName}\"><b>NOT Using Interface IDispatch</b></link>\n\n"
.printf /D "<link cmd=\"r @$t0 = 0; ${IsServerActivated} ad /q *; $$><${ScriptName}\"><b>Server Is Activated</b></link>"
.printf /D "\t\t\t<link cmd=\"r @$t0 = 1; ${IsServerActivated} ad /q *; $$><${ScriptName}\"><b>Server Is NOT Activated</b></link>\n\n"
.printf /D "<link cmd=\"r @$t0 = 0; ${IsActive} ad /q *; $$><${ScriptName}\"><b>Is Active</b></link>"
.printf /D "\t\t\t\t\t<link cmd=\"r @$t0 = 1; ${IsActive} ad /q *; $$><${ScriptName}\"><b>Is NOT Active</b></link>\n\n"
.printf /D "<link cmd=\"r @$t0 = 0; ${IsFinalized} ad /q *; $$><${ScriptName}\"><b>Is Finalized</b></link>"
.printf /D "\t\t\t\t<link cmd=\"r @$t0 = 1; ${IsFinalized} ad /q *; $$><${ScriptName}\"><b>Is NOT Finalized</b></link>\n\n"
.printf /D "<link cmd=\"r @$t0 = 0; ${ReturnedByFinalizer} ad /q *; $$><${ScriptName}\"><b>Returned by Finalizer</b></link>"
.printf /D "\t\t\t<link cmd=\"r @$t0 = 1; ${ReturnedByFinalizer} ad /q *; $$><${ScriptName}\"><b>NOT Returned by Finalizer</b></link>\n\n"
.printf /D "<link cmd=\"r @$t0 = 0; ${Disposed} ad /q *; $$><${ScriptName}\"><b>Disposed Serviced Components</b></link>"
.printf /D "\t<link cmd=\"r @$t0 = 1; ${Disposed} ad /q *; $$><${ScriptName}\"><b>NOT Disposed Serviced Components</b></link>\n\n"
$$
Comments
Anonymous
June 05, 2007
Eagerly awaiting your next article about books on improving debugging skills!Anonymous
June 05, 2007
Cool !!! Um dia vou ser assim também! []'sAnonymous
June 06, 2007
Bacana! Estou na espera pela indicação dos livros! Alias, 'Debugging .NET 2.0 Applications' do John Robbins é nota 10. []s