aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog9
-rw-r--r--defs.h4
-rw-r--r--display_args.c65
-rw-r--r--etc/ltrace.conf9
-rw-r--r--ltrace.15
-rw-r--r--ltrace.h8
-rw-r--r--options.c9
-rw-r--r--options.h1
-rw-r--r--read_config_file.c39
-rw-r--r--testsuite/ltrace.main/parameters-lib.c18
-rw-r--r--testsuite/ltrace.main/parameters.c16
-rw-r--r--testsuite/ltrace.main/parameters.conf2
-rw-r--r--testsuite/ltrace.main/parameters.exp8
13 files changed, 183 insertions, 10 deletions
diff --git a/ChangeLog b/ChangeLog
index 808d363..36dbee6 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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,
diff --git a/defs.h b/defs.h
index 1dc9c98..e59ebca 100644
--- a/defs.h
+++ b/defs.h
@@ -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);
diff --git a/ltrace.1 b/ltrace.1
index f9565e9..30f51e8 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 @@ 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;
diff --git a/options.h b/options.h
index 0b35693..9ead6f3 100644
--- a/options.h
+++ b/options.h
@@ -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