/* strace.cc: system/windows tracing This file is part of Cygwin. This software is a copyrighted work licensed under the terms of the Cygwin license. Please consult the file "CYGWIN_LICENSE" for details. */ #include "winsup.h" #include #include "cygerrno.h" #include "pinfo.h" #include "perprocess.h" #include "cygwin_version.h" #include "cygthread.h" #include "path.h" #include "fhandler.h" #include "dtable.h" #include "cygheap.h" #include "child_info.h" #include "sync.h" #define PROTECT(x) {x[NT_MAX_PATH - 1] = '\0';} #define CHECK(x) if (x[NT_MAX_PATH - 1] != '\0') \ { small_printf ("array bound exceeded %d\n", __LINE__); \ ExitProcess (1); \ } class strace NO_COPY strace; #ifndef NOSTRACE void strace::activate (bool isfork) { if (!_active && being_debugged ()) { char buf[30]; __small_sprintf (buf, "cYg%8x %lx %d", _STRACE_INTERFACE_ACTIVATE_ADDR, &_active, isfork); OutputDebugString (buf); if (_active) { char pidbuf[80]; PWCHAR progname; if (myself) { __small_sprintf (pidbuf, "(pid %d, ppid %d, windows pid %u)", myself->pid, myself->ppid ?: 1, GetCurrentProcessId ()); progname = myself->progname; } else { __small_sprintf (pidbuf, "(windows pid %u)", GetCurrentProcessId ()); progname = global_progname; } prntf (1, NULL, "**********************************************"); prntf (1, NULL, "Program name: %W %s", progname, pidbuf); prntf (1, NULL, "OS version: Windows %s", wincap.osname ()); prntf (1, NULL, "**********************************************"); } } } void strace::dll_info () { if (active ()) { prntf (1, NULL, "App version: %d.%d, api: %d.%d", user_data->dll_major, user_data->dll_minor, user_data->api_major, user_data->api_minor); prntf (1, NULL, "DLL version: %d.%d, api: %d.%d", cygwin_version.dll_major, cygwin_version.dll_minor, cygwin_version.api_major, cygwin_version.api_minor); prntf (1, NULL, "DLL build: %s", cygwin_version.dll_build_date); } } int strace::microseconds () { static hires_ns now NO_COPY; return (int) now.usecs (); } static int __stdcall getfunc (char *in_dst, const char *func) { const char *p; const char *pe; char *dst = in_dst; for (p = func; (pe = strchr (p, '(')); p = pe + 1) if (isalnum ((int)pe[-1]) || pe[-1] == '_') break; else if (isspace ((int)pe[-1])) { pe--; break; } if (!pe) pe = strchr (func, '\0'); for (p = pe; p > func; p--) if (p != pe && *p == ' ') { p++; break; } if (*p == '*') p++; while (p < pe) *dst++ = *p++; *dst++ = ':'; *dst++ = ' '; *dst = '\0'; return dst - in_dst; } static char * mypid (char *buf) { if (myself && myself->pid) __small_sprintf (buf, "%d", myself->pid); else __small_sprintf (buf, "(%d)", GetCurrentProcessId ()); return buf; } /* sprintf analog for use by output routines. */ int strace::vsprntf (char *buf, const char *func, const char *infmt, va_list ap) { int count; char fmt[80]; static NO_COPY bool nonewline = false; DWORD err = GetLastError (); const char *tn = mythreadname (); int microsec = microseconds (); lmicrosec = microsec; __small_sprintf (fmt, "%7d [%s] %s ", microsec, tn, "%W %s%s"); SetLastError (err); if (nonewline) count = 0; else { PWCHAR pn = NULL; WCHAR progname[NAME_MAX]; if (cygwin_finished_initializing && __progname) { char *p = strrchr (__progname, '/'); if (p) ++p; else p = __progname; char *pe = strrchr (p, '.'); if (!pe || !ascii_strcasematch (pe, ".exe")) pe = strrchr (p, '\0'); sys_mbstowcs (pn = progname, NAME_MAX, p, pe - p); } else { PWCHAR p = wcsrchr (global_progname, L'\\'); ++p; PWCHAR pe = wcsrchr (p, '.'); if (!pe || wcscasecmp (pe, L".exe")) pe = wcsrchr (p, L'\0'); pe = wcpncpy (progname, p, pe - p); *pe = L'\0'; pn = progname; } char tmpbuf[20]; count = __small_sprintf (buf, fmt, pn, mypid (tmpbuf), execing ? "!" : ""); if (func) count += getfunc (buf + count, func); } count += __small_vsprintf (buf + count, infmt, ap); char *p; for (p = buf + count; p > buf; p--) switch (p[-1]) { case '\n': p[-1] = '\0'; break; case '\b': *--p = '\0'; nonewline = true; goto done; default: goto addnl; } addnl: *p++ = '\n'; *p = '\0'; nonewline = false; done: return p - buf; } /* Write to strace file or strace queue. */ void strace::write (unsigned category, const char *buf, int count) { # define PREFIX (3 + 8 + 1 + 8 + 1) char outbuf[PREFIX + 1 + count + 1]; # define outstuff (outbuf + 12) __small_sprintf (outstuff, "%x %s", category, buf); __small_sprintf (outbuf, "cYg%08x", strlen (outstuff) + 1); outstuff[-1] = ' '; OutputDebugString (outbuf); #undef outstuff #undef PREFIX } void strace::write_childpid (pid_t pid) { char buf[30]; if (!attached () || !being_debugged ()) return; __small_sprintf (buf, "cYg%8x %x", _STRACE_CHILD_PID, pid); OutputDebugString (buf); } /* Printf function used when tracing system calls. Warning: DO NOT SET ERRNO HERE! */ static NO_COPY muto strace_buf_guard; static NO_COPY char *buf; void strace::vprntf (unsigned category, const char *func, const char *fmt, va_list ap) { DWORD err = GetLastError (); int len; strace_buf_guard.init ("smallprint_buf")->acquire (); /* Creating buffer on Windows process heap to drop stack pressure and keeping our .bss small. */ if (!buf) buf = (char *) HeapAlloc (GetProcessHeap (), 0, NT_MAX_PATH); if (!buf) return; PROTECT (buf); SetLastError (err); len = vsprntf (buf, func, fmt, ap); CHECK (buf); if (category & _STRACE_SYSTEM) { DWORD done; WriteFile (GetStdHandle (STD_ERROR_HANDLE), buf, len, &done, 0); FlushFileBuffers (GetStdHandle (STD_ERROR_HANDLE)); /* Make sure that the message shows up on the screen, too, since this is a serious error. */ if (GetFileType (GetStdHandle (STD_ERROR_HANDLE)) != FILE_TYPE_CHAR) { HANDLE h = CreateFile ("CONOUT$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, &sec_none, OPEN_EXISTING, 0, 0); if (h != INVALID_HANDLE_VALUE) { WriteFile (h, buf, len, &done, 0); CloseHandle (h); } } } #ifndef NOSTRACE if (active ()) write (category, buf, len); #endif strace_buf_guard.release (); SetLastError (err); } void strace::prntf (unsigned category, const char *func, const char *fmt, ...) { va_list ap; va_start (ap, fmt); vprntf (category, func, fmt, ap); va_end (ap); } extern "C" void strace_printf (unsigned category, const char *func, const char *fmt, ...) { va_list ap; if ((category & _STRACE_SYSTEM) || strace.active ()) { va_start (ap, fmt); strace.vprntf (category, func, fmt, ap); va_end (ap); } } static NO_COPY struct tab { int v; const char *n; } ta[] = { { WM_NULL, "WM_NULL" }, { WM_CREATE, "WM_CREATE" }, { WM_DESTROY, "WM_DESTROY" }, { WM_MOVE, "WM_MOVE" }, { WM_SIZE, "WM_SIZE" }, { WM_ACTIVATE, "WM_ACTIVATE" }, { WM_SETFOCUS, "WM_SETFOCUS" }, { WM_KILLFOCUS, "WM_KILLFOCUS" }, { WM_ENABLE, "WM_ENABLE" }, { WM_SETREDRAW, "WM_SETREDRAW" }, { WM_SETTEXT, "WM_SETTEXT" }, { WM_GETTEXT, "WM_GETTEXT" }, { WM_GETTEXTLENGTH, "WM_GETTEXTLENGTH" }, { WM_PAINT, "WM_PAINT" }, { WM_CLOSE, "WM_CLOSE" }, { WM_QUERYENDSESSION, "WM_QUERYENDSESSION" }, { WM_QUIT, "WM_QUIT" }, { WM_QUERYOPEN, "WM_QUERYOPEN" }, { WM_ERASEBKGND, "WM_ERASEBKGND" }, { WM_SYSCOLORCHANGE, "WM_SYSCOLORCHANGE" }, { WM_ENDSESSION, "WM_ENDSESSION" }, { WM_SHOWWINDOW, "WM_SHOWWINDOW" }, { WM_WININICHANGE, "WM_WININICHANGE" }, { WM_DEVMODECHANGE, "WM_DEVMODECHANGE" }, { WM_ACTIVATEAPP, "WM_ACTIVATEAPP" }, { WM_FONTCHANGE, "WM_FONTCHANGE" }, { WM_TIMECHANGE, "WM_TIMECHANGE" }, { WM_CANCELMODE, "WM_CANCELMODE" }, { WM_SETCURSOR, "WM_SETCURSOR" }, { WM_MOUSEACTIVATE, "WM_MOUSEACTIVATE" }, { WM_CHILDACTIVATE, "WM_CHILDACTIVATE" }, { WM_QUEUESYNC, "WM_QUEUESYNC" }, { WM_GETMINMAXINFO, "WM_GETMINMAXINFO" }, { WM_PAINTICON, "WM_PAINTICON" }, { WM_ICONERASEBKGND, "WM_ICONERASEBKGND" }, { WM_NEXTDLGCTL, "WM_NEXTDLGCTL" }, { WM_SPOOLERSTATUS, "WM_SPOOLERSTATUS" }, { WM_DRAWITEM, "WM_DRAWITEM" }, { WM_MEASUREITEM, "WM_MEASUREITEM" }, { WM_DELETEITEM, "WM_DELETEITEM" }, { WM_VKEYTOITEM, "WM_VKEYTOITEM" }, { WM_CHARTOITEM, "WM_CHARTOITEM" }, { WM_SETFONT, "WM_SETFONT" }, { WM_GETFONT, "WM_GETFONT" }, { WM_SETHOTKEY, "WM_SETHOTKEY" }, { WM_GETHOTKEY, "WM_GETHOTKEY" }, { WM_QUERYDRAGICON, "WM_QUERYDRAGICON" }, { WM_COMPAREITEM, "WM_COMPAREITEM" }, { WM_COMPACTING, "WM_COMPACTING" }, { WM_WINDOWPOSCHANGING, "WM_WINDOWPOSCHANGING" }, { WM_WINDOWPOSCHANGED, "WM_WINDOWPOSCHANGED" }, { WM_POWER, "WM_POWER" }, { WM_COPYDATA, "WM_COPYDATA" }, { WM_CANCELJOURNAL, "WM_CANCELJOURNAL" }, { WM_NCCREATE, "WM_NCCREATE" }, { WM_NCDESTROY, "WM_NCDESTROY" }, { WM_NCCALCSIZE, "WM_NCCALCSIZE" }, { WM_NCHITTEST, "WM_NCHITTEST" }, { WM_NCPAINT, "WM_NCPAINT" }, { WM_NCACTIVATE, "WM_NCACTIVATE" }, { WM_GETDLGCODE, "WM_GETDLGCODE" }, { WM_NCMOUSEMOVE, "WM_NCMOUSEMOVE" }, { WM_NCLBUTTONDOWN, "WM_NCLBUTTONDOWN" }, { WM_NCLBUTTONUP, "WM_NCLBUTTONUP" }, { WM_NCLBUTTONDBLCLK, "WM_NCLBUTTONDBLCLK" }, { WM_NCRBUTTONDOWN, "WM_NCRBUTTONDOWN" }, { WM_NCRBUTTONUP, "WM_NCRBUTTONUP" }, { WM_NCRBUTTONDBLCLK, "WM_NCRBUTTONDBLCLK" }, { WM_NCMBUTTONDOWN, "WM_NCMBUTTONDOWN" }, { WM_NCMBUTTONUP, "WM_NCMBUTTONUP" }, { WM_NCMBUTTONDBLCLK, "WM_NCMBUTTONDBLCLK" }, { WM_KEYFIRST, "WM_KEYFIRST" }, { WM_KEYDOWN, "WM_KEYDOWN" }, { WM_KEYUP, "WM_KEYUP" }, { WM_CHAR, "WM_CHAR" }, { WM_DEADCHAR, "WM_DEADCHAR" }, { WM_SYSKEYDOWN, "WM_SYSKEYDOWN" }, { WM_SYSKEYUP, "WM_SYSKEYUP" }, { WM_SYSCHAR, "WM_SYSCHAR" }, { WM_SYSDEADCHAR, "WM_SYSDEADCHAR" }, { WM_KEYLAST, "WM_KEYLAST" }, { WM_INITDIALOG, "WM_INITDIALOG" }, { WM_COMMAND, "WM_COMMAND" }, { WM_SYSCOMMAND, "WM_SYSCOMMAND" }, { WM_TIMER, "WM_TIMER" }, { WM_HSCROLL, "WM_HSCROLL" }, { WM_VSCROLL, "WM_VSCROLL" }, { WM_INITMENU, "WM_INITMENU" }, { WM_INITMENUPOPUP, "WM_INITMENUPOPUP" }, { WM_MENUSELECT, "WM_MENUSELECT" }, { WM_MENUCHAR, "WM_MENUCHAR" }, { WM_ENTERIDLE, "WM_ENTERIDLE" }, { WM_CTLCOLORMSGBOX, "WM_CTLCOLORMSGBOX" }, { WM_CTLCOLOREDIT, "WM_CTLCOLOREDIT" }, { WM_CTLCOLORLISTBOX, "WM_CTLCOLORLISTBOX" }, { WM_CTLCOLORBTN, "WM_CTLCOLORBTN" }, { WM_CTLCOLORDLG, "WM_CTLCOLORDLG" }, { WM_CTLCOLORSCROLLBAR, "WM_CTLCOLORSCROLLBAR" }, { WM_CTLCOLORSTATIC, "WM_CTLCOLORSTATIC" }, { WM_MOUSEFIRST, "WM_MOUSEFIRST" }, { WM_MOUSEMOVE, "WM_MOUSEMOVE" }, { WM_LBUTTONDOWN, "WM_LBUTTONDOWN" }, { WM_LBUTTONUP, "WM_LBUTTONUP" }, { WM_LBUTTONDBLCLK, "WM_LBUTTONDBLCLK" }, { WM_RBUTTONDOWN, "WM_RBUTTONDOWN" }, { WM_RBUTTONUP, "WM_RBUTTONUP" }, { WM_RBUTTONDBLCLK, "WM_RBUTTONDBLCLK" }, { WM_MBUTTONDOWN, "WM_MBUTTONDOWN" }, { WM_MBUTTONUP, "WM_MBUTTONUP" }, { WM_MBUTTONDBLCLK, "WM_MBUTTONDBLCLK" }, { WM_MOUSELAST, "WM_MOUSELAST" }, { WM_PARENTNOTIFY, "WM_PARENTNOTIFY" }, { WM_ENTERMENULOOP, "WM_ENTERMENULOOP" }, { WM_EXITMENULOOP, "WM_EXITMENULOOP" }, { WM_MDICREATE, "WM_MDICREATE" }, { WM_MDIDESTROY, "WM_MDIDESTROY" }, { WM_MDIACTIVATE, "WM_MDIACTIVATE" }, { WM_MDIRESTORE, "WM_MDIRESTORE" }, { WM_MDINEXT, "WM_MDINEXT" }, { WM_MDIMAXIMIZE, "WM_MDIMAXIMIZE" }, { WM_MDITILE, "WM_MDITILE" }, { WM_MDICASCADE, "WM_MDICASCADE" }, { WM_MDIICONARRANGE, "WM_MDIICONARRANGE" }, { WM_MDIGETACTIVE, "WM_MDIGETACTIVE" }, { WM_MDISETMENU, "WM_MDISETMENU" }, { WM_DROPFILES, "WM_DROPFILES" }, { WM_MDIREFRESHMENU, "WM_MDIREFRESHMENU" }, { WM_CUT, "WM_CUT" }, { WM_COPY, "WM_COPY" }, { WM_PASTE, "WM_PASTE" }, { WM_CLEAR, "WM_CLEAR" }, { WM_UNDO, "WM_UNDO" }, { WM_RENDERFORMAT, "WM_RENDERFORMAT" }, { WM_RENDERALLFORMATS, "WM_RENDERALLFORMATS" }, { WM_DESTROYCLIPBOARD, "WM_DESTROYCLIPBOARD" }, { WM_DRAWCLIPBOARD, "WM_DRAWCLIPBOARD" }, { WM_PAINTCLIPBOARD, "WM_PAINTCLIPBOARD" }, { WM_VSCROLLCLIPBOARD, "WM_VSCROLLCLIPBOARD" }, { WM_SIZECLIPBOARD, "WM_SIZECLIPBOARD" }, { WM_ASKCBFORMATNAME, "WM_ASKCBFORMATNAME" }, { WM_CHANGECBCHAIN, "WM_CHANGECBCHAIN" }, { WM_HSCROLLCLIPBOARD, "WM_HSCROLLCLIPBOARD" }, { WM_QUERYNEWPALETTE, "WM_QUERYNEWPALETTE" }, { WM_PALETTEISCHANGING, "WM_PALETTEISCHANGING" }, { WM_PALETTECHANGED, "WM_PALETTECHANGED" }, { WM_HOTKEY, "WM_HOTKEY" }, { WM_PENWINFIRST, "WM_PENWINFIRST" }, { WM_PENWINLAST, "WM_PENWINLAST" }, { WM_ASYNCIO, "ASYNCIO" }, { 0, 0 }}; void strace::wm (int message, int word, int lon) { if (active ()) { int i; for (i = 0; ta[i].n; i++) { if (ta[i].v == message) { prntf (_STRACE_WM, NULL, "wndproc %d %s %d %d", message, ta[i].n, word, lon); return; } } prntf (_STRACE_WM, NULL, "wndproc %d unknown %d %d", message, word, lon); } } #endif /*NOSTRACE*/