📄 strace.cc
字号:
/* strace.cc Copyright 2000, 2001, 2002 Red Hat Inc. Written by Chris Faylor <cgf@redhat.com>This file is part of Cygwin.This software is a copyrighted work licensed under the terms of theCygwin license. Please consult the file "CYGWIN_LICENSE" fordetails. */#define cygwin_internal cygwin_internal_dontuse#include <stdio.h>#include <fcntl.h>#include <getopt.h>#include <stdarg.h>#include <string.h>#include <stdlib.h>#include <time.h>#include <windows.h>#include <signal.h>#include <errno.h>#include "cygwin/include/sys/strace.h"#include "cygwin/include/sys/cygwin.h"#undef cygwin_internal/* GCC runtime library's C++ EH code unfortunately pulls in stdio, and we get undefine references to __impure_ptr, and hence the following hack. It should be reasonably safe however as long as this file is built using -mno-cygwin as is intended. */int _impure_ptr;/* we *know* we're being built with GCC */#define alloca __builtin_alloca// Version string.static const char version[] = "$Revision: 1.21 $";static const char *pgm;static int forkdebug = 1;static int numerror = 1;static int usecs = 1;static int delta = 1;static int hhmmss = 0;static int bufsize = 0;static int new_window = 0;static long flush_period = 0;static BOOL close_handle (HANDLE h, DWORD ok);#define CloseHandle(h) close_handle(h, 0)struct child_list{ DWORD id; HANDLE hproc; int saw_stars; char nfields; long long start_time; DWORD last_usecs; struct child_list *next; child_list ():id (0), hproc (NULL), saw_stars (0), nfields (0), start_time (0), last_usecs (0), next (NULL) { }};child_list children;static voidwarn (int geterrno, const char *fmt, ...){ va_list args; char buf[4096]; va_start (args, fmt); sprintf (buf, "%s: ", pgm); vsprintf (strchr (buf, '\0'), fmt, args); if (geterrno) perror (buf); else { fputs (buf, stderr); fputs ("\n", stderr); }}static void __attribute__ ((noreturn))error (int geterrno, const char *fmt, ...){ va_list args; char buf[4096]; va_start (args, fmt); sprintf (buf, "%s: ", pgm); vsprintf (strchr (buf, '\0'), fmt, args); if (geterrno) perror (buf); else { fputs (buf, stderr); fputs ("\n", stderr); } exit (1);}DWORD lastid = 0;HANDLE lasth;#define PROCFLAGS \ PROCESS_ALL_ACCESS /*(PROCESS_DUP_HANDLE | PROCESS_TERMINATE | PROCESS_VM_READ | PROCESS_VM_WRITE) */static voidadd_child (DWORD id, HANDLE hproc){ child_list *c = children.next; children.next = (child_list *) calloc (1, sizeof (child_list)); children.next->next = c; lastid = children.next->id = id; lasth = children.next->hproc = hproc;}static child_list *get_child (DWORD id){ child_list *c; for (c = &children; (c = c->next) != NULL;) if (c->id == id) return c; error (0, "no process id %d found", id);}static voidremove_child (DWORD id){ child_list *c; if (id == lastid) lastid = 0; for (c = &children; c->next != NULL; c = c->next) if (c->next->id == id) { child_list *c1 = c->next; c->next = c1->next; free (c1); return; } error (0, "no process id %d found", id);}#define LINE_BUF_CHUNK 128class linebuf{ size_t alloc;public: size_t ix; char *buf; linebuf () { ix = 0; alloc = 0; buf = NULL; } ~linebuf () { if (buf) free (buf); } void add (const char *what, int len); void add (const char *what) { add (what, strlen (what)); } void prepend (const char *what, int len);};voidlinebuf::add (const char *what, int len){ size_t newix; if ((newix = ix + len) >= alloc) { alloc += LINE_BUF_CHUNK + len; buf = (char *) realloc (buf, alloc + 1); } memcpy (buf + ix, what, len); ix = newix; buf[ix] = '\0';}voidlinebuf::prepend (const char *what, int len){ int buflen; size_t newix; if ((newix = ix + len) >= alloc) { alloc += LINE_BUF_CHUNK + len; buf = (char *) realloc (buf, alloc + 1); buf[ix] = '\0'; } if ((buflen = strlen (buf))) memmove (buf + len, buf, buflen + 1); else buf[newix] = '\0'; memcpy (buf, what, len); ix = newix;}static voidmake_command_line (linebuf & one_line, char **argv){ for (; *argv; argv++) { char *p = NULL; const char *a = *argv; int len = strlen (a); if (len != 0 && !(p = strpbrk (a, " \t\n\r\""))) one_line.add (a, len); else { one_line.add ("\"", 1); for (; p; a = p, p = strchr (p, '"')) { one_line.add (a, ++p - a); if (p[-1] == '"') one_line.add ("\"", 1); } if (*a) one_line.add (a); one_line.add ("\"", 1); } one_line.add (" ", 1); } if (one_line.ix) one_line.buf[one_line.ix - 1] = '\0'; else one_line.add ("", 1);}static DWORD child_pid;static BOOL WINAPIctrl_c (DWORD){ static int tic = 1; if ((tic ^= 1) && !GenerateConsoleCtrlEvent (CTRL_C_EVENT, 0)) error (0, "couldn't send CTRL-C to child, win32 error %d\n", GetLastError ()); return TRUE;}DWORD (*cygwin_internal) (int, ...);static intload_cygwin (){ static HMODULE h; if (cygwin_internal) return 1; if (h) return 0; if (!(h = LoadLibrary ("cygwin1.dll"))) { errno = ENOENT; return 0; } if (!(cygwin_internal = (DWORD (*) (int, ...)) GetProcAddress (h, "cygwin_internal"))) { errno = ENOSYS; return 0; } return 1;}static voidattach_process (pid_t pid){ load_cygwin (); child_pid = (DWORD) cygwin_internal (CW_CYGWIN_PID_TO_WINPID, pid); if (!child_pid) { warn (0, "no such cygwin pid - %d", pid); child_pid = pid; } if (!DebugActiveProcess (child_pid)) error (0, "couldn't attach to pid %d<%d> for debugging", pid, child_pid); printf ("Attached to pid %d (windows pid %u)\n", pid, (unsigned) child_pid); return;}static voidcreate_child (char **argv){ linebuf one_line; STARTUPINFO si; PROCESS_INFORMATION pi; BOOL ret; DWORD flags; memset (&si, 0, sizeof (si)); si.cb = sizeof (si); flags = CREATE_DEFAULT_ERROR_MODE | (forkdebug ? DEBUG_PROCESS : DEBUG_ONLY_THIS_PROCESS); if (new_window) flags |= CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP; make_command_line (one_line, argv); SetConsoleCtrlHandler (NULL, 0); ret = CreateProcess (0, one_line.buf, /* command line */ NULL, /* Security */ NULL, /* thread */ TRUE, /* inherit handles */ flags, /* start flags */ NULL, NULL, /* current directory */ &si, &pi); if (!ret) error (0, "error creating process %s, (error %d)", *argv, GetLastError ()); CloseHandle (pi.hThread); CloseHandle (pi.hProcess); child_pid = pi.dwProcessId; SetConsoleCtrlHandler (ctrl_c, 1);}static intoutput_winerror (FILE *ofile, char *s){ char *winerr = strstr (s, "Win32 error "); if (!winerr) return 0; DWORD errnum = atoi (winerr + sizeof ("Win32 error ") - 1); if (!errnum) return 0; /* * NOTE: Currently there is no policy for how long the * the buffers are, and looks like 256 is a smallest one * (dlfcn.cc). Other than error 1395 (length 213) and * error 1015 (length 249), the rest are all under 188 * characters, and so I'll use 189 as the buffer length. * For those longer error messages, FormatMessage will * return FALSE, and we'll get the old behaviour such as * ``Win32 error 1395'' etc. */ char buf[4096]; if (!FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errnum, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) buf, sizeof (buf), NULL)) return 0; /* Get rid the trailing CR/NL pair. */ char *p = strchr (buf, '\0'); p[-2] = '\n'; p[-1] = '\0'; *winerr = '\0'; fputs (s, ofile); fputs (buf, ofile); return 1;}static SYSTEMTIME *syst (long long t){ FILETIME n; static SYSTEMTIME st; long long now = t + ((long long) usecs * 10); n.dwHighDateTime = now >> 32; n.dwLowDateTime = now & 0xffffffff; FileTimeToSystemTime (&n, &st); return &st;}static void __stdcallhandle_output_debug_string (DWORD id, LPVOID p, unsigned mask, FILE *ofile){ int len; int special; char alen[3 + 8 + 1]; DWORD nbytes; child_list *child = get_child (id); HANDLE hchild = child->hproc;#define INTROLEN (sizeof (alen) - 1) if (id == lastid && hchild != lasth) warn (0, "%p != %p", hchild, lasth); alen[INTROLEN] = '\0'; if (!ReadProcessMemory (hchild, p, alen, INTROLEN, &nbytes))#ifndef DEBUGGING return;#else error (0, "couldn't get message length from subprocess %d<%p>, windows error %d", id, hchild, GetLastError ());#endif if (strncmp (alen, "cYg", 3)) return; len = (int) strtoul (alen + 3, NULL, 16); if (!len) return; if (len > 0) special = 0; else { special = len; if (special == _STRACE_INTERFACE_ACTIVATE_ADDR) len = 17; } char *buf; buf = (char *) alloca (len + 65) + 10; if (!ReadProcessMemory (hchild, ((char *) p) + INTROLEN, buf, len, &nbytes)) error (0, "couldn't get message from subprocess, windows error %d", GetLastError ()); buf[len] = '\0'; char *s = strtok (buf, " "); unsigned n = strtoul (s, NULL, 16); s = strchr (s, '\0') + 1; if (special == _STRACE_INTERFACE_ACTIVATE_ADDR) { DWORD new_flag = 1; if (!WriteProcessMemory (hchild, (LPVOID) n, &new_flag, sizeof (new_flag), &nbytes)) error (0, "couldn't write strace flag to subprocess, windows error %d", GetLastError ()); return; } char *origs = s; if (mask & n) /* got it */ ; else if (!(mask & _STRACE_ALL) || (n & _STRACE_NOTALL)) return; /* This should not be included in "all" output */ DWORD dusecs, usecs; char *ptusec, *ptrest; dusecs = strtoul (s, &ptusec, 10); char *q = ptusec; while (*q == ' ') q++; if (*q != '[') { usecs = strtoul (q, &ptrest, 10); while (*ptrest == ' ') ptrest++; } else { ptrest = q; ptusec = s; usecs = dusecs; } if (child->saw_stars == 0) { FILETIME st; char *news; GetSystemTimeAsFileTime (&st); FileTimeToLocalFileTime (&st, &st); child->start_time = st.dwHighDateTime; child->start_time <<= 32; child->start_time |= st.dwLowDateTime; if (*(news = ptrest) != '[') child->saw_stars = 2; else { child->saw_stars++; while ((news = strchr (news, ' ')) != NULL && *++news != '*') child->nfields++; if (news == NULL) child->saw_stars++; else { s = news;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -