I wanted to implement a trivial profiling for my 64 bit application.
Reason is that sometimes the application "hangs" for several seconds
at a customer's site, and I would like to be able to get periodic
information about where the application's main thread currently is
(and get a small stack trace for information why the application is at
the current routine).
On profiling start, I do create a second thread which periodically
calls (here without error checks etc)
::SuspendThread(_hProfiledThread);
::GetThreadContext(_hProfiledThread,&CTX);
<and walk the stack using CTX, RtlLookupFunctionEntry and
RtlVirtualUnwind>
::ResumeThread(_hProfiledThread);
This works nicely until the profiled thread loads a library and is
suspended, because the profiler thread calls RtlLookupFunctionEntry(),
which tries to access the same synchronization object that the
LoadLibrary() call uses somewhere deep inside. For example:
Profiled thread (suspended):
ntdll.dll!RtlInsertInvertedFunctionTable() + 0x36f6e bytes (calling
RtlAcquireResourceExclusive)
ntdll.dll!LdrpMapDll() + 0x36e11 bytes
ntdll.dll!LdrpLoadDll() - 0x1a0ef bytes
ntdll.dll!LdrLoadDll() + 0x124 bytes
kernel32.dll!LoadLibraryExW() + 0x120 bytes
kernel32.dll!LoadLibraryA() + 0x86 bytes
...
Profiler thread (waiting for the FunctionTable synchronization
object):
ntdll.dll!NtWaitForSingleObject() + 0xa bytes
ntdll.dll!RtlAcquireResourceShared() - 0x1372c bytes
ntdll.dll!RtlLookupFunctionTable() + 0x4c413 bytes
ntdll.dll!RtlLookupFunctionEntry() + 0xab bytes
...
Is there a (more or less official) way to check whether that
synchonization object is "in use" in order to skip the profiling
"tick"?
Christian
> Is there a (more or less official) way to check whether that
> synchonization object is "in use" in order to skip the profiling
> "tick"?
Use windbg !locks command to get the name for the lock you're waiting
on.
It will likely be ntdll!LdrpLoaderLock which is a
_RTL_CRITICAL_SECTION.
Then change your profiler thread to either (a) check if the object is
locked
or (b) do a trylock on it
HTH,
Roger.
Christian
"rogero" <roge...@gmail.com> wrote in message
news:7070e7cb-c74f-417b...@m16g2000yqc.googlegroups.com...
For the record in the world wide web here it comes... ;-)
a) ASM file for WIN64 (to be compiled in VS using for example
"ml64.exe /Zi /c /nologo /Fo "$(OutDir)$(InputName).obj"
"$(InputPath)""):
PUBLIC __getPEB
.CODE
ALIGN 8
__getPEB PROC
mov rax, gs:[60h]
ret
__getPEB ENDP
END
b) declaration:
#if defined(WIN64)
extern "C"
{
void* __fastcall __getPEB();
}
#else
inline __declspec(naked) void* __getPEB()
{
__asm
{
mov eax, fs:[0x30]
ret
}
}
#endif
c) the final function:
bool clsLibInfo::IsLoaderLockActive()
{
#if defined(_M_AMD64)
RTL_CRITICAL_SECTION*
pLoaderLock(*(RTL_CRITICAL_SECTION**)(((BYTE*)__getPEB())+0x0110));
#else
#if defined(_M_IX86)
RTL_CRITICAL_SECTION*
pLoaderLock(*(RTL_CRITICAL_SECTION**)(((BYTE*)__getPEB())+0x00a0));
#else
#pragma error("unknown target")
#endif
#endif
if (!RtlTryEnterCriticalSection(pLoaderLock)) // from ntdll.dll
{
return(true);
}
RtlLeaveCriticalSection(pLoaderLock);
return(false);
}
OMG ;-)
Christian
"Christian Kaiser" <bc...@gmx.de> wrote in message
news:OiojjzUX...@TK2MSFTNGP04.phx.gbl...
I hope it's better now.
----
a) ASM file for WIN64 (to be compiled in VS using for example
"ml64.exe /Zi /c /nologo /Fo "$(OutDir)$(InputName).obj"
"$(InputPath)""):
PUBLIC __getPEB
.CODE
ALIGN 8
__getPEB PROC
mov rax, gs:[60h]
ret
__getPEB ENDP
END
b) declaration:
#if defined(_WIN64)
extern "C"
{
void* __fastcall __getPEB();
}
#else
inline __declspec(naked) void* __getPEB()
{
__asm
{
mov eax, fs:[0x30]
ret
}
}
#endif
c) the final function:
bool IsLoaderLockActive()
{
#if defined(_M_AMD64)
RTL_CRITICAL_SECTION*
pLoaderLock(*(RTL_CRITICAL_SECTION**)(((BYTE*)__getPEB())+0x0110));
#elif defined(_M_IX86)
RTL_CRITICAL_SECTION*
pLoaderLock(*(RTL_CRITICAL_SECTION**)(((BYTE*)__getPEB())+0x00a0));
#else
#pragma error("unknown target")
#endif
yes, the original code does load the NTDLL APIs dynamically, and (as
the lookup uses Windows API that uses the LoaderLock itself) they must
do that before calling the function ;-)
I'd prefer having direct "documented" access, but I did not find the
LdrpLoaderLock export in NTDLL, at least not using DEPENDS.EXE.
Getting the symbols would possibly mean to need DBGHELP et al on a
client's system, and the correct PDBs.
Christian
"rogero" <roge...@gmail.com> wrote in message
news:9baf50ca-da01-4463...@k17g2000yqb.googlegroups.com...