* strace.cc (main): Change getopt() to getopt_long().
Add support for help and version info. Use new parse_mask() function for -m/--mask option. (longopts): Add long options structure. (opts): Move options string from getopts call to static var. (usage): Print usage information. (SCCSid): Version info. (version): New function for displaying version info. (parse_mask): New function supporting parsing of mnemonics, hex, and basic expressions in masks. (mnemonic2ul): New mnemonic parsing function. (tag_mask_mnemonic): New type. (mnemonic_table): New table of mnemonics for mnemonic2ul() to search through.
This commit is contained in:
		| @@ -1,3 +1,20 @@ | |||||||
|  | 2001-11-15  Gary R. Van Sickle  <g.r.vansickle@worldnet.att.net> | ||||||
|  |  | ||||||
|  | 	* strace.cc (main): Change getopt() to getopt_long(). | ||||||
|  | 	Add support for help and version info. | ||||||
|  | 	Use new parse_mask() function for -m/--mask option. | ||||||
|  | 	(longopts): Add long options structure. | ||||||
|  | 	(opts): Move options string from getopts call to static var. | ||||||
|  | 	(usage): Print usage information. | ||||||
|  | 	(SCCSid): Version info. | ||||||
|  | 	(version): New function for displaying version info. | ||||||
|  | 	(parse_mask): New function supporting parsing of mnemonics, | ||||||
|  | 	hex, and basic expressions in masks. | ||||||
|  | 	(mnemonic2ul): New mnemonic parsing function. | ||||||
|  | 	(tag_mask_mnemonic): New type. | ||||||
|  | 	(mnemonic_table): New table of mnemonics for mnemonic2ul() to | ||||||
|  | 	search through. | ||||||
|  |  | ||||||
| 2001-11-12  Corinna Vinschen  <corinna@vinschen.de> | 2001-11-12  Corinna Vinschen  <corinna@vinschen.de> | ||||||
|  |  | ||||||
| 	* cygcheck.cc (dump_sysinfo): Redefine output format slightly. | 	* cygcheck.cc (dump_sysinfo): Redefine output format slightly. | ||||||
|   | |||||||
| @@ -30,6 +30,9 @@ int _impure_ptr; | |||||||
| /* we *know* we're being built with GCC */ | /* we *know* we're being built with GCC */ | ||||||
| #define alloca __builtin_alloca | #define alloca __builtin_alloca | ||||||
|  |  | ||||||
|  | // Version string. | ||||||
|  | static char *SCCSid = "@(#)strace V1.0, Copyright (C) 2001 Red Hat Inc., " __DATE__ "\n"; | ||||||
|  |  | ||||||
| static const char *pgm; | static const char *pgm; | ||||||
| static int forkdebug = 0; | static int forkdebug = 0; | ||||||
| static int numerror = 1; | static int numerror = 1; | ||||||
| @@ -602,6 +605,196 @@ dostrace (unsigned mask, FILE *ofile, char **argv) | |||||||
|   return; |   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 long | ||||||
|  | mnemonic2ul (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 long | ||||||
|  | parse_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 void | ||||||
|  | usage () | ||||||
|  | { | ||||||
|  |   fprintf (stderr, "\ | ||||||
|  | Usage: strace [OPTIONS] <command-line>\n\ | ||||||
|  |   -b, --buffer-size=SIZE       Set size of output file buffer.\n\ | ||||||
|  |   -m, --mask=MASK              Set message filter mask.\n\ | ||||||
|  | \n\ | ||||||
|  |     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)   Cache strace messages.\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\ | ||||||
|  | \n\ | ||||||
|  |   -o, --output=FILENAME        Set output file to FILENAME.\n\ | ||||||
|  |   -f, --trace-children         Also trace forked child processes.\n\ | ||||||
|  |   -n, --crack-error-numbers    Output descriptive text instead of error\n\ | ||||||
|  |                                  numbers for Windows errors.\n\ | ||||||
|  |   -d, --no-delta               Don't display the delta-t microsecond timestamp.\n\ | ||||||
|  |   -t, --timestamp              Use an absolute hh:mm:ss timestamp insted of the\n\ | ||||||
|  |                                  default microsecond timestamp.  Implies -d.\n\ | ||||||
|  |   -w, --new-window             Spawn program under test in a new window.\n\ | ||||||
|  |   -S, --flush-period=PERIOD    Flush buffered strace output every PERIOD secs.\n\ | ||||||
|  |   -v, --version                Display version info.\n\ | ||||||
|  |   -h, --help                   Display this help info.\n\ | ||||||
|  | "); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static void | ||||||
|  | version () | ||||||
|  | { | ||||||
|  |   fprintf (stderr, SCCSid+4); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | struct option longopts[] = { | ||||||
|  |   {"help", no_argument, NULL, 'h'}, | ||||||
|  |   {"version", no_argument, NULL, 'v'}, | ||||||
|  |   {"buffer-size", required_argument, NULL, 'b'}, | ||||||
|  |   {"mask", required_argument, NULL, 'm'}, | ||||||
|  |   {"output", required_argument, NULL, 'o'}, | ||||||
|  |   {"trace-children", no_argument, NULL, 'f'}, | ||||||
|  |   {"crack-error-numbers", no_argument, NULL, 'n'}, | ||||||
|  |   {"no-delta", no_argument, NULL, 'd'}, | ||||||
|  |   {"usecs", no_argument, NULL, 'u'}, | ||||||
|  |   {"timestamp", no_argument, NULL, 't'}, | ||||||
|  |   {"new-window", no_argument, NULL, 'w'}, | ||||||
|  |   {"flush-period", required_argument, NULL, 'S'}, | ||||||
|  |   {NULL, 0, NULL, 0} | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | static const char *const opts = "hvb:m:o:fndutwS:"; | ||||||
|  |  | ||||||
| int | int | ||||||
| main (int argc, char **argv) | main (int argc, char **argv) | ||||||
| { | { | ||||||
| @@ -614,9 +807,19 @@ main (int argc, char **argv) | |||||||
|   else |   else | ||||||
|     pgm++; |     pgm++; | ||||||
|  |  | ||||||
|   while ((opt = getopt (argc, argv, "b:m:o:fndutwS:")) != EOF) |   while ((opt = getopt_long (argc, argv, opts, longopts, NULL)) != EOF) | ||||||
|     switch (opt) |     switch (opt) | ||||||
|       { |       { | ||||||
|  |       case 'h': | ||||||
|  | 	// Print help and exit | ||||||
|  | 	usage (); | ||||||
|  | 	return 1; | ||||||
|  | 	break; | ||||||
|  |       case 'v': | ||||||
|  | 	// Print version info and exit | ||||||
|  | 	version (); | ||||||
|  | 	return 1; | ||||||
|  | 	break; | ||||||
|       case 'f': |       case 'f': | ||||||
| 	forkdebug ^= 1; | 	forkdebug ^= 1; | ||||||
| 	break; | 	break; | ||||||
| @@ -624,8 +827,17 @@ main (int argc, char **argv) | |||||||
| 	bufsize = atoi (optarg); | 	bufsize = atoi (optarg); | ||||||
| 	break; | 	break; | ||||||
|       case 'm': |       case 'm': | ||||||
| 	mask = strtoul (optarg, NULL, 16); | 	{ | ||||||
|  | 	  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; | 	break; | ||||||
|  | 	} | ||||||
|       case 'o': |       case 'o': | ||||||
| 	if ((ofile = fopen (optarg, "w")) == NULL) | 	if ((ofile = fopen (optarg, "w")) == NULL) | ||||||
| 	  error (1, "can't open %s", optarg); | 	  error (1, "can't open %s", optarg); | ||||||
| @@ -643,6 +855,9 @@ main (int argc, char **argv) | |||||||
| 	delta ^= 1; | 	delta ^= 1; | ||||||
| 	break; | 	break; | ||||||
|       case 'u': |       case 'u': | ||||||
|  |     // FIXME: This option isn't handled properly/at all by the | ||||||
|  |     // program's logic.  It seems to be the default, does it | ||||||
|  |     // need to just be removed? | ||||||
| 	usecs ^= 1; | 	usecs ^= 1; | ||||||
| 	break; | 	break; | ||||||
|       case 'w': |       case 'w': | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user