📄 strace.cc
字号:
child->nfields++; } } } else if (child->saw_stars < 2) { int i; char *news; if (*(news = ptrest) != '[') child->saw_stars = 2; else { for (i = 0; i < child->nfields; i++) if ((news = strchr (news, ' ')) == NULL) break; // Should never happen else news++; if (news == NULL) child->saw_stars = 2; else { s = news; if (*s == '*') { SYSTEMTIME *st = syst (child->start_time); fprintf (ofile, "Date/Time: %d-%02d-%02d %02d:%02d:%02d\n", st->wYear, st->wMonth, st->wDay, st->wHour, st->wMinute, st->wSecond); child->saw_stars++; } } } } long long d = usecs - child->last_usecs; char intbuf[40]; if (child->saw_stars < 2 || s != origs) /* Nothing */ ; else if (hhmmss) { s = ptrest - 9; SYSTEMTIME *st = syst (child->start_time + (long long) usecs * 10); sprintf (s, "%02d:%02d:%02d", st->wHour, st->wMinute, st->wSecond); *strchr (s, '\0') = ' '; } else if (!delta) s = ptusec; else { s = ptusec; sprintf (intbuf, "%5d ", (int) d); int len = strlen (intbuf); memcpy ((s -= len), intbuf, len); } child->last_usecs = usecs; if (numerror || !output_winerror (ofile, s)) fputs (s, ofile); if (!bufsize) fflush (ofile);}static voidproc_child (unsigned mask, FILE *ofile, pid_t pid){ DEBUG_EVENT ev; int processes = 0; time_t cur_time, last_time; SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_HIGHEST); last_time = time (NULL); while (1) { BOOL debug_event = WaitForDebugEvent (&ev, 1000); DWORD status = DBG_CONTINUE; if (bufsize && flush_period > 0 && (cur_time = time (NULL)) >= last_time + flush_period) { last_time = cur_time; fflush (ofile); } if (!debug_event) continue; if (pid) { (void) cygwin_internal (CW_STRACE_TOGGLE, pid); pid = 0; } switch (ev.dwDebugEventCode) { case CREATE_PROCESS_DEBUG_EVENT: if (ev.u.CreateProcessInfo.hFile) CloseHandle (ev.u.CreateProcessInfo.hFile); add_child (ev.dwProcessId, ev.u.CreateProcessInfo.hProcess); processes++; break; case CREATE_THREAD_DEBUG_EVENT: break; case LOAD_DLL_DEBUG_EVENT: if (ev.u.LoadDll.hFile) CloseHandle (ev.u.LoadDll.hFile); break; case OUTPUT_DEBUG_STRING_EVENT: handle_output_debug_string (ev.dwProcessId, ev.u.DebugString.lpDebugStringData, mask, ofile); break; case EXIT_PROCESS_DEBUG_EVENT: remove_child (ev.dwProcessId); break; case EXCEPTION_DEBUG_EVENT: if (ev.u.Exception.ExceptionRecord.ExceptionCode != STATUS_BREAKPOINT) { status = DBG_EXCEPTION_NOT_HANDLED;#if 0 fprintf (stderr, "exception %p at %p\n", ev.u.Exception.ExceptionRecord.ExceptionCode, ev.u.Exception.ExceptionRecord.ExceptionAddress);#endif } break; } if (!ContinueDebugEvent (ev.dwProcessId, ev.dwThreadId, status)) error (0, "couldn't continue debug event, windows error %d", GetLastError ()); if (ev.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT && --processes == 0) break; }}static voiddotoggle (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 (cygwin_internal (CW_STRACE_TOGGLE, child_pid)) error (0, "failed to toggle tracing for process %d<%d>", pid, child_pid); return;}static voiddostrace (unsigned mask, FILE *ofile, pid_t pid, char **argv){ if (!pid) create_child (argv); else attach_process (pid); proc_child (mask, ofile, pid); return;}typedef struct tag_mask_mnemonic{ unsigned long val; const char *text;}mask_mnemonic;static const mask_mnemonic mnemonic_table[] = { {_STRACE_ALL, "all"}, {_STRACE_FLUSH, "flush"}, {_STRACE_INHERIT, "inherit"}, {_STRACE_UHOH, "uhoh"}, {_STRACE_SYSCALL, "syscall"}, {_STRACE_STARTUP, "startup"}, {_STRACE_DEBUG, "debug"}, {_STRACE_PARANOID, "paranoid"}, {_STRACE_TERMIOS, "termios"}, {_STRACE_SELECT, "select"}, {_STRACE_WM, "wm"}, {_STRACE_SIGP, "sigp"}, {_STRACE_MINIMAL, "minimal"}, {_STRACE_EXITDUMP, "exitdump"}, {_STRACE_SYSTEM, "system"}, {_STRACE_NOMUTEX, "nomutex"}, {_STRACE_MALLOC, "malloc"}, {_STRACE_THREAD, "thread"}, {0, NULL}};static unsigned longmnemonic2ul (const char *nptr, char **endptr){ // Look up mnemonic in table, return value. // *endptr = ptr to char that breaks match. const mask_mnemonic *mnp = mnemonic_table; while (mnp->text != NULL) { if (strcmp (mnp->text, nptr) == 0) { // Found a match. if (endptr != NULL) { *endptr = ((char *) nptr) + strlen (mnp->text); } return mnp->val; } mnp++; } // Didn't find it. if (endptr != NULL) { *endptr = (char *) nptr; } return 0;}static unsigned longparse_mask (const char *ms, char **endptr){ const char *p = ms; char *newp; unsigned long retval = 0, thisval; const size_t bufsize = 16; char buffer[bufsize]; size_t len; while (*p != '\0') { // First extract the term, terminate it, and lowercase it. strncpy (buffer, p, bufsize); buffer[bufsize - 1] = '\0'; len = strcspn (buffer, "+,\0"); buffer[len] = '\0'; strlwr (buffer); // Check if this is a mnemonic. We have to do this first or strtoul() // will false-trigger on anything starting with "a" through "f". thisval = mnemonic2ul (buffer, &newp); if (buffer == newp) { // This term isn't mnemonic, check if it's hex. thisval = strtoul (buffer, &newp, 16); if (newp != buffer + len) { // Not hex either, syntax error. *endptr = (char *) p; return 0; } } p += len; retval += thisval; // Handle operators if (*p == '\0') break; if ((*p == '+') || (*p == ',')) { // For now these both equate to addition/ORing. Until we get // fancy and add things like "all-<something>", all we need do is // continue the looping. p++; continue; } else { // Syntax error *endptr = (char *) p; return 0; } } *endptr = (char *) p; return retval;}static voidusage (FILE *where = stderr){ fprintf (where, "\Usage: %s [OPTIONS] <command-line>\n\Usage: %s [OPTIONS] -p <pid>\n\ -b, --buffer-size=SIZE set size of output file buffer\n\ -d, --no-delta don't display the delta-t microsecond timestamp\n\ -f, --trace-children trace child processes (toggle - default true)\n\ -h, --help output usage information and exit\n\ -m, --mask=MASK set message filter mask\n\ -n, --crack-error-numbers output descriptive text instead of error\n\ numbers for Windows errors\n\ -o, --output=FILENAME set output file to FILENAME\n\ -p, --pid=n attach to executing program with cygwin pid n\n\ -S, --flush-period=PERIOD flush buffered strace output every PERIOD secs\n\ -t, --timestamp use an absolute hh:mm:ss timestamp insted of \n\ the default microsecond timestamp. Implies -d\n\ -T, --toggle toggle tracing in a process already being\n\ traced. Requires -p <pid>\n\ -v, --version output version information and exit\n\ -w, --new-window spawn program under test in a new window\n\\n", pgm, pgm); if ( where == stdout) fprintf (stdout, "\ MASK can be any combination of the following mnemonics and/or hex values\n\ (0x is optional). Combine masks with '+' or ',' like so:\n\\n\ --mask=wm+system,malloc+0x00800\n\\n\ Mnemonic Hex Corresponding Def Description\n\ =========================================================================\n\ all 0x00001 (_STRACE_ALL) All strace messages.\n\ flush 0x00002 (_STRACE_FLUSH) Flush output buffer after each message.\n\ inherit 0x00004 (_STRACE_INHERIT) Children inherit mask from parent.\n\ uhoh 0x00008 (_STRACE_UHOH) Unusual or weird phenomenon.\n\ syscall 0x00010 (_STRACE_SYSCALL) System calls.\n\ startup 0x00020 (_STRACE_STARTUP) argc/envp printout at startup.\n\ debug 0x00040 (_STRACE_DEBUG) Info to help debugging. \n\ paranoid 0x00080 (_STRACE_PARANOID) Paranoid info.\n\ termios 0x00100 (_STRACE_TERMIOS) Info for debugging termios stuff.\n\ select 0x00200 (_STRACE_SELECT) Info on ugly select internals.\n\ wm 0x00400 (_STRACE_WM) Trace Windows msgs (enable _strace_wm).\n\ sigp 0x00800 (_STRACE_SIGP) Trace signal and process handling.\n\ minimal 0x01000 (_STRACE_MINIMAL) Very minimal strace output.\n\ exitdump 0x04000 (_STRACE_EXITDUMP) Dump strace cache on exit.\n\ system 0x08000 (_STRACE_SYSTEM) Serious error; goes to console and log.\n\ nomutex 0x10000 (_STRACE_NOMUTEX) Don't use mutex for synchronization.\n\ malloc 0x20000 (_STRACE_MALLOC) Trace malloc calls.\n\ thread 0x40000 (_STRACE_THREAD) Thread-locking calls.\n\"); if (where == stderr) fprintf (stderr, "Try '%s --help' for more information.\n", pgm); exit (where == stderr ? 1 : 0 );}struct option longopts[] = { {"buffer-size", required_argument, NULL, 'b'}, {"help", no_argument, NULL, 'h'}, {"flush-period", required_argument, NULL, 'S'}, {"mask", required_argument, NULL, 'm'}, {"new-window", no_argument, NULL, 'w'}, {"output", required_argument, NULL, 'o'}, {"no-delta", no_argument, NULL, 'd'}, {"pid", required_argument, NULL, 'p'}, {"timestamp", no_argument, NULL, 't'}, {"toggle", no_argument, NULL, 'T'}, {"trace-children", no_argument, NULL, 'f'}, {"translate-error-numbers", no_argument, NULL, 'n'}, {"usecs", no_argument, NULL, 'u'}, {"version", no_argument, NULL, 'v'}, {NULL, 0, NULL, 0}};static const char *const opts = "b:dhfm:no:p:S:tTuvw";static voidprint_version (){ const char *v = strchr (version, ':'); int len; if (!v) { v = "?"; len = 1; } else { v += 2; len = strchr (v, ' ') - v; } printf ("\%s (cygwin) %.*s\n\System Trace\n\Copyright 2000, 2001, 2002 Red Hat, Inc.\n\Compiled on %s\n\", pgm, len, v, __DATE__);}intmain (int argc, char **argv){ unsigned mask = 0; FILE *ofile = NULL; pid_t pid = 0; int opt; int toggle = 0; if (!(pgm = strrchr (*argv, '\\')) && !(pgm = strrchr (*argv, '/'))) pgm = *argv; else pgm++; while ((opt = getopt_long (argc, argv, opts, longopts, NULL)) != EOF) switch (opt) { case 'b': bufsize = atoi (optarg); break; case 'd': delta ^= 1; break; case 'f': forkdebug ^= 1; break; case 'h': // Print help and exit usage (stdout); break; case 'm': { char *endptr; mask = parse_mask (optarg, &endptr); if (*endptr != '\0') { // Bad mask expression. error (0, "syntax error in mask expression \"%s\" near \character #%d.\n", optarg, (int) (endptr - optarg), endptr); } break; } case 'n': numerror ^= 1; break; case 'o': if ((ofile = fopen (optarg, "w")) == NULL) error (1, "can't open %s", optarg);#ifdef F_SETFD (void) fcntl (fileno (ofile), F_SETFD, 0);#endif break; case 'p': pid = strtoul (optarg, NULL, 10); break; case 'S': flush_period = strtoul (optarg, NULL, 10); break; case 't': hhmmss ^= 1; break; case 'T': toggle ^= 1; break; case 'u': // FIXME: currently unimplemented usecs ^= 1; break; case 'v': // Print version info and exit print_version (); return 0; case 'w': new_window ^= 1; break; case '?': fprintf (stderr, "Try '%s --help' for more information.\n", pgm); exit (1); } if (pid && argv[optind]) error (0, "cannot provide both a command line and a process id"); if (!pid && !argv[optind]) error (0, "must provide either a command line or a process id"); if (toggle && !pid) error (0, "must provide a process id to toggle tracing"); if (!mask) mask = 1; if (bufsize) setvbuf (ofile, (char *) alloca (bufsize), _IOFBF, bufsize); if (!ofile) ofile = stdout; if (toggle) dotoggle (pid); else dostrace (mask, ofile, pid, argv + optind);}#undef CloseHandlestatic BOOLclose_handle (HANDLE h, DWORD ok){ child_list *c; for (c = &children; (c = c->next) != NULL;) if (c->hproc == h && c->id != ok) error (0, "Closing child handle %p", h); return CloseHandle (h);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -