491 lines
13 KiB
C++
491 lines
13 KiB
C++
/* 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 <ctype.h>
|
|
#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 LONGLONG process_start NO_COPY;
|
|
clk_monotonic_t *clk = (clk_monotonic_t *) get_clock (CLOCK_MONOTONIC);
|
|
|
|
if (!process_start)
|
|
process_start = clk->strace_usecs ();
|
|
return (int) (clk->strace_usecs () - process_start);
|
|
}
|
|
|
|
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*/
|