diff options
-rw-r--r-- | ChangeLog | 9 | ||||
-rw-r--r-- | defs.h | 4 | ||||
-rw-r--r-- | display_args.c | 65 | ||||
-rw-r--r-- | etc/ltrace.conf | 9 | ||||
-rw-r--r-- | ltrace.1 | 5 | ||||
-rw-r--r-- | ltrace.h | 8 | ||||
-rw-r--r-- | options.c | 9 | ||||
-rw-r--r-- | options.h | 1 | ||||
-rw-r--r-- | read_config_file.c | 39 | ||||
-rw-r--r-- | testsuite/ltrace.main/parameters-lib.c | 18 | ||||
-rw-r--r-- | testsuite/ltrace.main/parameters.c | 16 | ||||
-rw-r--r-- | testsuite/ltrace.main/parameters.conf | 2 | ||||
-rw-r--r-- | testsuite/ltrace.main/parameters.exp | 8 |
13 files changed, 183 insertions, 10 deletions
@@ -1,5 +1,14 @@ 2006-08-07 Steve Fink <sphink@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, + testsuite/ltrace.main/parameters.c, + testsuite/ltrace.main/parameters.conf, + testsuite/ltrace.main/parameters.exp: array arguments + +2006-08-07 Steve Fink <sphink@gmail.com> + * etc/ltrace.conf, read_config_file.c, testsuite/ltrace.main/parameters-lib.c, testsuite/ltrace.main/parameters.c, @@ -10,3 +10,7 @@ #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, 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) { @@ -28,18 +29,68 @@ static long get_length(enum tof type, struct process *proc, int len_spec) 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 process *proc, 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); @@ -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 @@ -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; @@ -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 @@ static void usage(void) # 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 @@ char **process_options(int argc, char **argv) # 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 @@ char **process_options(int argc, char **argv) case 'a': opt_a = atoi(optarg); break; + case 'A': + opt_A = atoi(optarg); + break; case 'c': opt_c++; break; @@ -7,6 +7,7 @@ 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_type(char **str) 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 |