[Ltrace-devel] [PATCH 9/11] arrays

Steve Fink sphink at gmail.com
Sat Aug 5 23:57:59 UTC 2006


-------------- next part --------------
From 7409a0a85b43cb9e98b95068e7273af043aa7ba4 Mon Sep 17 00:00:00 2001
From: Steve Fink sphink at gmail.com <sphink at gmail.com>
Date: Sun, 23 Jul 2006 17:30:01 -0700
Subject: [PATCH 9/11] pointer to array parameters

Add yet another parameter type: pointers to arrays of (nearly)
anything else. Useful for things like OpenGL's glGenTextures().
---
 ChangeLog                              |    2 +
 defs.h                                 |    4 ++
 display_args.c                         |   65 +++++++++++++++++++++++++++++---
 etc/ltrace.conf                        |    9 ++++
 ltrace.1                               |    5 ++
 ltrace.h                               |    8 ++++
 options.c                              |    9 +++-
 options.h                              |    1 
 read_config_file.c                     |   39 +++++++++++++++++++
 testsuite/ltrace.main/parameters-lib.c |   18 +++++++++
 testsuite/ltrace.main/parameters.c     |   16 ++++++++
 testsuite/ltrace.main/parameters.conf  |    2 +
 testsuite/ltrace.main/parameters.exp   |    8 ++++
 13 files changed, 176 insertions(+), 10 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 5404ecf..3236d86 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,7 @@
 2006-07-20    Steve Fink <sphink at gmail.com>
 
+	* display_args.c: Implement parameters that point to arrays
+	* options.c: Add -A option for giving max # array elts
 	* read-config-file.c: Implement typedef (aliased parameter types)
 	* various: Implement short, ushort, float types
 
diff --git a/defs.h b/defs.h
index 1dc9c98..e59ebca 100644
--- a/defs.h
+++ b/defs.h
@@ -10,3 +10,7 @@ #endif
 #ifndef DEFAULT_STRLEN
 #define DEFAULT_STRLEN  32	/* default maximum # of bytes printed in */
 #endif				/* strings (-s switch) */
+
+#ifndef DEFAULT_ARRAYLEN
+#define DEFAULT_ARRAYLEN  4	/* default maximum # array elements */
+#endif				/* (-A switch) */
diff --git a/display_args.c b/display_args.c
index bb0bca0..f91267c 100644
--- a/display_args.c
+++ b/display_args.c
@@ -20,6 +20,7 @@ static int display_unknown(enum tof type
 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)
 {
@@ -28,18 +29,68 @@ static long get_length(enum tof type, st
     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 temp;
+    temp.type = ARGTYPE_POINTER;
+    temp.u.ptr_info.info = info;
+    return display_value(type, proc, item, &temp);
+}
+
+/*
+ * addr - A pointer to the first element of the array
+ *
+ * The function name is used to indicate that we're not actually
+ * looking at an 'array', which is a contiguous region of memory
+ * containing a sequence of elements of some type; instead, we have a
+ * pointer to that region of memory.
+ */
+static int display_arrayptr(enum tof type, struct process *proc,
+			    void *addr, arg_type_info * info)
+{
+    int len = 0;
+    int i;
+    int array_len;
+
+    if (addr == NULL)
+	return fprintf(output, "NULL");
+
+    array_len = get_length(type, proc, info->u.array_info.len_spec);
+    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;
+	size_t elt_size = info->u.array_info.elt_size;
+	if (i != 0)
+	    len += fprintf(output, ", ");
+	if (opt_d)
+	    len += fprintf(output, "%p=", addr);
+	len +=
+	    display_ptrto(type, proc, (long) addr, elt_type);
+	addr += elt_size;
+    }
+    if (i < array_len)
+	len += fprintf(output, "...");
+    len += fprintf(output, " ]");
+    return len;
+}
+ 
 static int display_pointer(enum tof type, struct process *proc, long value,
 			   arg_type_info * info)
 {
     long pointed_to;
     arg_type_info *inner = info->u.ptr_info.info;
 
-    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);
+    if (inner->type == ARGTYPE_ARRAY) {
+	return display_arrayptr(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);
+    }
 }
 
 static int display_enum(enum tof type, struct process *proc,
@@ -115,6 +166,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_ARRAY:
+		return fprintf(output, "<array without address>");
         case ARGTYPE_ENUM:
 		return display_enum(type, proc, info, value);
 	case ARGTYPE_POINTER:
diff --git a/etc/ltrace.conf b/etc/ltrace.conf
index 2ef97e7..fa901fc 100644
--- a/etc/ltrace.conf
+++ b/etc/ltrace.conf
@@ -27,6 +27,9 @@
 ; ignore	== (any)			[ignore arg, output blank]
 ; type*		== (type *)			[pointer to any other type]
 ; enum (key=value,key=value,...)		[enumeration, see below]
+; array(type,argN)
+;		== (type[SIZE])			[array of (arg N) elements]
+; array(type,N)	== (type[N])			[array of N elements]
 
 ; Backwards-compatibility:
 ; string0	== (char *)			[same as string[retval]]
@@ -48,6 +51,12 @@
 ; an example usage might look like
 ;   int fcntl(int,enum (F_DUPFD=0,F_GETFD=1,F_SETFD=2))
 ;
+; Arrays
+;
+; NOTE: Uses of array(...) alone are very rare. You almost always
+; want array(...)*. The exceptions are when you have a fixed-size
+; array.
+
 
 ; arpa/inet.h
 int inet_aton(string,addr);
diff --git a/ltrace.1 b/ltrace.1
index 7c114cc..f7b7d95 100644
--- a/ltrace.1
+++ b/ltrace.1
@@ -6,7 +6,7 @@ ltrace \- A library call tracer
 
 .SH SYNOPSIS
 .B ltrace
-.I "[-CdfhiLrStttV] [-a column] [-e expr] [-l filename] [-n nr] [-o filename] [-p pid] ... [-s strsize] [-u username] [-X extern] [-x extern] ... [--align=column] [--debug] [--demangle] [--help] [--indent=nr] [--library=filename] [--output=filename] [--version] [command [arg ...]]"
+.I "[-CdfhiLrStttV] [-a column] [-A maxelts] [-e expr] [-l filename] [-n nr] [-o filename] [-p pid] ... [-s strsize] [-u username] [-X extern] [-x extern] ... [--align=column] [--debug] [--demangle] [--help] [--indent=nr] [--library=filename] [--output=filename] [--version] [command [arg ...]]"
 
 .SH DESCRIPTION
 .B ltrace
@@ -25,6 +25,9 @@ Its use is very similar to
 .I \-a, \-\-align column
 Align return values in a specific column (default column is 5/8 of screen width).
 .TP
+.I \-A maxelts
+Maximum number of array elements to print before suppressing the rest with an ellipsis ("...")
+.TP
 .I \-c
 Count time and calls for each library call and report a summary on program exit.
 .TP
diff --git a/ltrace.h b/ltrace.h
index 2b34476..fe5fd87 100644
--- a/ltrace.h
+++ b/ltrace.h
@@ -45,6 +45,7 @@ enum arg_type {
 	ARGTYPE_FORMAT,		/* printf-like format */
 	ARGTYPE_STRING,		/* NUL-terminated string */
 	ARGTYPE_STRING_N,	/* String of known maxlen */
+        ARGTYPE_ARRAY,		/* Series of values in memory */
         ARGTYPE_ENUM,		/* Enumeration */
         ARGTYPE_IGNORE,		/* Leave parameter blank */
         ARGTYPE_POINTER,	/* Pointer to some other type */
@@ -61,6 +62,13 @@ typedef struct arg_type_info_t {
 	    int *values;
 	} enum_info;
 
+	// ARGTYPE_ARRAY
+	struct {
+	    struct arg_type_info_t *elt_type;
+	    size_t elt_size;
+	    int len_spec;
+	} array_info;
+
 	// ARGTYPE_STRING_N
 	struct {
 	    int size_spec;
diff --git a/options.c b/options.c
index bdf565b..272870b 100644
--- a/options.c
+++ b/options.c
@@ -30,6 +30,7 @@ int library_num = 0;
 static char *progname;		/* Program name (`ltrace') */
 FILE *output;
 int opt_a = DEFAULT_ACOLUMN;	/* default alignment column for results */
+int opt_A = DEFAULT_ARRAYLEN;	/* default maximum # array elements to print */
 int opt_c = 0;			/* Count time, calls, and report a summary on program exit */
 int opt_d = 0;			/* debug */
 int opt_i = 0;			/* instruction pointer */
@@ -78,6 +79,7 @@ # if HAVE_GETOPT_LONG
 # else
 		"  -a COLUMN           align return values in a secific column.\n"
 # endif
+                "  -A ARRAYLEN         maximum number of array elements to print.\n"
 		"  -c                  count time and calls, and report a summary on exit.\n"
 # ifdef USE_DEMANGLE
 #  if HAVE_GETOPT_LONG
@@ -202,14 +204,14 @@ #endif
 # ifdef USE_DEMANGLE
 				"C"
 # endif
-				"a:e:F:l:n:o:p:s:u:x:X:", long_options,
+				"a:A:e:F:l:n:o:p:s:u:x:X:", long_options,
 				&option_index);
 #else
 		c = getopt(argc, argv, "+cdfhiLrStTV"
 # ifdef USE_DEMANGLE
 			   "C"
 # endif
-			   "a:e:F:l:n:o:p:s:u:x:X:");
+			   "a:A:e:F:l:n:o:p:s:u:x:X:");
 #endif
 		if (c == -1) {
 			break;
@@ -218,6 +220,9 @@ #endif
 		case 'a':
 			opt_a = atoi(optarg);
 			break;
+                case 'A':
+			opt_A = atoi(optarg);
+			break;
 		case 'c':
 			opt_c++;
 			break;
diff --git a/options.h b/options.h
index 0b35693..9ead6f3 100644
--- a/options.h
+++ b/options.h
@@ -7,6 +7,7 @@ #include <sys/types.h>
 
 extern FILE *output;
 extern int opt_a;		/* default alignment column for results */
+extern int opt_A;		/* default maximum # of array elements printed */
 extern int opt_c;		/* count time, calls, and report a summary on program exit */
 extern int opt_d;		/* debug */
 extern int opt_i;		/* instruction pointer */
diff --git a/read_config_file.c b/read_config_file.c
index 76104dc..51d4d85 100644
--- a/read_config_file.c
+++ b/read_config_file.c
@@ -38,6 +38,7 @@ static struct list_of_pt_t {
 	"file", ARGTYPE_FILE}, {
 	"format", ARGTYPE_FORMAT}, {
 	"string", ARGTYPE_STRING}, {
+	"array", ARGTYPE_ARRAY}, {
 	"enum", ARGTYPE_ENUM}, {
 	"ignore", ARGTYPE_IGNORE}, {
 	NULL, ARGTYPE_UNKNOWN}	/* Must finish with NULL */
@@ -59,6 +60,7 @@ static arg_type_info arg_type_singletons
 	{ ARGTYPE_FORMAT },
 	{ ARGTYPE_STRING },
 	{ ARGTYPE_STRING_N },
+	{ ARGTYPE_ARRAY },
 	{ ARGTYPE_ENUM },
 	{ ARGTYPE_IGNORE },
 	{ ARGTYPE_POINTER },
@@ -162,6 +164,7 @@ static int simple_type(enum arg_type at)
     switch (at) {
     case ARGTYPE_STRING:
     case ARGTYPE_STRING_N:
+    case ARGTYPE_ARRAY:
     case ARGTYPE_ENUM:
 	return 0;
 
@@ -276,6 +279,26 @@ static void parse_typedef(char **str)
     typedefs = binding;
 }
 
+static size_t arg_sizeof(arg_type_info * arg)
+{
+    if (arg->type == ARGTYPE_CHAR) {
+	return sizeof(char);
+    } else if (arg->type == ARGTYPE_SHORT || arg->type == ARGTYPE_USHORT) {
+	return sizeof(short);
+    } else if (arg->type == ARGTYPE_FLOAT) {
+	return sizeof(float);
+    } else if (arg->type == ARGTYPE_ENUM) {
+	return sizeof(int);
+    } 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;
+	else
+	    return sizeof(void *);
+    } else {
+	return sizeof(int);
+    }
+}
+
 static arg_type_info *parse_nonpointer_type(char **str)
 {
 	arg_type_info *simple;
@@ -306,7 +329,21 @@ static arg_type_info *parse_nonpointer_t
 
 	switch (info->type) {
 
-	// Syntax: enum ( keyname=value,keyname=value,... )
+	/* Syntax: array ( type, N|argN ) */
+	case ARGTYPE_ARRAY:
+	    (*str)++;		// Get past open paren
+	    eat_spaces(str);
+	    if ((info->u.array_info.elt_type = parse_type(str)) == NULL)
+		return NULL;
+	    info->u.array_info.elt_size =
+		arg_sizeof(info->u.array_info.elt_type);
+	    (*str)++;		// Get past comma
+	    eat_spaces(str);
+	    info->u.array_info.len_spec = parse_argnum(str);
+	    (*str)++;		// Get past close paren
+	    return info;
+
+	/* Syntax: enum ( keyname=value,keyname=value,... ) */
 	case ARGTYPE_ENUM:{
 	    struct enum_opt {
 		char *key;
diff --git a/testsuite/ltrace.main/parameters-lib.c b/testsuite/ltrace.main/parameters-lib.c
index f5ed3f7..a45cd2e 100644
--- a/testsuite/ltrace.main/parameters-lib.c
+++ b/testsuite/ltrace.main/parameters-lib.c
@@ -61,3 +61,21 @@ void func_typedef(int x)
 {
 	printf("typedef'd enum: %d\n", x);
 }
+
+void func_arrayi(int* a, int N)
+{
+    int i;
+    printf("array[int]: ");
+    for (i = 0; i < N; i++)
+	printf("%d ", a[i]);
+    printf("\n");
+}
+
+void func_arrayf(float* a, int N)
+{
+    int i;
+    printf("array[float]: ");
+    for (i = 0; i < N; i++)
+	printf("%f ", a[i]);
+    printf("\n");
+}
diff --git a/testsuite/ltrace.main/parameters.c b/testsuite/ltrace.main/parameters.c
index b573767..dbc8ace 100644
--- a/testsuite/ltrace.main/parameters.c
+++ b/testsuite/ltrace.main/parameters.c
@@ -22,6 +22,8 @@ void func_stringp(char**);
 void func_short(short, short);
 void func_ushort(unsigned short, unsigned short);
 void func_float(float, float);
+void func_arrayi(int*, int);
+void func_arrayf(float*, int);
 
 typedef enum {
   RED,
@@ -40,6 +42,8 @@ main ()
   int *xP, **xPP;
   char buf[200];
   char *s;
+  int *ai;
+  float *af;
 
   func_ignore(1, 2, 3);
 
@@ -70,5 +74,17 @@ main ()
 
   func_typedef(BLUE);
 
+  ai = (int*) calloc(sizeof(int), 8);
+  for (x = 0; x < 8; x++)
+    ai[x] = 10 + x;
+  func_arrayi(ai, 8);
+  func_arrayi(ai, 2);
+
+  af = (float*) calloc(sizeof(float), 8);
+  for (x = 0; x < 8; x++)
+    af[x] = 10.1 + x;
+  func_arrayf(af, 8);
+  func_arrayf(af, 2);
+
   return 0;
 }
diff --git a/testsuite/ltrace.main/parameters.conf b/testsuite/ltrace.main/parameters.conf
index dd8294d..8216857 100644
--- a/testsuite/ltrace.main/parameters.conf
+++ b/testsuite/ltrace.main/parameters.conf
@@ -11,3 +11,5 @@ void func_ushort(ushort, ushort)
 void func_float(float,float)
 typedef color = enum (RED=0,GREEN=1,BLUE=2,CHARTREUSE=3,PETUNIA=4)
 void func_typedef(color)
+void func_arrayi(array(int,arg2)*,ignore)
+void func_arrayf(array(float,arg2)*,ignore)
diff --git a/testsuite/ltrace.main/parameters.exp b/testsuite/ltrace.main/parameters.exp
index 2026cbd..ee269e4 100644
--- a/testsuite/ltrace.main/parameters.exp
+++ b/testsuite/ltrace.main/parameters.exp
@@ -60,5 +60,13 @@ set pattern "func_float(3.40*, -3.40*)"
 ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern 1
 set pattern "func_typedef(BLUE)"
 ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern 1
+set pattern "func_arrayi(. 10, 11, 12, 13\\.\\.\\. ., )"
+ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern 1
+set pattern "func_arrayi(. 10, 11 ., )"
+ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern 1
+set pattern "func_arrayf(. 10.10*, 11.10*, 12.10*, 13.10*\\.\\.\\. ., )"
+ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern 1
+set pattern "func_arrayf(. 10.10*, 11.10* ., )"
+ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern 1
 set pattern "exited (status 0)"
 ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern 1
-- 
1.4.1


More information about the Ltrace-devel mailing list