[Ltrace-devel] [PATCH 6/11] enumerations

Steve Fink sphink at gmail.com
Sat Aug 5 23:56:46 UTC 2006


-------------- next part --------------
From 6f25f69301f3c7c187f12bac451647fe117e6e35 Mon Sep 17 00:00:00 2001
From: Steve Fink sphink at gmail.com <sphink at gmail.com>
Date: Thu, 27 Jul 2006 08:38:56 -0700
Subject: [PATCH 6/11] Implement enumerated parameters
---
 ChangeLog                              |    4 +
 display_args.c                         |   14 ++++
 etc/ltrace.conf                        |    9 ++
 ltrace.h                               |    8 ++
 read_config_file.c                     |  120 +++++++++++++++++++++++++++++++-
 testsuite/ltrace.main/parameters-lib.c |    5 +
 testsuite/ltrace.main/parameters.c     |   18 +++++
 testsuite/ltrace.main/parameters.conf  |    1 
 testsuite/ltrace.main/parameters.exp   |    2 +
 9 files changed, 177 insertions(+), 4 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index f361d52..83940b8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,9 @@
 2006-07-20    Steve Fink <sphink at gmail.com>
 
+	* various: Implement enumerated parameters
+
+2006-07-21    <sphink at gmail.com>
+
 	* various: add pointers as valid parameter descriptor
 	* display_args.c: switch to passing around values rather than
 	  argument numbers that need to be fetched (needed for pointer params)
diff --git a/display_args.c b/display_args.c
index 66a9093..2a6b34f 100644
--- a/display_args.c
+++ b/display_args.c
@@ -42,6 +42,18 @@ static int display_pointer(enum tof type
       return display_value(type, proc, pointed_to, inner);
 }
 
+static int display_enum(enum tof type, struct process *proc,
+                        arg_type_info* info, long value)
+{
+    int ii;
+    for (ii = 0; ii < info->u.enum_info.entries; ++ii) {
+	if (info->u.enum_info.values[ii] == value)
+	    return fprintf(output, "%s", info->u.enum_info.keys[ii]);
+    }
+
+    return display_unknown(type, proc, value);
+}
+
 /* Args:
    type - syscall or shared library function or memory
    proc - information about the traced process
@@ -94,6 +106,8 @@ int display_value(enum tof type, struct 
 		return display_string(type, proc, (void*) value,
 				      get_length(type, proc,
 						 info->u.string_n_info.size_spec));
+        case ARGTYPE_ENUM:
+		return display_enum(type, proc, info, value);
 	case ARGTYPE_POINTER:
 		return display_pointer(type, proc, value, info);
  	case ARGTYPE_UNKNOWN:
diff --git a/etc/ltrace.conf b/etc/ltrace.conf
index 547a125..bff45fa 100644
--- a/etc/ltrace.conf
+++ b/etc/ltrace.conf
@@ -24,11 +24,20 @@
 ; string[N]     == (char *)             [N>0]   [show only up to N bytes]
 ; ignore	== (any)			[ignore arg, output blank]
 ; type*		== (type *)			[pointer to any other type]
+; enum (key=value,key=value,...)		[enumeration, see below]
 
 ; Backwards-compatibility:
 ; string0	== (char *)			[same as string[retval]]
 ; stringN	== (char *)		[N>0]	[same as string[argN]]
 
+; Enumerations
+;
+; The syntax is a parenthesized list of key=value assignments, like so:
+;   enum (F_DUPFD=0,F_GETFD=1,F_SETFD=2)
+; an example usage might look like
+;   int fcntl(int,enum (F_DUPFD=0,F_GETFD=1,F_SETFD=2))
+;
+
 ; arpa/inet.h
 int inet_aton(string,addr);
 string inet_ntoa(addr);			; It isn't a ADDR but an hexa number...
diff --git a/ltrace.h b/ltrace.h
index e649bb1..3b40cb3 100644
--- a/ltrace.h
+++ b/ltrace.h
@@ -42,6 +42,7 @@ enum arg_type {
 	ARGTYPE_FORMAT,		/* printf-like format */
 	ARGTYPE_STRING,		/* NUL-terminated string */
 	ARGTYPE_STRING_N,	/* String of known maxlen */
+        ARGTYPE_ENUM,		/* Enumeration */
         ARGTYPE_IGNORE,		/* Leave parameter blank */
         ARGTYPE_POINTER,	/* Pointer to some other type */
         ARGTYPE_COUNT		/* number of ARGTYPE_* values */
@@ -50,6 +51,13 @@ enum arg_type {
 typedef struct arg_type_info_t {
     enum arg_type type;
     union {
+	// ARGTYPE_ENUM
+	struct {
+	    size_t entries;
+	    char **keys;
+	    int *values;
+	} enum_info;
+
 	// ARGTYPE_STRING_N
 	struct {
 	    int size_spec;
diff --git a/read_config_file.c b/read_config_file.c
index 15c3f39..5b114de 100644
--- a/read_config_file.c
+++ b/read_config_file.c
@@ -11,6 +11,10 @@ #include "read_config_file.h"
 #include "output.h"
 #include "debug.h"
 
+static int line_no;
+static char *filename;
+static int error_count = 0;
+
 struct function *list_of_functions = NULL;
 
 static struct list_of_pt_t {
@@ -29,6 +33,7 @@ static struct list_of_pt_t {
 	"file", ARGTYPE_FILE}, {
 	"format", ARGTYPE_FORMAT}, {
 	"string", ARGTYPE_STRING}, {
+	"enum", ARGTYPE_ENUM}, {
 	"ignore", ARGTYPE_IGNORE}, {
 	NULL, ARGTYPE_UNKNOWN}	/* Must finish with NULL */
 };
@@ -46,6 +51,7 @@ static arg_type_info arg_type_singletons
 	{ ARGTYPE_FORMAT },
 	{ ARGTYPE_STRING },
 	{ ARGTYPE_STRING_N },
+	{ ARGTYPE_ENUM },
 	{ ARGTYPE_IGNORE },
 	{ ARGTYPE_POINTER },
 	{ ARGTYPE_UNKNOWN }
@@ -81,6 +87,32 @@ static void eat_spaces(char **str)
 	}
 }
 
+static char *xstrndup(char *str, size_t len)
+{
+    char *ret = (char *) malloc(len + 1);
+    strncpy(ret, str, len);
+    ret[len] = 0;
+    return ret;
+}
+
+static char *parse_ident(char **str)
+{
+    char *ident = *str;
+
+    if (!isalnum(**str) && **str != '_') {
+	output_line(0, "Syntax error in `%s', line %d: Bad identifier",
+		    filename, line_no);
+	error_count++;
+	return NULL;
+    }
+
+    while (**str && (isalnum(**str) || **str == '_')) {
+	++(*str);
+    }
+
+    return xstrndup(ident, *str - ident);
+}
+
 /*
   Returns position in string at the left parenthesis which starts the
   function's argument signature. Returns NULL on error.
@@ -119,12 +151,17 @@ static char *start_of_arg_sig(char *str)
 */
 static int simple_type(enum arg_type at)
 {
+    switch (at) {
+    case ARGTYPE_STRING:
+    case ARGTYPE_STRING_N:
+    case ARGTYPE_ENUM:
+	return 0;
+
+    default:
 	return 1;
+    }
 }
 
-static int line_no;
-static char *filename;
-
 static int parse_int(char **str)
 {
     char *end;
@@ -132,6 +169,7 @@ static int parse_int(char **str)
     if (end == *str) {
 	output_line(0, "Syntax error in `%s', line %d: Bad number",
 		    filename, line_no);
+	error_count++;
 	return 0;
     }
 
@@ -191,6 +229,73 @@ static arg_type_info *parse_nonpointer_t
 
 	switch (info->type) {
 
+	// Syntax: enum ( keyname=value,keyname=value,... )
+	case ARGTYPE_ENUM:{
+	    struct enum_opt {
+		char *key;
+		int value;
+		struct enum_opt *next;
+	    };
+	    struct enum_opt *list = NULL;
+	    struct enum_opt *p;
+	    int entries = 0;
+	    int ii;
+
+	    eat_spaces(str);
+	    (*str)++;		// Get past open paren
+	    eat_spaces(str);
+
+	    while (**str && **str != ')') {
+		p = (struct enum_opt *) malloc(sizeof(*p));
+		eat_spaces(str);
+		p->key = parse_ident(str);
+		if (error_count) {
+		    free(p);
+		    return NULL;
+		}
+		eat_spaces(str);
+		if (**str != '=') {
+		    free(p->key);
+		    free(p);
+		    output_line(0,
+				"Syntax error in `%s', line %d: expected '=', got '%c'",
+				filename, line_no, **str);
+		    error_count++;
+		    return NULL;
+		}
+		++(*str);
+		eat_spaces(str);
+		p->value = parse_int(str);
+		p->next = list;
+		list = p;
+		++entries;
+
+		// Skip comma
+		eat_spaces(str);
+		if (**str == ',') {
+		    (*str)++;
+		    eat_spaces(str);
+		}
+	    }
+
+	    info->u.enum_info.entries = entries;
+	    info->u.enum_info.keys =
+		(char **) malloc(entries * sizeof(char *));
+	    info->u.enum_info.values =
+		(int *) malloc(entries * sizeof(int));
+	    for (ii = 0, p = NULL; list; ++ii, list = list->next) {
+		if (p)
+		    free(p);
+		info->u.enum_info.keys[ii] = list->key;
+		info->u.enum_info.values[ii] = list->value;
+		p = list;
+	    }
+	    if (p)
+		free(p);
+
+	    return info;
+	}
+
 	case ARGTYPE_STRING:
 	    if (!isdigit(**str) && **str != '[') {
 		/* Oops, was just a simple string after all */
@@ -217,6 +322,7 @@ static arg_type_info *parse_nonpointer_t
 		output_line(0, "Syntax error in `%s', line %d: Unknown type encountered",
 			    filename, line_no);
 		free(info);
+		error_count++;
 		return NULL;
 	}
 }
@@ -258,6 +364,7 @@ static struct function *process_line(cha
 	if (!tmp) {
 		output_line(0, "Syntax error in `%s', line %d", filename,
 			    line_no);
+		error_count++;
 		return NULL;
 	}
 	*tmp = '\0';
@@ -281,6 +388,7 @@ static struct function *process_line(cha
 			output_line(0, "Syntax error in `%s', line %d"
                                     ": unknown argument type",
 				    filename, line_no);
+			error_count++;
 			return NULL;
 		}
 		eat_spaces(&str);
@@ -294,6 +402,7 @@ static struct function *process_line(cha
 				str[strlen(str) - 1] = '\0';
 			output_line(0, "Syntax error in `%s', line %d at ...\"%s\"",
 				    filename, line_no, str);
+			error_count++;
 			return NULL;
 		}
 	}
@@ -318,7 +427,10 @@ void read_config_file(char *file)
 	}
 	line_no = 0;
 	while (fgets(buf, 1024, stream)) {
-		struct function *tmp = process_line(buf);
+		struct function *tmp;
+
+		error_count = 0;
+		tmp = process_line(buf);
 
 		if (tmp) {
 			debug(2, "New function: `%s'", tmp->name);
diff --git a/testsuite/ltrace.main/parameters-lib.c b/testsuite/ltrace.main/parameters-lib.c
index bc320cf..b43de08 100644
--- a/testsuite/ltrace.main/parameters-lib.c
+++ b/testsuite/ltrace.main/parameters-lib.c
@@ -36,3 +36,8 @@ void func_stringp(char** sP)
 {
 	printf("%s\n", *sP);
 }
+
+void func_enum(int x)
+{
+	printf("enum: %d\n", x);
+}
diff --git a/testsuite/ltrace.main/parameters.c b/testsuite/ltrace.main/parameters.c
index e26e0a6..d7c225f 100644
--- a/testsuite/ltrace.main/parameters.c
+++ b/testsuite/ltrace.main/parameters.c
@@ -20,6 +20,15 @@ void func_strfixed(char*);
 void func_ppp(int***);
 void func_stringp(char**);
 
+typedef enum {
+  RED,
+  GREEN,
+  BLUE,
+  CHARTREUSE,
+  PETUNIA
+} color_t;
+void func_enum(color_t);
+
 int 
 main ()
 {
@@ -27,18 +36,27 @@ main ()
   int *xP, **xPP;
   char buf[200];
   char *s;
+
   func_ignore(1, 2, 3);
+
   func_intptr(&x);
+
   func_intptr_ret(&x);
+
   func_strlen(buf);
   printf("%s\n", buf);
+
   func_strfixed(buf);
   printf("%s\n", buf);
+
   x = 80;
   xP = &x;
   xPP = &xP;
   func_ppp(&xPP);
+
   s = (char*) malloc(100);
   strcpy(s, "Dude");
   func_stringp(&s);
+
+  func_enum(BLUE);
 }
diff --git a/testsuite/ltrace.main/parameters.conf b/testsuite/ltrace.main/parameters.conf
index 7690f89..debb1dc 100644
--- a/testsuite/ltrace.main/parameters.conf
+++ b/testsuite/ltrace.main/parameters.conf
@@ -5,3 +5,4 @@ int func_strlen(+string[retval])
 void func_strfixed(string[4])
 void func_ppp(int***)
 void func_stringp(string*)
+void func_enum(enum (RED=0,GREEN=1,BLUE=2,CHARTREUSE=3,PETUNIA=4))
diff --git a/testsuite/ltrace.main/parameters.exp b/testsuite/ltrace.main/parameters.exp
index 21a02b4..024c3f3 100644
--- a/testsuite/ltrace.main/parameters.exp
+++ b/testsuite/ltrace.main/parameters.exp
@@ -50,3 +50,5 @@ set pattern "func_ppp(80)"
 ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern 1
 set pattern "func_stringp(\\\"Dude\\\")"
 ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern 1
+set pattern "func_enum(BLUE)"
+ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern 1
-- 
1.4.1


More information about the Ltrace-devel mailing list