[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