[Ltrace-devel] r64 - in ltrace/trunk: . etc testsuite/ltrace.main

Ian Wienand ianw-guest at costa.debian.org
Mon Aug 7 04:10:12 UTC 2006


Author: ianw-guest
Date: 2006-08-07 04:10:08 +0000 (Mon, 07 Aug 2006)
New Revision: 64

Modified:
   ltrace/trunk/ChangeLog
   ltrace/trunk/display_args.c
   ltrace/trunk/etc/ltrace.conf
   ltrace/trunk/ltrace.h
   ltrace/trunk/read_config_file.c
   ltrace/trunk/testsuite/ltrace.main/parameters-lib.c
   ltrace/trunk/testsuite/ltrace.main/parameters.c
   ltrace/trunk/testsuite/ltrace.main/parameters.conf
   ltrace/trunk/testsuite/ltrace.main/parameters.exp
Log:
add struct support


Modified: ltrace/trunk/ChangeLog
===================================================================
--- ltrace/trunk/ChangeLog	2006-08-07 04:04:43 UTC (rev 63)
+++ ltrace/trunk/ChangeLog	2006-08-07 04:10:08 UTC (rev 64)
@@ -1,5 +1,17 @@
 2006-08-07  Steve Fink <sphink at gmail.com>
 
+	* display_args.c, etc/ltrace.conf, ltrace.h, read_config_file.c,
+	testsuite/ltrace.main/parameters-lib.c,
+	testsuite/ltrace.main/parameters.c,
+	testsuite/ltrace.main/parameters.conf,
+	testsuite/ltrace.main/parameters.exp: Allow parameters to be
+	pointers to structs, which themselves can contain
+	(nearly) any other type, including other structs or pointers to
+	structs.
+
+
+2006-08-07  Steve Fink <sphink at gmail.com>
+
 	* defs.h, display_args.c, etc/ltrace.conf, ltrace.1, ltrace.h,
 	options.c, options.h, read_config_file.c,
 	testsuite/ltrace.main/parameters-lib.c,

Modified: ltrace/trunk/display_args.c
===================================================================
--- ltrace/trunk/display_args.c	2006-08-07 04:04:43 UTC (rev 63)
+++ ltrace/trunk/display_args.c	2006-08-07 04:10:08 UTC (rev 64)
@@ -15,27 +15,35 @@
 static int display_string(enum tof type, struct process *proc,
 			  void* addr, size_t maxlen);
 static int display_value(enum tof type, struct process *proc,
-			 long value, arg_type_info *info);
+			 long value, arg_type_info *info,
+			 void *st, arg_type_info* st_info);
 static int display_unknown(enum tof type, struct process *proc, long value);
 static int display_format(enum tof type, struct process *proc, int arg_num);
 
 static int string_maxlength = INT_MAX;
 static int array_maxlength = INT_MAX;
 
-static long get_length(enum tof type, struct process *proc, int len_spec)
+static long get_length(enum tof type, struct process *proc, int len_spec,
+		       void *st, arg_type_info* st_info)
 {
+    long len;
     if (len_spec > 0)
 	return len_spec;
+    if (type == LT_TOF_STRUCT) {
+	umovelong(proc, st + st_info->u.struct_info.offset[-len_spec-1], &len);
+	return len;
+    }
     return gimme_arg(type, proc, -len_spec - 1);
 }
 
 static int display_ptrto(enum tof type, struct process *proc, long item,
-			 arg_type_info * info)
+			 arg_type_info * info,
+			 void *st, arg_type_info* st_info)
 {
     arg_type_info temp;
     temp.type = ARGTYPE_POINTER;
     temp.u.ptr_info.info = info;
-    return display_value(type, proc, item, &temp);
+    return display_value(type, proc, item, &temp, st, st_info);
 }
 
 /*
@@ -47,7 +55,8 @@
  * pointer to that region of memory.
  */
 static int display_arrayptr(enum tof type, struct process *proc,
-			    void *addr, arg_type_info * info)
+			    void *addr, arg_type_info * info,
+			    void *st, arg_type_info* st_info)
 {
     int len = 0;
     int i;
@@ -56,7 +65,8 @@
     if (addr == NULL)
 	return fprintf(output, "NULL");
 
-    array_len = get_length(type, proc, info->u.array_info.len_spec);
+    array_len = get_length(type, proc, info->u.array_info.len_spec,
+			   st, st_info);
     len += fprintf(output, "[ ");
     for (i = 0; i < opt_A && i < array_maxlength && i < array_len; i++) {
 	arg_type_info *elt_type = info->u.array_info.elt_type;
@@ -66,7 +76,7 @@
 	if (opt_d)
 	    len += fprintf(output, "%p=", addr);
 	len +=
-	    display_ptrto(type, proc, (long) addr, elt_type);
+	    display_ptrto(type, proc, (long) addr, elt_type, st, st_info);
 	addr += elt_size;
     }
     if (i < array_len)
@@ -75,21 +85,57 @@
     return len;
 }
  
+/* addr - A pointer to the beginning of the memory region occupied by
+ *        the struct (aka a pointer to the struct)
+ */
+static int display_structptr(enum tof type, struct process *proc,
+			     void *addr, arg_type_info * info)
+{
+    int i;
+    arg_type_info *field;
+    int len = 0;
+
+    if (addr == NULL)
+	return fprintf(output, "NULL");
+
+    len += fprintf(output, "{ ");
+    for (i = 0; (field = info->u.struct_info.fields[i]) != NULL; i++) {
+	if (i != 0)
+	    len += fprintf(output, ", ");
+	if (opt_d)
+	    len +=
+		fprintf(output, "%p=",
+			addr + info->u.struct_info.offset[i]);
+	len +=
+	    display_ptrto(LT_TOF_STRUCT, proc,
+			  (long) addr + info->u.struct_info.offset[i],
+			  field, addr, info);
+    }
+    len += fprintf(output, " }");
+
+    return len;
+}
+
 static int display_pointer(enum tof type, struct process *proc, long value,
-			   arg_type_info * info)
+			   arg_type_info * info,
+			   void *st, arg_type_info* st_info)
 {
     long pointed_to;
     arg_type_info *inner = info->u.ptr_info.info;
 
     if (inner->type == ARGTYPE_ARRAY) {
-	return display_arrayptr(type, proc, (void*) value, inner);
+	return display_arrayptr(type, proc, (void*) value, inner,
+				st, st_info);
+    } else if (inner->type == ARGTYPE_STRUCT) {
+	return display_structptr(type, proc, (void *) value, inner);
     } else {
 	if (value == 0)
 	    return fprintf(output, "NULL");
 	else if (umovelong(proc, (void *) value, &pointed_to) < 0)
 	    return fprintf(output, "?");
 	else
-	    return display_value(type, proc, pointed_to, inner);
+	    return display_value(type, proc, pointed_to, inner,
+				 st, st_info);
     }
 }
 
@@ -110,9 +156,15 @@
    proc - information about the traced process
    value - the value to display
    info - the description of the type to display
+   st - if the current value is a struct member, the address of the struct
+   st_info - type of the above struct
+
+   Those last two parameters are used for structs containing arrays or
+   strings whose length is given by another structure element.
 */
 int display_value(enum tof type, struct process *proc,
-                  long value, arg_type_info *info)
+                  long value, arg_type_info *info,
+		  void *st, arg_type_info* st_info)
 {
 	int tmp;
 
@@ -165,13 +217,16 @@
 	case ARGTYPE_STRING_N:
 		return display_string(type, proc, (void*) value,
 				      get_length(type, proc,
-						 info->u.string_n_info.size_spec));
+						 info->u.string_n_info.size_spec, st, st_info));
 	case ARGTYPE_ARRAY:
 		return fprintf(output, "<array without address>");
         case ARGTYPE_ENUM:
 		return display_enum(type, proc, info, value);
+	case ARGTYPE_STRUCT:
+		return fprintf(output, "<struct without address>");
 	case ARGTYPE_POINTER:
-		return display_pointer(type, proc, value, info);
+		return display_pointer(type, proc, value, info,
+				       st, st_info);
  	case ARGTYPE_UNKNOWN:
 	default:
 		return display_unknown(type, proc, value);
@@ -189,7 +244,7 @@
 	return display_format(type, proc, arg_num);
     } else {
 	arg = gimme_arg(type, proc, arg_num);
-	return display_value(type, proc, arg, info);
+	return display_value(type, proc, arg, info, NULL, NULL);
     }
 }
 

Modified: ltrace/trunk/etc/ltrace.conf
===================================================================
--- ltrace/trunk/etc/ltrace.conf	2006-08-07 04:04:43 UTC (rev 63)
+++ ltrace/trunk/etc/ltrace.conf	2006-08-07 04:10:08 UTC (rev 64)
@@ -21,6 +21,7 @@
 ; format	== ((const char *), ...)	[printf() like]		[TODO]
 ; string	== (char *)
 ; string[argN]  == (char *)		[N>0]	[show only up to (arg N) bytes]
+; string[eltN]  == (char *)		[N>0]	[show only up to (elt N) bytes]
 ; string[retval] == (char *)			[show only up to (return val) bytes]
 ; string[arg0]	== (char *)			[same as string[retval]]
 ; string[N]     == (char *)             [N>0]   [show only up to N bytes]
@@ -29,12 +30,18 @@
 ; enum (key=value,key=value,...)		[enumeration, see below]
 ; array(type,argN)
 ;		== (type[SIZE])			[array of (arg N) elements]
+; array(type,eltN)
+;		== (type[SIZE])			[array of (struct element N) elements]
 ; array(type,N)	== (type[N])			[array of N elements]
-
+; struct(type,type,...)
+;		== (struct {...})		[struct of several types]
+;
 ; Backwards-compatibility:
 ; string0	== (char *)			[same as string[retval]]
 ; stringN	== (char *)		[N>0]	[same as string[argN]]
 
+
+
 ; Typedefs
 ;
 ; To make it easier to specify argument lists, you can use 'typedef'
@@ -56,6 +63,37 @@
 ; NOTE: Uses of array(...) alone are very rare. You almost always
 ; want array(...)*. The exceptions are when you have a fixed-size
 ; array.
+;
+; Structs
+;
+; NOTE: Uses of struct(...) alone are very rare. You almost always
+; want struct(...)* (a pointer to a struct) anyway. Most compilers
+; pass structs as pointers anyway, and those that don't are not yet
+; supported. The one time when you want to use a non-pointer
+; struct(...) type are when you have an array of structs, or a struct
+; containing another struct.
+;
+; For example, if you have
+;   struct s1 {
+;	int y_size;
+;	int * y;
+;	int z[3];
+;	struct { char c; } a;
+;	struct { char c; } * b;
+;   }
+; and a function
+;   void f(struct s1*)
+; then the corresponding ltrace spec is
+;   void f(struct(int,array(int,elt0),array(int,3),struct(char),struct(char)*)*)
+; which, formatted similarly to the C declaration, looks like
+;   void f(struct(
+;                 int,
+;                 array(int,elt0),
+;                 array(int,3),
+;                 struct(char),
+;                 struct(char)*
+;                )*
+;         )
 
 
 ; arpa/inet.h

Modified: ltrace/trunk/ltrace.h
===================================================================
--- ltrace/trunk/ltrace.h	2006-08-07 04:04:43 UTC (rev 63)
+++ ltrace/trunk/ltrace.h	2006-08-07 04:10:08 UTC (rev 64)
@@ -47,6 +47,7 @@
 	ARGTYPE_STRING_N,	/* String of known maxlen */
         ARGTYPE_ARRAY,		/* Series of values in memory */
         ARGTYPE_ENUM,		/* Enumeration */
+        ARGTYPE_STRUCT,		/* Structure of values */
         ARGTYPE_IGNORE,		/* Leave parameter blank */
         ARGTYPE_POINTER,	/* Pointer to some other type */
         ARGTYPE_COUNT		/* number of ARGTYPE_* values */
@@ -74,6 +75,14 @@
 	    int size_spec;
 	} string_n_info;
 
+	// ARGTYPE_STRUCT
+	struct {
+	    struct arg_type_info_t **fields;	// NULL-terminated
+	    size_t *gap;
+	    size_t *offset;
+	    size_t size;
+	} struct_info;
+
 	// ARGTYPE_POINTER
 	struct {
 	    struct arg_type_info_t *info;
@@ -86,7 +95,8 @@
 	LT_TOF_FUNCTION,	/* A real library function */
 	LT_TOF_FUNCTIONR,	/* Return from a real library function */
 	LT_TOF_SYSCALL,		/* A syscall */
-	LT_TOF_SYSCALLR		/* Return from a syscall */
+	LT_TOF_SYSCALLR,	/* Return from a syscall */
+        LT_TOF_STRUCT		/* Not a function; read args from struct */
 };
 
 struct function {

Modified: ltrace/trunk/read_config_file.c
===================================================================
--- ltrace/trunk/read_config_file.c	2006-08-07 04:04:43 UTC (rev 63)
+++ ltrace/trunk/read_config_file.c	2006-08-07 04:10:08 UTC (rev 64)
@@ -19,6 +19,8 @@
 
 struct function *list_of_functions = NULL;
 
+/* Map of strings to type names. These do not need to be in any
+ * particular order */
 static struct list_of_pt_t {
 	char *name;
 	enum arg_type pt;
@@ -39,11 +41,15 @@
 	"format", ARGTYPE_FORMAT}, {
 	"string", ARGTYPE_STRING}, {
 	"array", ARGTYPE_ARRAY}, {
+	"struct", ARGTYPE_STRUCT}, {
 	"enum", ARGTYPE_ENUM}, {
 	"ignore", ARGTYPE_IGNORE}, {
 	NULL, ARGTYPE_UNKNOWN}	/* Must finish with NULL */
 };
 
+/* Array of singleton objects for each of the types. The order in this
+ * array must exactly match the list of enumerated values in
+ * ltrace.h */
 static arg_type_info arg_type_singletons[] = {
 	{ ARGTYPE_VOID },
 	{ ARGTYPE_INT },
@@ -62,6 +68,7 @@
 	{ ARGTYPE_STRING_N },
 	{ ARGTYPE_ARRAY },
 	{ ARGTYPE_ENUM },
+	{ ARGTYPE_STRUCT },
 	{ ARGTYPE_IGNORE },
 	{ ARGTYPE_POINTER },
 	{ ARGTYPE_UNKNOWN }
@@ -166,6 +173,7 @@
     case ARGTYPE_STRING_N:
     case ARGTYPE_ARRAY:
     case ARGTYPE_ENUM:
+    case ARGTYPE_STRUCT:
 	return 0;
 
     default:
@@ -178,8 +186,8 @@
     char *end;
     long n = strtol(*str, &end, 0);
     if (end == *str) {
-	output_line(0, "Syntax error in `%s', line %d: Bad number",
-		    filename, line_no);
+	output_line(0, "Syntax error in `%s', line %d: Bad number (%s)",
+		    filename, line_no, *str);
 	error_count++;
 	return 0;
     }
@@ -209,6 +217,9 @@
     if (strncmp(*str, "arg", 3) == 0) {
 	(*str) += 3;
 	multiplier = -1;
+    } else if (strncmp(*str, "elt", 3) == 0) {
+	(*str) += 3;
+	multiplier = -1;
     } else if (strncmp(*str, "retval", 6) == 0) {
 	(*str) += 6;
 	return 0;
@@ -289,6 +300,8 @@
 	return sizeof(float);
     } else if (arg->type == ARGTYPE_ENUM) {
 	return sizeof(int);
+    } else if (arg->type == ARGTYPE_STRUCT) {
+	return arg->u.struct_info.size;
     } else if (arg->type == ARGTYPE_ARRAY) {
 	if (arg->u.array_info.len_spec > 0)
 	    return arg->u.array_info.len_spec * arg->u.array_info.elt_size;
@@ -299,6 +312,63 @@
     }
 }
 
+/* I'm sure this isn't completely correct, but just try to get most of
+ * them right for now. */
+#undef alignof
+#define alignof(field,st) ((size_t) ((char*) &st.field - (char*) &st))
+static void align_struct(arg_type_info* info)
+{
+    struct {
+	char c;
+	int i;
+    } ci;
+    struct {
+	struct {
+	    char c;
+	} s;
+	int i;
+    } cis;
+
+    size_t int_alignment = alignof(i, ci);
+    size_t whole_struct_alignment = alignof(i, cis);
+
+    size_t offset;
+    size_t gap;
+    int i;
+
+    if (info->u.struct_info.size != 0)
+	return;			// Already done
+
+    // The gap array isn't actually needed anymore, because the
+    // offset can be used for everything.
+
+    // 1. Add internal padding
+    offset = 0;
+    for (i = 0; info->u.struct_info.fields[i] != NULL; i++) {
+	arg_type_info *field = info->u.struct_info.fields[i];
+	info->u.struct_info.offset[i] = offset;
+	offset += arg_sizeof(field);
+
+	if (offset % int_alignment != 0) {
+	    gap = int_alignment - offset % int_alignment;
+	    info->u.struct_info.gap[i] = gap;
+	    offset += gap;
+	}
+    }
+
+    // 2. Add padding at end of entire struct
+    for (i = 0; info->u.struct_info.fields[i] != NULL; i++);
+    if (i == 0)
+	return;
+    if (offset % whole_struct_alignment != 0) {
+	gap = whole_struct_alignment - offset % whole_struct_alignment;
+	info->u.struct_info.gap[i - 1] = gap;
+	offset += gap;
+    }
+
+    info->u.struct_info.size = offset;
+}
+
 static arg_type_info *parse_nonpointer_type(char **str)
 {
 	arg_type_info *simple;
@@ -432,6 +502,46 @@
 	    (*str)++;		// Skip past closing ]
 	    return info;
 
+	// Syntax: struct ( type,type,type,... )
+    case ARGTYPE_STRUCT:{
+	    int field_num = 0;
+	    (*str)++;		// Get past open paren
+	    info->u.struct_info.fields =
+		malloc((MAX_ARGS + 1) * sizeof(void *));
+	    info->u.struct_info.gap =
+		malloc((MAX_ARGS + 1) * sizeof(size_t));
+	    info->u.struct_info.offset =
+		malloc((MAX_ARGS + 1) * sizeof(size_t));
+	    info->u.struct_info.size = 0;
+	    eat_spaces(str); // Empty arg list with whitespace inside
+	    while (**str && **str != ')') {
+		if (field_num == MAX_ARGS) {
+		    output_line(0,
+				"Error in `%s', line %d: Too many structure elements",
+				filename, line_no);
+		    error_count++;
+		    return NULL;
+		}
+		eat_spaces(str);
+		if (field_num != 0) {
+		    (*str)++;	// Get past comma
+		    eat_spaces(str);
+		}
+		info->u.struct_info.gap[field_num] = 0;
+		if ((info->u.struct_info.fields[field_num++] =
+		     parse_type(str)) == NULL)
+		    return NULL;
+
+		// Must trim trailing spaces so the check for
+		// the closing paren is simple
+		eat_spaces(str);
+	    }
+	    (*str)++;		// Get past closing paren
+	    info->u.struct_info.fields[field_num] = NULL;
+	    align_struct(info);
+	    return info;
+	}
+
 	default:
 		output_line(0, "Syntax error in `%s', line %d: Unknown type encountered",
 			    filename, line_no);

Modified: ltrace/trunk/testsuite/ltrace.main/parameters-lib.c
===================================================================
--- ltrace/trunk/testsuite/ltrace.main/parameters-lib.c	2006-08-07 04:04:43 UTC (rev 63)
+++ ltrace/trunk/testsuite/ltrace.main/parameters-lib.c	2006-08-07 04:10:08 UTC (rev 64)
@@ -79,3 +79,39 @@
 	printf("%f ", a[i]);
     printf("\n");
 }
+
+struct test_struct {
+    int simple;
+    int alen;
+    int slen;
+    struct { int a; int b; }* array;
+    struct { int a; int b; } seq[3];
+    char* str;
+    char* outer_str;
+};
+
+void func_struct(struct test_struct* x)
+{
+    char buf[100];
+    int i;
+
+    printf("struct: ");
+
+    printf("%d, [", x->simple);
+    for (i = 0; i < x->alen; i++) {
+	printf("%d/%d", x->array[i].a, x->array[i].b);
+	if (i < x->alen - 1)
+	    printf(" ");
+    }
+    printf("] [");
+    for (i = 0; i < 3; i++) {
+	printf("%d/%d", x->seq[i].a, x->seq[i].b);
+	if (i < 2)
+	    printf(" ");
+    }
+    printf("] ");
+
+    strncpy(buf, x->str, x->slen);
+    buf[x->slen] = '\0';
+    printf("%s\n", buf);
+}

Modified: ltrace/trunk/testsuite/ltrace.main/parameters.c
===================================================================
--- ltrace/trunk/testsuite/ltrace.main/parameters.c	2006-08-07 04:04:43 UTC (rev 63)
+++ ltrace/trunk/testsuite/ltrace.main/parameters.c	2006-08-07 04:10:08 UTC (rev 64)
@@ -24,6 +24,7 @@
 void func_float(float, float);
 void func_arrayi(int*, int);
 void func_arrayf(float*, int);
+void func_struct(void*);
 
 typedef enum {
   RED,
@@ -86,5 +87,37 @@
   func_arrayf(af, 8);
   func_arrayf(af, 2);
 
+  {
+    struct {
+      int simple;
+      int alen;
+      int slen;
+      struct { int a; int b; }* array;
+      struct { int a; int b; } seq[3];
+      char* str;
+    } x;
+
+    x.simple = 89;
+
+    x.alen = 2;
+    x.array = malloc(800);
+    x.array[0].a = 1;
+    x.array[0].b = 10;
+    x.array[1].a = 3;
+    x.array[1].b = 30;
+
+    x.seq[0].a = 4;
+    x.seq[0].b = 40;
+    x.seq[1].a = 5;
+    x.seq[1].b = 50;
+    x.seq[2].a = 6;
+    x.seq[2].b = 60;
+
+    x.slen = 3;
+    x.str = "123junk";
+
+    func_struct(&x);
+  }
+
   return 0;
 }

Modified: ltrace/trunk/testsuite/ltrace.main/parameters.conf
===================================================================
--- ltrace/trunk/testsuite/ltrace.main/parameters.conf	2006-08-07 04:04:43 UTC (rev 63)
+++ ltrace/trunk/testsuite/ltrace.main/parameters.conf	2006-08-07 04:10:08 UTC (rev 64)
@@ -13,3 +13,4 @@
 void func_typedef(color)
 void func_arrayi(array(int,arg2)*,ignore)
 void func_arrayf(array(float,arg2)*,ignore)
+void func_struct(struct(int,int,int,array(struct(int,int),elt2)*,array(struct(int,int),3),string[elt3])*)

Modified: ltrace/trunk/testsuite/ltrace.main/parameters.exp
===================================================================
--- ltrace/trunk/testsuite/ltrace.main/parameters.exp	2006-08-07 04:04:43 UTC (rev 63)
+++ ltrace/trunk/testsuite/ltrace.main/parameters.exp	2006-08-07 04:10:08 UTC (rev 64)
@@ -70,3 +70,5 @@
 ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern 1
 set pattern "exited (status 0)"
 ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern 1
+set pattern "func_struct({ 89, 2, 3, . { 1, 10 }, { 3, 30 } ., . { 4, 40 }, { 5, 50 }, { 6, 60 } ., \\\"123\\\" })"
+ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern 1




More information about the Ltrace-devel mailing list