/* (C) 2003-2007 Willem Jan Hengeveld * Web: http://www.xs4all.nl/~itsme/ * http://wiki.xda-developers.com/ * * $Id: pdebug.cpp 1921 2008-07-31 17:08:31Z itsme $ * * this program attaches to or runs programs on the windows ce device in * debug mode, and dumping all debug events, and dumping the stack when * an exception occors. * */ // todo: // ITWaitForDebugEvent should return multiple events. ... like max 16. // then should get rid of some buffer issues. // // ... sometimes the output is way behind what is happening // #include #include #include #include #include #include "args.h" #include "ItsUtils.h" #include "stringutils.h" #include "debug.h" #include "dllversion.h" #include using namespace std; // !!! I am mixing up handles and processid's quite often. // on WinCE this is not a problem, but this needs to be // fixed before porting to another platform. bool g_bLessInformation= false; bool g_bFilterForProcess= true; bool g_bSysMessagesOnly= false; typedef struct _tagDebugEvent { DWORD dwProcessId; DWORD dwThreadId; DWORD dwDebugEventCode; std::string description; } DebugEvent; bool DebugProcess(DWORD dwProcessId, const WCHAR *szExeName, const WCHAR *szCmdLine); DWORD ITGetProcessId(const char *szProcessName); HANDLE ITGetProcessHandle(const char *szProcessName); bool ITStartDebuggingProcess(DWORD dwProcessId, const WCHAR *wszExeName, const WCHAR *wszCmdLine, DWORD *pdwDebugger, bool bFilterForProcess, bool bSysMessagesOnly); bool ITWaitForDebugEvent(DWORD dwDebugger, DebugEvent *ev, DWORD *pdwMissedEvents); bool ITStopDebuggingProcess(DWORD dwDebugger); void WriteDebugEvent(DebugEvent *ev); void usage() { printf("(C) 2003-2008 Willem jan Hengeveld itsme@xs4all.nl\n"); printf("Usage: pdebug [options] [-h PID|HANDLE ]\n"); printf(" or: pdebug [options] \n"); printf(" or: pdebug [options] -x [--] [cmdline args]\n"); printf(" -q : output only to logfile\n"); printf(" -o FILENAME : specify logfile to output debug events to\n"); printf(" -h HANDLE : specify handle of running process to attach to\n"); printf(" -h HANDLE : specify handle of running process to attach to\n"); printf(" -x EXENAME : run, and attach to new process\n"); printf(" -a : show messages from all processes\n"); printf(" -n : sys systemmessages from all processes ( no-debugmessages )\n"); printf(" -s : less verbose output\n"); printf(" -- : don't process options after this\n"); } int main(int argc, char *argv[]) { bool bStartProcess= false; DWORD dwProcessId= 0; string exename; string cmdline; char *szLogFile= NULL; bool bQuiet= false; bool bProcessOptions= true; int argsfound=0; for (int i=1 ; i1 && !bStartProcess)) { usage(); return 1; } CheckITSDll(); if (szLogFile) DebugSetLogfile(szLogFile); if (!bQuiet) DebugStdOut(); if (dwProcessId==0 && !bStartProcess) { string processname; string::size_type ls= exename.find_last_of('\\'); if (ls==string::npos) processname= exename; else processname= exename.substr(ls+1); dwProcessId= ITGetProcessId(processname.c_str()); } DebugProcess(dwProcessId, ToWString(exename).c_str(), ToWString(cmdline).c_str()); CeRapiUninit(); return 0; } bool check_for_break() { HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE); if (hStdin == INVALID_HANDLE_VALUE) { error("GetStdHandle"); return false; } INPUT_RECORD irInBuf[128]; DWORD cNumRead; if (!PeekConsoleInput(hStdin, irInBuf, 128, &cNumRead)) { error("PeekConsoleInput"); return false; } if (cNumRead==0) return false; if (! ReadConsoleInput( hStdin, irInBuf, 128, &cNumRead) ) { error("ReadConsoleInput"); return false; } for (size_t i=0 ; ibKeyDown && kev->uChar.AsciiChar==0x1b) return true; } } return false; } bool DebugProcess(DWORD dwProcessId, const WCHAR *szExeName, const WCHAR *szCmdLine) { DWORD debugger; if (!ITStartDebuggingProcess(dwProcessId, szExeName, szCmdLine, &debugger, g_bFilterForProcess, g_bSysMessagesOnly)) { debug("ERROR: ITStartDebuggingProcess failed\n"); return false; } DebugEvent ev; DWORD missed= 0; DWORD totalmissed= 0; while (ITWaitForDebugEvent(debugger, &ev, &missed)) { if (missed) { debug("MISSED %d events\n", missed); totalmissed += missed; } WriteDebugEvent(&ev); if (check_for_break()) break; } debug("total missed %d events\n", totalmissed); if (!ITStopDebuggingProcess(debugger)) { debug("ERROR: ITStopDebuggingProcess failed\n"); return false; } return true; } bool DebugProcess(HANDLE hProc) { return DebugProcess((DWORD)hProc, NULL, NULL); } bool ITStartDebuggingProcess(DWORD dwProcessId, const WCHAR *wszExeName, const WCHAR *wszCmdLine, DWORD *pdwDebugger, bool bFilterForProcess, bool bSysMessagesOnly) { StartDebuggingProcessParams inbuf; memset(&inbuf, 0, sizeof(inbuf)); inbuf.dwProcessId= dwProcessId; inbuf.bFilterForProcess= bFilterForProcess; inbuf.bSysMessagesOnly= bSysMessagesOnly; if (dwProcessId==0) { if (wszExeName) wcsncpy(inbuf.wszExeName, wszExeName, sizeof(inbuf.wszExeName)/sizeof(WCHAR)); if (wszCmdLine) wcsncpy(inbuf.wszCmdLine, wszCmdLine, sizeof(inbuf.wszCmdLine)/sizeof(WCHAR)); } StartDebuggingProcessResult *outbuf; DWORD outsize= 0; HRESULT res= ItsutilsInvoke(L"ITStartDebuggingProcess", sizeof(StartDebuggingProcessParams), (BYTE*)&inbuf, &outsize, (BYTE**)&outbuf); if (res || outbuf==NULL) { error(res, "ITStartDebuggingProcess(%08lx, %ls, %ls)", dwProcessId, wszExeName, wszCmdLine); return false; } *pdwDebugger= outbuf->debugger; LocalFree(outbuf); return true; } bool ITWaitForDebugEvent(DWORD dwDebugger, DebugEvent *ev, DWORD *pdwMissedEvents) { WaitForDebugEventParams inbuf; WaitForDebugEventResult *outbuf=NULL; DWORD outsize=0; inbuf.debugger= dwDebugger; HRESULT res= ItsutilsInvoke(L"ITWaitForDebugEvent", sizeof(WaitForDebugEventParams), (BYTE*)&inbuf, &outsize, (BYTE**)&outbuf); if (res==-1) return false; if (res || outbuf==NULL) { error(res, "ITWaitForDebugEvent"); return false; } ev->dwProcessId= outbuf->dwProcessId; ev->dwThreadId= outbuf->dwThreadId; ev->dwDebugEventCode= outbuf->dwDebugEventCode; ev->description.resize(outbuf->len); memcpy(stringptr(ev->description), outbuf->description, outbuf->len); *pdwMissedEvents= outbuf->dwMissedEvents; LocalFree(outbuf); return true; } bool ITStopDebuggingProcess(DWORD dwDebugger) { StopDebuggingProcessParams inbuf; inbuf.debugger= dwDebugger; DWORD outsize=0; HRESULT res= ItsutilsInvoke(L"ITStopDebuggingProcess", sizeof(StopDebuggingProcessParams), (BYTE*)&inbuf, &outsize, NULL); if (res) { error(res, "ITStopDebuggingProcess"); return false; } return true; } void WriteDebugEvent(DebugEvent *ev) { if (g_bLessInformation) debug("%hs\n", ev->description.c_str()); else debug("%08lx:%08lx %d %hs\n", ev->dwProcessId, ev->dwThreadId, ev->dwDebugEventCode, ev->description.c_str()); } DWORD ITGetProcessId(const char *szProcessName) { return (DWORD)ITGetProcessHandle(szProcessName); } HANDLE ITGetProcessHandle(const char *szProcessName) { DWORD insize= (strlen(szProcessName)+1)*sizeof(WCHAR); WCHAR *inbuf= (WCHAR*)LocalAlloc(LPTR, insize); _snwprintf((WCHAR*)inbuf, insize/sizeof(WCHAR), L"%hs", szProcessName); DWORD outsize=0; HANDLE *outbuf=NULL; HRESULT res= ItsutilsInvoke(L"ITGetProcessHandle", insize, (BYTE*)inbuf, &outsize, (BYTE**)&outbuf); if (res || outbuf==NULL) { error(res, "ITGetProcessHandle"); return INVALID_HANDLE_VALUE; } HANDLE hproc= *outbuf; LocalFree(outbuf); return hproc; }