home *** CD-ROM | disk | FTP | other *** search
- /*
- * CallTrace.cpp - Java method call tracing tool.
- */
-
-
- /* Headers
- **********/
-
- #include <javadbg.h>
-
- #include <stdio.h>
-
-
- /* Constants
- ************/
-
- #define QUOTE '\''
- #define QUOTES '"'
- #define SPACE ' '
- #define TAB '\t'
-
-
- /* Macros
- *********/
-
- #define DECLARE_STANDARD_TYPES(type) typedef type *P##type; \
- typedef const type C##type; \
- typedef const type *PC##type;
-
- #define SAFE_CAST(type, obj) (((type)(obj) == (obj) ? 0 : 0), (type)(obj))
-
- #define WIN32_ERROR_TO_HRESULT(err) MAKE_SCODE(SEVERITY_ERROR, FACILITY_WIN32, (err))
-
- #define WIN32_RESULT_TO_HRESULT(err) ((err) == ERROR_SUCCESS ? S_OK : WIN32_ERROR_TO_HRESULT(err))
-
- #define LAST_WIN32_ERROR_TO_HRESULT() WIN32_RESULT_TO_HRESULT(GetLastError())
-
-
- /* Classes
- **********/
-
- typedef LPOLESTR POLESTR;
- typedef LPCOLESTR PCOLESTR;
-
- DECLARE_STANDARD_TYPES(IRemoteClassField);
- DECLARE_STANDARD_TYPES(IRemoteContainerField);
- DECLARE_STANDARD_TYPES(IRemoteContainerObject);
- DECLARE_STANDARD_TYPES(IRemoteDebugManager);
- DECLARE_STANDARD_TYPES(IRemoteDebugManagerCallback);
- DECLARE_STANDARD_TYPES(IRemoteField);
- DECLARE_STANDARD_TYPES(IRemoteMethodField);
- DECLARE_STANDARD_TYPES(IRemoteObject);
- DECLARE_STANDARD_TYPES(IRemoteProcess);
- DECLARE_STANDARD_TYPES(IRemoteProcessCallback);
- DECLARE_STANDARD_TYPES(IRemoteStackFrame);
- DECLARE_STANDARD_TYPES(IRemoteThread);
- DECLARE_STANDARD_TYPES(IRemoteThreadEx);
- DECLARE_STANDARD_TYPES(IRemoteThreadGroup);
-
- class RefCount;
- DECLARE_STANDARD_TYPES(RefCount);
-
- // Generic reference counting virtual base class.
-
- class RefCount
- {
- private:
-
- /* Fields
- *********/
-
- ULONG m_ulcRef;
-
- public:
-
- /* Methods
- **********/
-
- RefCount(void)
- {
- m_ulcRef = 1;
- }
-
- ~RefCount(void)
- {
- }
-
- // IUnknown methods
-
- // N.b., ulcRef is only guaranteed to match the new reference count in sign
- // and zero-ness.
-
- ULONG STDMETHODCALLTYPE AddRef(void)
- {
- return((ULONG)InterlockedIncrement((PLONG)&m_ulcRef));
- }
-
- ULONG STDMETHODCALLTYPE Release(void)
- {
- return((ULONG)InterlockedDecrement((PLONG)&m_ulcRef));
- }
- };
-
- class CallTracer;
- DECLARE_STANDARD_TYPES(CallTracer);
-
- class CallTracer : public RefCount,
- public IRemoteDebugManagerCallback,
- public IRemoteProcessCallback
- {
- private:
- /* Fields
- *********/
-
- PIRemoteDebugManager m_pirdm;
- PIRemoteProcess m_pirp;
- DWORD m_dwMsgLoopThreadID;
-
- /* Methods
- **********/
-
- UINT RunMessageLoop(void);
- BOOL QuitMessageLoop(UINT uResult);
- HRESULT DebugProcess(PCSTR pcszDebuggeeCmdLine);
- static PCSTR GetFRAMEKINDString(FRAMEKIND fk);
- static ULONG CountParentFrames(PIRemoteStackFrame pirsf);
- static HRESULT DumpContext(PIRemoteThread pirth);
-
- public:
- /* Methods
- **********/
-
- CallTracer(void);
- ~CallTracer(void);
-
- HRESULT Initialize(PIRemoteDebugManager pirdm);
- void Terminate(void);
- HRESULT Run(PCSTR pcszDebuggeeCmdLine);
-
- // IRemoteDebugManagerCallback methods
-
- STDMETHODIMP ProcessCreateEvent(PIRemoteProcess pirpNew, PIRemoteProcess pirpParent);
-
- // IRemoteProcessCallback methods
-
- STDMETHODIMP DebugStringEvent(PIRemoteThread pirth, PCOLESTR pcwszDebugMsg);
- STDMETHODIMP CodeBreakpointEvent(PIRemoteThread pirth);
- STDMETHODIMP DataBreakpointEvent(PIRemoteThread pirth, PIRemoteObject piro);
- STDMETHODIMP ExceptionEvent(PIRemoteThread pirth, PIRemoteClassField pircfException, EXCEPTIONKIND exk);
- STDMETHODIMP StepEvent(PIRemoteThread pirth);
- STDMETHODIMP CanStopEvent(PIRemoteThread pirth);
- STDMETHODIMP BreakEvent(PIRemoteThread pirth);
- STDMETHODIMP ThreadCreateEvent(PIRemoteThread pirth);
- STDMETHODIMP ThreadDestroyEvent(PIRemoteThread pirth);
- STDMETHODIMP ThreadGroupCreateEvent(PIRemoteThread pirth, PIRemoteThreadGroup pirthg);
- STDMETHODIMP ThreadGroupDestroyEvent(PIRemoteThread pirth, PIRemoteThreadGroup pirthg);
- STDMETHODIMP ClassLoadEvent(PIRemoteThread pirth, PIRemoteClassField pircfClass);
- STDMETHODIMP ClassUnloadEvent(PIRemoteThread pirth, PIRemoteClassField pircfClass);
- STDMETHODIMP ProcessDestroyEvent(PIRemoteThread pirth);
- STDMETHODIMP TraceEvent(PIRemoteThread pirth);
- STDMETHODIMP LoadCompleteEvent(PIRemoteThread pirth);
-
- // IUnknown methods
-
- ULONG STDMETHODCALLTYPE AddRef(void)
- {
- return(RefCount::AddRef());
- }
-
- // Wrap RefCount::Release() here so we don't need a virtual base class.
- ULONG STDMETHODCALLTYPE Release(void)
- {
- ULONG ulcRef;
-
- ulcRef = RefCount::Release();
-
- // N.b., there is a race condition here we're ignoring.
-
- if (! ulcRef)
- delete(this);
-
- return(ulcRef);
- }
-
- STDMETHODIMP QueryInterface(REFIID riid, PVOID *ppvObject);
- };
-
-
- /* Module Constants
- *******************/
-
- #pragma data_seg(".rdata")
-
- const char s_cszDebugKey[] = "Software\\Microsoft\\Java VM\\Debug";
-
- #pragma data_seg()
-
-
- /***************************** Private Functions *****************************/
-
-
- PCSTR SkipWhiteSpace(PCSTR pcsz)
- {
- while (*pcsz == SPACE ||
- *pcsz == TAB)
- pcsz = CharNext(pcsz);
-
- return(pcsz);
- }
-
-
- PCSTR SkipNonWhiteSpace(PCSTR pcsz)
- {
- while (*pcsz &&
- *pcsz != SPACE &&
- *pcsz != TAB)
- pcsz = CharNext(pcsz);
-
- return(pcsz);
- }
-
-
- PCSTR SkipQuotedArg(PCSTR pcsz)
- {
- char chQ;
-
- // Skip over quoted argument to matching quote.
-
- chQ = *pcsz;
- pcsz = CharNext(pcsz);
-
- while (*pcsz &&
- *pcsz != chQ)
- pcsz = CharNext(pcsz);
-
- if (*pcsz == chQ)
- pcsz = CharNext(pcsz);
-
- return(pcsz);
- }
-
-
- PCSTR SkipPossiblyQuotedArg(PCSTR pcsz)
- {
- pcsz = SkipWhiteSpace(pcsz);
-
- switch (*pcsz)
- {
- case QUOTE:
- case QUOTES:
- // Skip over quoted argument to matching quote.
- pcsz = SkipQuotedArg(pcsz);
- break;
-
- default:
- // Skip over unquoted argument.
- pcsz = SkipNonWhiteSpace(pcsz);
- break;
- }
-
- return(pcsz);
- }
-
-
- PCSTR GetDebuggeeCmdLine(PCSTR pcszCmdLine)
- {
- PCSTR pcszDebuggeeCmdLine;
-
- pcszDebuggeeCmdLine = SkipWhiteSpace(SkipPossiblyQuotedArg(pcszCmdLine));
-
- if (! *pcszDebuggeeCmdLine)
- pcszDebuggeeCmdLine = NULL;
-
- return(pcszDebuggeeCmdLine);
- }
-
-
- BOOL CreateDebugKey(void)
- {
- BOOL bResult;
- DWORD dwDisposition;
- HKEY hkeyDebug;
-
- bResult = (RegCreateKeyEx(HKEY_LOCAL_MACHINE, s_cszDebugKey, 0, NULL, 0, KEY_WRITE, NULL, &hkeyDebug, &dwDisposition)
- == ERROR_SUCCESS);
-
- if (bResult)
- RegCloseKey(hkeyDebug);
-
- return(bResult);
- }
-
-
- BOOL DeleteDebugKey(void)
- {
- return(RegDeleteKey(HKEY_LOCAL_MACHINE, s_cszDebugKey) == ERROR_SUCCESS);
- }
-
-
- /****************************** Public Functions *****************************/
-
-
- HRESULT RunDebugger(PCSTR pcszDebuggeeCmdLine)
- {
- HRESULT hr;
-
- hr = CoInitialize(NULL);
-
- if (SUCCEEDED(hr))
- {
- PIRemoteDebugManager pirdm;
-
- hr = CoCreateInstance(CLSID_RemoteJavaDebugManager, NULL, CLSCTX_LOCAL_SERVER, IID_IRemoteDebugManager, (PVOID *)&pirdm);
-
- if (hr == S_OK)
- {
- PCallTracer pct;
-
- pct = new(CallTracer);
-
- if (pct)
- {
- hr = pct->Initialize(pirdm);
-
- if (hr == S_OK)
- {
- hr = pct->Run(pcszDebuggeeCmdLine);
-
- pct->Terminate();
- }
-
- pct->Release();
- pct = NULL;
- }
- else
- hr = E_OUTOFMEMORY;
-
- pirdm->Release();
- pirdm = NULL;
- }
-
- CoUninitialize();
- }
-
- return(hr);
- }
-
-
- #pragma warning(disable:4100) // "unreferenced formal parameter" warning
-
- int __cdecl main(int argc, char *argv[])
- {
- HRESULT hr = E_FAIL;
- PCSTR pcszDebuggeeCmdLine;
-
- printf("Java method call tracing application.\n\n");
-
- pcszDebuggeeCmdLine = GetDebuggeeCmdLine(GetCommandLine());
-
- if (pcszDebuggeeCmdLine)
- hr = RunDebugger(pcszDebuggeeCmdLine);
-
- return(hr);
- }
-
- #pragma warning(default:4100) // "unreferenced formal parameter" warning
-
-
- /********************************** Methods **********************************/
-
-
- CallTracer::CallTracer(void)
- {
- m_pirdm = NULL;
- m_pirp = NULL;
- m_dwMsgLoopThreadID = 0;
- }
-
-
- CallTracer::~CallTracer(void)
- {
- Terminate();
- }
-
-
- HRESULT CallTracer::Initialize(PIRemoteDebugManager pirdm)
- {
- HRESULT hr;
-
- hr = pirdm->RegisterCallback(this);
-
- if (hr == S_OK)
- {
- m_pirdm = pirdm;
- m_pirdm->AddRef();
- }
-
- return(hr);
- }
-
-
- void CallTracer::Terminate(void)
- {
- if (m_pirdm)
- {
- m_pirdm->Detach();
-
- m_pirdm->Release();
- m_pirdm = NULL;
- }
- }
-
-
- UINT CallTracer::RunMessageLoop(void)
- {
- UINT uResult;
- MSG msg;
-
- // No accelerators to load.
-
- // Get and dispatch messages until a WM_QUIT message is received.
-
- m_dwMsgLoopThreadID = GetCurrentThreadId();
-
- ZeroMemory(&msg, sizeof(msg));
-
- while (GetMessage(&msg, NULL, 0, 0))
- {
- TranslateMessage(&msg);
- DispatchMessage(&msg);
- }
-
- m_dwMsgLoopThreadID = 0;
-
- uResult = msg.wParam;
-
- return(uResult);
- }
-
-
- BOOL CallTracer::QuitMessageLoop(UINT uResult)
- {
- return(PostThreadMessage(m_dwMsgLoopThreadID, WM_QUIT, uResult, 0));
- }
-
-
- HRESULT CallTracer::DebugProcess(PCSTR pcszDebuggeeCmdLine)
- {
- HRESULT hr = E_FAIL;
- STARTUPINFO si;
- PROCESS_INFORMATION pi;
-
- ZeroMemory(&si, sizeof(si));
- si.cb = sizeof(si);
-
- if (CreateProcess(NULL, (PSTR)pcszDebuggeeCmdLine, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi))
- {
- hr = m_pirdm->RequestCreateEvent(L"", pi.dwProcessId);
-
- if (SUCCEEDED(hr))
- {
- if (ResumeThread(pi.hThread) == 0xffffffff)
- hr = E_FAIL;
- }
-
- CloseHandle(pi.hProcess);
- CloseHandle(pi.hThread);
-
- RunMessageLoop();
- }
-
- return(hr);
- }
-
-
- HRESULT CallTracer::Run(PCSTR pcszDebuggeeCmdLine)
- {
- HRESULT hr;
-
- if (CreateDebugKey())
- {
- hr = DebugProcess(pcszDebuggeeCmdLine);
-
- DeleteDebugKey();
- }
- else
- hr = LAST_WIN32_ERROR_TO_HRESULT();
-
- return(hr);
- }
-
-
- // static
- PCSTR CallTracer::GetFRAMEKINDString(FRAMEKIND fk)
- {
- PCSTR pcsz;
-
- switch (fk)
- {
- case FRAME_KIND_JIT_COMPILED:
- pcsz = "JIT";
- break;
-
- case FRAME_KIND_NATIVE:
- pcsz = "native";
- break;
-
- case FRAME_KIND_COM:
- pcsz = "COM";
- break;
-
- case FRAME_KIND_INTERPRETED:
- pcsz = "interpreted";
- break;
-
- case FRAME_KIND_FAST_INTERPRETED:
- pcsz = "fast interpreted";
- break;
-
- case FRAME_KIND_INVALID:
- pcsz = "INVALID";
- break;
-
- default:
- pcsz = "UNRECOGNIZED FRAMEKIND";
- break;
- }
-
- return(pcsz);
- }
-
-
- // static
- ULONG CallTracer::CountParentFrames(PIRemoteStackFrame pirsf)
- {
- ULONG ulcFrames = 0;
-
- if (pirsf)
- {
- pirsf->AddRef();
-
- do
- {
- HRESULT hr;
- PIRemoteStackFrame pirsfParent;
-
- hr = pirsf->GetCallingFrame(&pirsfParent);
- pirsf->Release();
-
- if (hr == S_OK &&
- pirsfParent)
- {
- ulcFrames++;
- pirsf = pirsfParent;
- }
- else
- break;
-
- } while (pirsf);
- }
-
- return(ulcFrames);
- }
-
-
- // static
- HRESULT CallTracer::DumpContext(PIRemoteThread pirth)
- {
- HRESULT hr;
- PIRemoteThreadEx pirthex;
-
- hr = pirth->QueryInterface(IID_IRemoteThreadEx, (PVOID *)&pirthex);
-
- if (hr == S_OK)
- {
- ULONG ulThreadID;
-
- hr = pirthex->GetThreadId(&ulThreadID);
-
- if (hr == S_OK)
- {
- PIRemoteStackFrame pirsf;
-
- hr = pirthex->GetCurrentFrame(&pirsf);
-
- if (hr == S_OK)
- {
- FRAMEKIND fk;
-
- hr = pirsf->GetKind(&fk);
-
- if (hr == S_OK)
- {
- PIRemoteContainerObject pirco;
-
- hr = pirsf->GetMethodObject(&pirco);
-
- if (hr == S_OK)
- {
- PIRemoteField pirf;
-
- hr = pirco->GetType(&pirf);
-
- if (hr == S_OK)
- {
- PIRemoteMethodField pirmf;
-
- hr = pirf->QueryInterface(IID_IRemoteMethodField, (PVOID *)&pirmf);
-
- if (hr == S_OK)
- {
- POLESTR pwszMethodName;
-
- hr = pirmf->GetName(&pwszMethodName);
-
- if (hr == S_OK)
- {
- PIRemoteContainerField pircf;
-
- hr = pirmf->GetContainer(&pircf);
-
- if (hr == S_OK)
- {
- POLESTR pwszClassName;
-
- hr = pircf->GetName(&pwszClassName);
-
- if (hr == S_OK)
- {
- ULONG ulcDepth = CountParentFrames(pirsf);
- ULONG uli;
-
- for (uli = 0; uli < ulcDepth; uli++)
- printf(" ");
-
- printf("%lxh [%s] %ls.%ls()\n",
- ulThreadID,
- GetFRAMEKINDString(fk),
- pwszClassName,
- pwszMethodName);
-
- CoTaskMemFree(pwszClassName);
- pwszClassName = NULL;
- }
-
- pircf->Release();
- pircf = NULL;
- }
-
- CoTaskMemFree(pwszMethodName);
- pwszMethodName = NULL;
- }
-
- pirmf->Release();
- pirmf = NULL;
- }
-
- pirf->Release();
- pirf = NULL;
- }
-
- pirco->Release();
- pirco = NULL;
- }
- }
-
- pirsf->Release();
- pirsf = NULL;
- }
- }
-
- pirthex->Release();
- pirthex = NULL;
- }
-
- return(hr);
- }
-
-
- // IUnknown methods
-
- STDMETHODIMP CallTracer::QueryInterface(REFIID riid, PVOID *ppvObject)
- {
- HRESULT hr = S_OK;
-
- if (riid == IID_IRemoteDebugManagerCallback)
- *ppvObject = SAFE_CAST(PIRemoteDebugManagerCallback, this);
- else if (riid == IID_IUnknown ||
- riid == IID_IRemoteProcessCallback)
- *ppvObject = SAFE_CAST(PIRemoteProcessCallback, this);
- else
- {
- *ppvObject = NULL;
- hr = E_NOINTERFACE;
- }
-
- if (hr == S_OK)
- AddRef();
-
- return(hr);
- }
-
-
- // IRemoteDebugManagerCallback methods
-
- #pragma warning(disable:4100) // "unreferenced formal parameter" warning
-
- STDMETHODIMP CallTracer::ProcessCreateEvent(PIRemoteProcess pirpNew, PIRemoteProcess pirpParent)
- {
- if (pirpNew->RegisterCallback(this) == S_OK)
- {
- m_pirp = pirpNew;
- m_pirp->AddRef();
-
- m_pirp->TraceMethods(TRUE);
- }
-
- DeleteDebugKey();
-
- return(S_FALSE);
- }
-
-
- // IRemoteProcessCallback methods
-
- STDMETHODIMP CallTracer::ProcessDestroyEvent(PIRemoteThread pirth)
- {
- m_pirp->Detach();
- m_pirp->Release();
- m_pirp = NULL;
-
- QuitMessageLoop(0);
-
- return(S_FALSE);
- }
-
-
- STDMETHODIMP CallTracer::TraceEvent(PIRemoteThread pirth)
- {
- DumpContext(pirth);
-
- return(S_FALSE);
- }
-
-
- STDMETHODIMP CallTracer::DebugStringEvent(PIRemoteThread pirth, PCOLESTR pcwszDebugMsg)
- {
- return(S_FALSE);
- }
-
-
- STDMETHODIMP CallTracer::CodeBreakpointEvent(PIRemoteThread pirth)
- {
- return(S_FALSE);
- }
-
-
- STDMETHODIMP CallTracer::DataBreakpointEvent(PIRemoteThread pirth, PIRemoteObject piro)
- {
- return(S_FALSE);
- }
-
-
- STDMETHODIMP CallTracer::ExceptionEvent(PIRemoteThread pirth, PIRemoteClassField pircfException, EXCEPTIONKIND exk)
- {
- return(S_FALSE);
- }
-
-
- STDMETHODIMP CallTracer::StepEvent(PIRemoteThread pirth)
- {
- return(S_FALSE);
- }
-
-
- STDMETHODIMP CallTracer::CanStopEvent(PIRemoteThread pirth)
- {
- return(S_FALSE);
- }
-
-
- STDMETHODIMP CallTracer::BreakEvent(PIRemoteThread pirth)
- {
- return(S_FALSE);
- }
-
-
- STDMETHODIMP CallTracer::ThreadCreateEvent(PIRemoteThread pirth)
- {
- return(S_FALSE);
- }
-
-
- STDMETHODIMP CallTracer::ThreadDestroyEvent(PIRemoteThread pirth)
- {
- return(S_FALSE);
- }
-
-
- STDMETHODIMP CallTracer::ThreadGroupCreateEvent(PIRemoteThread pirth, PIRemoteThreadGroup pirthg)
- {
- return(S_FALSE);
- }
-
-
- STDMETHODIMP CallTracer::ThreadGroupDestroyEvent(PIRemoteThread pirth, PIRemoteThreadGroup pirthg)
- {
- return(S_FALSE);
- }
-
-
- STDMETHODIMP CallTracer::ClassLoadEvent(PIRemoteThread pirth, PIRemoteClassField pircfClass)
- {
- return(S_FALSE);
- }
-
-
- STDMETHODIMP CallTracer::ClassUnloadEvent(PIRemoteThread pirth, PIRemoteClassField pircfClass)
- {
- return(S_FALSE);
- }
-
-
- STDMETHODIMP CallTracer::LoadCompleteEvent(PIRemoteThread pirth)
- {
- return(S_FALSE);
- }
-
- #pragma warning(default:4100) // "unreferenced formal parameter" warning
-
-