#include "itsutils.h" #include "debug.h" #include "util/process.h" #include "util/queuebuf.h" #include "cenk.h" #include "stringutils.h" #include "cever_deps.h" #include #include "utfcvutils.h" //---------------------debugger---------------------------------- typedef struct _tagDebugEvent { DWORD dwProcessId; DWORD dwThreadId; DWORD dwDebugEventCode; int len; // note: -1 means: final event char *description; } DebugEvent; #define MAX_DEBUG_EVENTS 256 class textbuffer { size_t _max; size_t _minreserve; size_t _wr; char *_buf; boost::mutex _mtx; public: textbuffer(size_t totalsize, size_t minreserve) : _max(totalsize), _minreserve(minreserve), _buf(new char[_max]), _wr(0) { } ~textbuffer() { delete _buf; debug("destructing textbuffer\n"); } char *newptr(size_t& maxstr) { boost::mutex::scoped_lock lock(_mtx); if (_wr+_minreserve > _max) _wr= 0; maxstr= _max-_wr; return _buf+_wr; } void commit(char *ptr, size_t n) { boost::mutex::scoped_lock lock(_mtx); if (ptr==_buf+_wr) _wr += n; } }; int ParseDebugEvent(char *buf, int bufsize, DEBUG_EVENT *event); class DebuggerInfo : public process { public: DebuggerInfo(DWORD procid, const std::string& exename, const std::string& cmdline, bool bFilterProc, bool bSysOnly) : _procstarted(false), _result(0), _queue(256, "debugevents"), _textbuf(1024*256, 1024), _processid(procid), _exename(exename), _cmdline(cmdline), _bFilterForProcess(bFilterProc), _bSysMessagesOnly(bSysOnly) { _result= 0; _missedEvents= 0; _dll= LoadLibrary(_T("ItsUtils.dll")); if (_dll==NULL) { _result= GetLastError(); terminateservice(); } start(); } ~DebuggerInfo() { stop(); FreeLibrary(_dll); debug("destructed DebuggerInfo\n"); } virtual const char*name() { return "debugger"; } virtual void processstop() { DebugEvent ev; ev.dwProcessId= 0; ev.dwThreadId= 0; ev.dwDebugEventCode= 0; ev.len= -1; _queue.write(&ev, 1); } virtual void service() { DWORD res=0; // on the smartphone, and wm2005 the setkmode is nescesary // on ppc2003 it is not. BOOL bMode = SetKMode(TRUE); DWORD dwPerm = SetProcPermissions(0xFFFFFFFF); //debug("DebugThreadProc started\n"); // either use provided pid, or start new process if (_processid!=0) { if (!DebugActiveProcess(_processid)) { res= _result= GetLastError(); } } else { PROCESS_INFORMATION pi; if (!CreateProcess(ToTString(_exename).c_str(), ToTString(_cmdline).c_str(), NULL, NULL, 0, DEBUG_PROCESS, NULL, NULL, NULL, &pi)) { res= _result= GetLastError(); } else { _processid= pi.dwProcessId; CloseHandle(pi.hProcess); CloseHandle(pi.hThread); } } notify_proc_started(); DEBUG_EVENT ev; // loop until a 'stopped' event is created while(!res && !isterminating()) { if (WaitForDebugEvent(&ev, 100)) { if (!_bSysMessagesOnly || ev.dwDebugEventCode!=OUTPUT_DEBUG_STRING_EVENT) if (!_bFilterForProcess || ev.dwProcessId==_processid) if (!ProcessDebugEvent(&ev)) _missedEvents++; // todo: process breakpoints if (!ContinueDebugEvent(ev.dwProcessId, ev.dwThreadId, DBG_EXCEPTION_NOT_HANDLED )) res= _result= GetLastError(); } else if (GetLastError()==WAIT_TIMEOUT) { // continue - timeout is used to check if we need to stop } else { error("WaitForDebugEvent %08lx", GetLastError()); break; } } debug("stopping debugloop"); terminateservice(); } size_t getmissed() { size_t n= _missedEvents; _missedEvents= 0; return n; } void notify_proc_started() { boost::mutex::scoped_lock lock(_mtx); _procstarted= true; _cond.notify_one(); } bool waitforstart() { boost::mutex::scoped_lock lock(_mtx); while (!_procstarted && !isterminating()) _cond.wait(lock); return _result==0; } void stopdebugging() { stop(); } bool ProcessDebugEvent(DEBUG_EVENT *sysev) { if (!_queue.freesize()) return false; DebugEvent ev; ev.dwProcessId= sysev->dwProcessId; ev.dwThreadId= sysev->dwThreadId; ev.dwDebugEventCode= sysev->dwDebugEventCode; size_t maxstr; ev.description= _textbuf.newptr(maxstr); ev.len= ParseDebugEvent(ev.description, maxstr, sysev); _textbuf.commit(ev.description, ev.len); _queue.write(&ev, 1); // todo: test sysev.ExceptionRecord.ExceptionFlags&EXCEPTION_NONCONTINUABLE return true; } bool GetDebugEvent(DebugEvent *ev) { try { _queue.read(ev, 1); } catch(const char*msg) { printf("GetDebugEvent::read -> ERROR %s\n", msg); return false; } catch(...) { printf("GetDebugEvent::read -> ERROR\n"); return false; } return true; } private: bool _procstarted; boost::condition _cond; boost::mutex _mtx; DWORD _result; DWORD _processid; bool _bFilterForProcess; bool _bSysMessagesOnly; std::string _exename; std::string _cmdline; HMODULE _dll; // used to retain itsutils.dll in memory DWORD _missedEvents; queuebuf _queue; textbuffer _textbuf; }; ITSUTILS_API HRESULT STDAPICALLTYPE ITStartDebuggingProcess( DWORD cbInput, StartDebuggingProcessParams *pbInput, DWORD *pcbOutput, StartDebuggingProcessResult **ppbOutput, IRAPIStream *pStream) { DWORD res= 0; *pcbOutput= 0; *ppbOutput= NULL; debug("itsutils debugger starting\n"); DebuggerInfo *di= new DebuggerInfo(pbInput->dwProcessId, pbInput->exename, pbInput->cmdline, pbInput->bFilterForProcess, pbInput->bSysMessagesOnly); if (!di->waitforstart()) { debug("error starting debugger\n"); return -1; } *pcbOutput= sizeof(StartDebuggingProcessResult); StartDebuggingProcessResult *pOut= *ppbOutput= (StartDebuggingProcessResult *)LocalAlloc(LPTR, *pcbOutput); pOut->debugger= (DWORD)di; debug("itsutils debugger started\n"); return 0; } ITSUTILS_API HRESULT STDAPICALLTYPE ITStopDebuggingProcess( DWORD cbInput, StopDebuggingProcessParams *pbInput, DWORD *pcbOutput, StopDebuggingProcessResult **ppbOutput, IRAPIStream *pStream) { DebuggerInfo *di= (DebuggerInfo *)pbInput->debugger; *pcbOutput= 0; *ppbOutput= NULL; debug("itsutils debugger stopping\n"); di->stopdebugging(); delete di; debug("itsutils debugger stopped\n"); return 0; } ITSUTILS_API HRESULT STDAPICALLTYPE ITWaitForDebugEvent( DWORD cbInput, WaitForDebugEventParams *pbInput, DWORD *pcbOutput, WaitForDebugEventResult **ppbOutput, IRAPIStream *pStream) { DWORD res=0; DebuggerInfo *di= (DebuggerInfo *)pbInput->debugger; *pcbOutput= 0; *ppbOutput= NULL; DebugEvent ev; if (!di->GetDebugEvent(&ev)) { debug("ITWaitForDebugEvent : error getting debugevent\n"); di->stopdebugging(); return -1; } if (ev.len==-1) { debug("ITWaitForDebugEvent : final event\n"); di->stopdebugging(); return -1; } *pcbOutput= sizeof(WaitForDebugEventResult)+ev.len; WaitForDebugEventResult *pOut= *ppbOutput= (WaitForDebugEventResult *)LocalAlloc(LPTR, *pcbOutput); pOut->dwProcessId= ev.dwProcessId; pOut->dwThreadId= ev.dwThreadId; pOut->dwDebugEventCode= ev.dwDebugEventCode; pOut->len= ev.len; memcpy(pOut->description, ev.description, ev.len+1); pOut->dwMissedEvents= di->getmissed(); return res; } /* struct breakpoint { DWORD originsn; DWORD type; DWORD addr; }; std::map bplist; bool SetBreakPoint(HANDLE hProc, DWORD dwAddr, int type) { DWORD bptinsn= 0xe6000001; DWORD originsn; DWORD nProcessed; if (bplist.find(dwAddr)!=bplist.end()) { // breakpoint already set return false; } if (!ReadProcessMemory(hProc, dwAddr, &originsn, sizeof(originsn), &nProcessed)) return false; if (!WriteProcessMemory(hProc, dwAddr, &bptinsn, sizeof(bptinsn), &nProcessed)) return false; bplist[dwAddr]= breakpoint(originsn, type, dwAddr); } bool RemoveBreakPoint(HANDLE hProc, DWORD dwAddr) { DWORD bptinsn= 0xe6000001; DWORD originsn; DWORD nProcessed; if (bplist.find(dwAddr)==bplist.end()) { // error: breakpoint did not exist. return false; } if (!ReadProcessMemory(hProc, dwAddr, &originsn, sizeof(originsn), &nProcessed)) return false; if (originsn!=bptinsn) { // breakpoint no longer there!! bplist.remove(dwAddr); return false; } if (!WriteProcessMemory(hProc, dwAddr, &bplist[dwAddr].originsn, sizeof(DWORD), &nProcessed)) return false; bplist.remove(dwAddr); return true; } void ProcessTasks(iterator begin, iterator end) { for (iterator i=begin ; i!=end ; ++i) { switch((*i).action) { case DBG_ADDBREAKPOINT: SetBreakPoint((*i).proc, (*i).addr, BP_BREAKPOINT); break; case DBG_REMOVEBREAKPOINT: RemoveBreakPoint((*i).proc, (*i).addr); break; case DBG_ADDTRACE: SetBreakPoint((*i).proc, (*i).addr1, BP_STARTTRACE); SetBreakPoint((*i).proc, (*i).addr2, BP_ENDTRACE); break; } } } */ //--------------converting a debug event to a string int ParseDebugException(char *buf, int bufsize, DWORD dwProcessId, DWORD dwThreadId, EXCEPTION_DEBUG_INFO *exception); int ParseDebugCreateThread(char *buf, int bufsize, DWORD dwProcessId, DWORD dwThreadId, CREATE_THREAD_DEBUG_INFO *createThread); int ParseDebugCreateProcessInfo(char *buf, int bufsize, DWORD dwProcessId, DWORD dwThreadId, CREATE_PROCESS_DEBUG_INFO *createProcessInfo); int ParseDebugExitThread(char *buf, int bufsize, DWORD dwProcessId, DWORD dwThreadId, EXIT_THREAD_DEBUG_INFO *exitThread); int ParseDebugExitProcess(char *buf, int bufsize, DWORD dwProcessId, DWORD dwThreadId, EXIT_PROCESS_DEBUG_INFO *exitProcess); int ParseDebugLoadDll(char *buf, int bufsize, DWORD dwProcessId, DWORD dwThreadId, LOAD_DLL_DEBUG_INFO *loadDll); int ParseDebugUnloadDll(char *buf, int bufsize, DWORD dwProcessId, DWORD dwThreadId, UNLOAD_DLL_DEBUG_INFO *unloadDll); int ParseDebugString(char *buf, int bufsize, DWORD dwProcessId, DWORD dwThreadId, OUTPUT_DEBUG_STRING_INFO *debugString); int ParseDebugRipInfo(char *buf, int bufsize, DWORD dwProcessId, DWORD dwThreadId, RIP_INFO *ripInfo); bool needStackdump(bool bFirst, DWORD dwCode) { return bFirst && dwCode!=EXCEPTION_BREAKPOINT && dwCode!=EXCEPTION_SINGLE_STEP && ((dwCode>=0x80000000 && dwCode<0x80001000) || (dwCode>=0xc0000000 && dwCode<0xc0001000)); } int ParseDebugEvent(char *buf, int bufsize, DEBUG_EVENT *event) { int n=0; switch(event->dwDebugEventCode) { case EXCEPTION_DEBUG_EVENT: n+=ParseDebugException(buf+n, bufsize-n, event->dwProcessId, event->dwThreadId, &event->u.Exception); printf("ITSUTILS debugger, need stackdump: first= %d, code=%08x -> %d\n", event->u.Exception.dwFirstChance, event->u.Exception.ExceptionRecord.ExceptionCode, needStackdump(event->u.Exception.dwFirstChance, event->u.Exception.ExceptionRecord.ExceptionCode)); // this creates the stackdump n+=AddThreadInfo(buf+n, bufsize-n, event->dwProcessId, event->dwThreadId, needStackdump(event->u.Exception.dwFirstChance, event->u.Exception.ExceptionRecord.ExceptionCode)); break; case CREATE_THREAD_DEBUG_EVENT: n+=ParseDebugCreateThread(buf+n, bufsize-n, event->dwProcessId, event->dwThreadId, &event->u.CreateThread); break; case CREATE_PROCESS_DEBUG_EVENT:n+=ParseDebugCreateProcessInfo(buf+n, bufsize-n, event->dwProcessId, event->dwThreadId, &event->u.CreateProcessInfo); break; case EXIT_THREAD_DEBUG_EVENT: n+=ParseDebugExitThread(buf+n, bufsize-n, event->dwProcessId, event->dwThreadId, &event->u.ExitThread); break; case EXIT_PROCESS_DEBUG_EVENT: n+=ParseDebugExitProcess(buf+n, bufsize-n, event->dwProcessId, event->dwThreadId, &event->u.ExitProcess); break; case LOAD_DLL_DEBUG_EVENT: n+=ParseDebugLoadDll(buf+n, bufsize-n, event->dwProcessId, event->dwThreadId, &event->u.LoadDll); break; case UNLOAD_DLL_DEBUG_EVENT: n+=ParseDebugUnloadDll(buf+n, bufsize-n, event->dwProcessId, event->dwThreadId, &event->u.UnloadDll); break; case OUTPUT_DEBUG_STRING_EVENT: n+=ParseDebugString(buf+n, bufsize-n, event->dwProcessId, event->dwThreadId, &event->u.DebugString); break; case RIP_EVENT: n+=ParseDebugRipInfo(buf+n, bufsize-n, event->dwProcessId, event->dwThreadId, &event->u.RipInfo); break; default: n+= _snprintf(buf+n, bufsize-n, "unknown debug event pid=%08lx tid=%08lx ev=%08lx", event->dwProcessId, event->dwThreadId, event->dwDebugEventCode); } return n; } // provide some info in case other things fail. char *StrInfo(DWORD dwProcessId, void *ptr, int len, int uni) { static textbuffer tbuf(16*1024, 256); size_t maxstr; char *str= tbuf.newptr(maxstr); size_t slen= _snprintf(str, maxstr, "[%08lx:%08lx L%04x uni=%d]", dwProcessId, ptr, len, uni); tbuf.commit(str, slen); return str; } char *ReadProcessWString(DWORD dwProcessId, void *ptr, int len) { static textbuffer tbuf(16*1024, 1024); size_t maxstr; char *str= tbuf.newptr(maxstr); WCHAR buf[1024]; DWORD nCopied; if (!ReadProcessMemory((HANDLE)dwProcessId, ptr, buf, std::min((size_t)len, sizeof(buf)-1), &nCopied)) return 0; buf[nCopied]= 0; utf16toutf8(reinterpret_cast(buf), str, maxstr); tbuf.commit(str, maxstr); return str; } char *ReadProcessString(DWORD dwProcessId, void *ptr, int len) { static textbuffer buf(16*1024, 1024); size_t maxstr; char *str= buf.newptr(maxstr); DWORD nCopied; if (!ReadProcessMemory((HANDLE)dwProcessId, ptr, str, std::min((size_t)len, maxstr-1), &nCopied)) return 0; str[nCopied]= 0; buf.commit(str, nCopied+1); return str; } DWORD ReadProcessDword(DWORD dwProcessId, void *ptr) { DWORD dw; DWORD nCopied; if (!ReadProcessMemory((HANDLE)dwProcessId, ptr, &dw, sizeof(DWORD), &nCopied)) return 0; return dw; } char *PtrToString(DWORD dwProcessId, void *ptr, int len, int uni) { if (ptr==NULL) return "(NULL)"; else if (uni) { char *tbuf= ReadProcessWString(dwProcessId, ptr, len); if (tbuf==NULL) return StrInfo(dwProcessId, ptr, len, uni); return tbuf; } else { char *buf= ReadProcessString(dwProcessId, ptr, len); if (buf==NULL) return StrInfo(dwProcessId, ptr, len, uni); return buf; } } char *PtrptrToString(DWORD dwProcessId, void *pptr, int len, int uni) { if (pptr==NULL) return "((NULL))"; void *ptr= (void*)ReadProcessDword(dwProcessId, pptr); return PtrToString(dwProcessId, ptr, len, uni); } int ParseExceptionCode(char *buf, int bufsize, DWORD dwCode) { const char *str=NULL; int n=0; switch (dwCode) { case EXCEPTION_ACCESS_VIOLATION: str= "EXCEPTION_ACCESS_VIOLATION"; break; case EXCEPTION_DATATYPE_MISALIGNMENT: str= "EXCEPTION_DATATYPE_MISALIGNMENT"; break; case EXCEPTION_BREAKPOINT: str= "EXCEPTION_BREAKPOINT"; break; case EXCEPTION_SINGLE_STEP: str= "EXCEPTION_SINGLE_STEP"; break; case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: str= "EXCEPTION_ARRAY_BOUNDS_EXCEEDED"; break; case EXCEPTION_FLT_DENORMAL_OPERAND: str= "EXCEPTION_FLT_DENORMAL_OPERAND"; break; case EXCEPTION_FLT_DIVIDE_BY_ZERO: str= "EXCEPTION_FLT_DIVIDE_BY_ZERO"; break; case EXCEPTION_FLT_INEXACT_RESULT: str= "EXCEPTION_FLT_INEXACT_RESULT"; break; case EXCEPTION_FLT_INVALID_OPERATION: str= "EXCEPTION_FLT_INVALID_OPERATION"; break; case EXCEPTION_FLT_OVERFLOW: str= "EXCEPTION_FLT_OVERFLOW"; break; case EXCEPTION_FLT_STACK_CHECK: str= "EXCEPTION_FLT_STACK_CHECK"; break; case EXCEPTION_FLT_UNDERFLOW: str= "EXCEPTION_FLT_UNDERFLOW"; break; case EXCEPTION_INT_DIVIDE_BY_ZERO: str= "EXCEPTION_INT_DIVIDE_BY_ZERO"; break; case EXCEPTION_INT_OVERFLOW: str= "EXCEPTION_INT_OVERFLOW"; break; case EXCEPTION_PRIV_INSTRUCTION: str= "EXCEPTION_PRIV_INSTRUCTION"; break; case EXCEPTION_IN_PAGE_ERROR: str= "EXCEPTION_IN_PAGE_ERROR"; break; case EXCEPTION_ILLEGAL_INSTRUCTION: str= "EXCEPTION_ILLEGAL_INSTRUCTION"; break; case EXCEPTION_NONCONTINUABLE_EXCEPTION: str= "EXCEPTION_NONCONTINUABLE_EXCEPTION"; break; case EXCEPTION_STACK_OVERFLOW: str= "EXCEPTION_STACK_OVERFLOW"; break; case EXCEPTION_INVALID_DISPOSITION: str= "EXCEPTION_INVALID_DISPOSITION"; break; case EXCEPTION_GUARD_PAGE: str= "EXCEPTION_GUARD_PAGE"; break; case EXCEPTION_INVALID_HANDLE: str= "EXCEPTION_INVALID_HANDLE"; break; } if (str) n+= _snprintf(buf+n, bufsize-n, " %s", str); else n+= _snprintf(buf+n, bufsize-n, " EXCEPTION_%08lx", dwCode); return n; } int ParseExceptionFlags(char *buf, int bufsize, DWORD dwFlags) { int n=0; if (dwFlags==0) { n+= _snprintf(buf+n, bufsize-n, " noflags"); return n; } n+= _snprintf(buf+n, bufsize-n, " flags="); int m=n; if (dwFlags&EXCEPTION_NONCONTINUABLE ) n+= _snprintf(buf+n, bufsize-n, "%sNONCONTINUABLE", n==m?"":"|"); if (dwFlags&EXCEPTION_UNWINDING ) n+= _snprintf(buf+n, bufsize-n, "%sUNWINDING", n==m?"":"|"); if (dwFlags&EXCEPTION_EXIT_UNWIND ) n+= _snprintf(buf+n, bufsize-n, "%sEXIT_UNWIND", n==m?"":"|"); if (dwFlags&EXCEPTION_STACK_INVALID ) n+= _snprintf(buf+n, bufsize-n, "%sSTACK_INVALID", n==m?"":"|"); if (dwFlags&EXCEPTION_NESTED_CALL ) n+= _snprintf(buf+n, bufsize-n, "%sNESTED_CALL", n==m?"":"|"); if (dwFlags&EXCEPTION_TARGET_UNWIND ) n+= _snprintf(buf+n, bufsize-n, "%sTARGET_UNWIND", n==m?"":"|"); if (dwFlags&EXCEPTION_COLLIDED_UNWIND) n+= _snprintf(buf+n, bufsize-n, "%sCOLLIDED_UNWIND", n==m?"":"|"); const DWORD knownflags= EXCEPTION_NONCONTINUABLE|EXCEPTION_UNWINDING|EXCEPTION_EXIT_UNWIND|EXCEPTION_STACK_INVALID|EXCEPTION_NESTED_CALL|EXCEPTION_TARGET_UNWIND|EXCEPTION_COLLIDED_UNWIND; if (dwFlags&~knownflags) n+= _snprintf(buf+n, bufsize-n, "%s%08lx", n==m?"":"|", dwFlags&~knownflags); return n; } int ParseDebugException(char *buf, int bufsize, DWORD dwProcessId, DWORD dwThreadId, EXCEPTION_DEBUG_INFO *exception) { int n=0; n+= _snprintf(buf+n, bufsize-n, "debugException first=%d", exception->dwFirstChance); EXCEPTION_RECORD *er= &exception->ExceptionRecord; int i=0; while (er) { if (i) n+= _snprintf(buf+n, bufsize-n, " ; "); n+= ParseExceptionCode(buf+n, bufsize-n, er->ExceptionCode); n+= ParseExceptionFlags(buf+n, bufsize-n, er->ExceptionFlags); n+= _snprintf(buf+n, bufsize-n, " @%08lx", er->ExceptionAddress); if (er->ExceptionCode==EXCEPTION_ACCESS_VIOLATION && er->NumberParameters==2) { n+= _snprintf(buf+n, bufsize-n, " RW=%08lx addr=%08lx\n", er->ExceptionInformation[0], er->ExceptionInformation[1]); } else { for (unsigned i=0 ; iNumberParameters ; i++) { n+= _snprintf(buf+n, bufsize-n, " %08lx", er->ExceptionInformation[i]); } n+= _snprintf(buf+n, bufsize-n, "\n"); } er= er->ExceptionRecord; i++; } return n; } int ParseDebugCreateThread(char *buf, int bufsize, DWORD dwProcessId, DWORD dwThreadId, CREATE_THREAD_DEBUG_INFO *createThread) { int n=0; n+= _snprintf(buf+n, bufsize-n, "createThread(hthread=%08x base=%08x start=%08x)", createThread->hThread, createThread->lpThreadLocalBase, createThread->lpStartAddress); return n; } int ParseDebugCreateProcessInfo(char *buf, int bufsize, DWORD dwProcessId, DWORD dwThreadId, CREATE_PROCESS_DEBUG_INFO *createProcessInfo) { int n=0; n+= _snprintf(buf+n, bufsize-n, "createProcess(file=%d hproc=%08x hthread=%08x image=%08x debug=%08x(%08x)", createProcessInfo->hFile, createProcessInfo->hProcess, createProcessInfo->hThread, createProcessInfo->lpBaseOfImage, createProcessInfo->dwDebugInfoFileOffset, createProcessInfo->nDebugInfoSize); n+= _snprintf(buf+n, bufsize-n, " base=%08x start=%08x name='%s'", createProcessInfo->lpThreadLocalBase, createProcessInfo->lpStartAddress, PtrToString( dwProcessId, createProcessInfo->lpImageName, 128, // todo ..... what should this be ?? createProcessInfo->fUnicode)); return n; } int ParseDebugExitThread(char *buf, int bufsize, DWORD dwProcessId, DWORD dwThreadId, EXIT_THREAD_DEBUG_INFO *exitThread) { int n=0; // todo: remember n+= _snprintf(buf+n, bufsize-n, "exitThread %08lx code=%d", dwThreadId, exitThread->dwExitCode); return n; } int ParseDebugExitProcess(char *buf, int bufsize, DWORD dwProcessId, DWORD dwThreadId, EXIT_PROCESS_DEBUG_INFO *exitProcess) { int n=0; n+= _snprintf(buf+n, bufsize-n, "exitProcess code=%d", exitProcess->dwExitCode); return n; } int ParseDebugLoadDll(char *buf, int bufsize, DWORD dwProcessId, DWORD dwThreadId, LOAD_DLL_DEBUG_INFO *loadDll) { int n=0; n+= _snprintf(buf+n, bufsize-n, "loadDll file=%d base=%08x debug=%08x(%08x) name='%s'", loadDll->hFile, loadDll->lpBaseOfDll, loadDll->dwDebugInfoFileOffset, loadDll->nDebugInfoSize, PtrToString( dwProcessId, loadDll->lpImageName, 128, // todo ..... what should this be ?? loadDll->fUnicode)); return n; } int ParseDebugUnloadDll(char *buf, int bufsize, DWORD dwProcessId, DWORD dwThreadId, UNLOAD_DLL_DEBUG_INFO *unloadDll) { int n=0; // todo: keep track of pid+dllbase to remember the module name. n+= _snprintf(buf+n, bufsize-n, "unloadDll base=%08x", unloadDll->lpBaseOfDll); return n; } int ParseDebugString(char *buf, int bufsize, DWORD dwProcessId, DWORD dwThreadId, OUTPUT_DEBUG_STRING_INFO *debugString) { int n=0; n+= _snprintf(buf+n, bufsize-n, "%s", PtrToString(dwProcessId, debugString->lpDebugStringData, debugString->nDebugStringLength, debugString->fUnicode)); return n; } int ParseDebugRipInfo(char *buf, int bufsize, DWORD dwProcessId, DWORD dwThreadId, RIP_INFO *ripInfo) { int n=0; n+= _snprintf(buf+n, bufsize-n, "ripinfo error=%d type=%d", ripInfo->dwError, ripInfo->dwType); return n; }