[Ltrace-devel] [PATCH 5/11] pointers
Steve Fink
sphink at gmail.com
Sat Aug 5 23:56:13 UTC 2006
-------------- next part --------------
From 859887ca61fd94e94601c6f71e72e1867b06d34d Mon Sep 17 00:00:00 2001
From: Steve Fink sphink at gmail.com <sphink at gmail.com>
Date: Thu, 27 Jul 2006 08:37:24 -0700
Subject: [PATCH 5/11] implement pointer parameters
switch to passing around values rather than argument numbers that need
to be fetched (needed for pointer params)
add tests for several recently-added parameter types
---
ChangeLog | 12 ++-
display_args.c | 132 +++++++++++++++++++-------------
etc/ltrace.conf | 3 -
ltrace.h | 7 ++
read_config_file.c | 18 ++++
sysdeps/README | 1
sysdeps/linux-gnu/trace.c | 18 ++++
testsuite/ltrace.main/Makefile | 2
testsuite/ltrace.main/parameters-lib.c | 38 +++++++++
testsuite/ltrace.main/parameters.c | 44 +++++++++++
testsuite/ltrace.main/parameters.conf | 7 ++
testsuite/ltrace.main/parameters.exp | 52 +++++++++++++
12 files changed, 273 insertions(+), 61 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 4575942..f361d52 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,11 +1,17 @@
2006-07-20 Steve Fink <sphink at gmail.com>
- * testsuite/lib/ltrace.exp: better quoting and error detection for
- ltrace_verify_output's call to grep
+ * various: add pointers as valid parameter descriptor
+ * display_args.c: switch to passing around values rather than
+ argument numbers that need to be fetched (needed for pointer params)
+ * testsuite/ltrace.main/parameters.*: add tests for several
+ recently-added parameter types
+
+ * various: add 'ignore' parameter descriptor
2006-07-20 Steve Fink <sphink at gmail.com>
- * various: add 'ignore' parameter descriptor
+ * testsuite/lib/ltrace.exp: better quoting and error detection for
+ ltrace_verify_output's call to grep
2006-07-20 Steve Fink <sphink at gmail.com>
diff --git a/display_args.c b/display_args.c
index 2669228..66a9093 100644
--- a/display_args.c
+++ b/display_args.c
@@ -2,6 +2,7 @@ #if HAVE_CONFIG_H
#include "config.h"
#endif
+#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -12,9 +13,10 @@ #include "options.h"
static int display_char(int what);
static int display_string(enum tof type, struct process *proc,
- int arg_num, arg_type_info *info,
- size_t maxlen);
-static int display_unknown(enum tof type, struct process *proc, int arg_num);
+ void* addr, size_t maxlen);
+static int display_value(enum tof type, struct process *proc,
+ long value, arg_type_info *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;
@@ -26,12 +28,30 @@ static long get_length(enum tof type, st
return gimme_arg(type, proc, -len_spec - 1);
}
-int
-display_arg(enum tof type, struct process *proc,
- int arg_num, arg_type_info *info)
+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);
+}
+
+/* Args:
+ type - syscall or shared library function or memory
+ proc - information about the traced process
+ value - the value to display
+ info - the description of the type to display
+*/
+int display_value(enum tof type, struct process *proc,
+ long value, arg_type_info *info)
{
int tmp;
- long arg;
switch (info->type) {
case ARGTYPE_VOID:
@@ -39,52 +59,62 @@ display_arg(enum tof type, struct proces
case ARGTYPE_IGNORE:
return 0; /* Empty gap between commas */
case ARGTYPE_INT:
- return fprintf(output, "%d",
- (int)gimme_arg(type, proc, arg_num));
+ return fprintf(output, "%d", (int) value);
case ARGTYPE_UINT:
- return fprintf(output, "%u",
- (unsigned)gimme_arg(type, proc, arg_num));
+ return fprintf(output, "%u", (unsigned) value);
case ARGTYPE_LONG:
if (proc->mask_32bit)
- return fprintf(output, "%d",
- (int)gimme_arg(type, proc, arg_num));
- return fprintf(output, "%ld", gimme_arg(type, proc, arg_num));
+ return fprintf(output, "%d", (int) value);
+ else
+ return fprintf(output, "%ld", value);
case ARGTYPE_ULONG:
if (proc->mask_32bit)
- return fprintf(output, "%u",
- (unsigned)gimme_arg(type, proc,
- arg_num));
- return fprintf(output, "%lu",
- (unsigned long)gimme_arg(type, proc, arg_num));
+ return fprintf(output, "%u", (unsigned) value);
+ else
+ return fprintf(output, "%lu", (unsigned long) value);
case ARGTYPE_OCTAL:
- return fprintf(output, "0%o",
- (unsigned)gimme_arg(type, proc, arg_num));
+ return fprintf(output, "0%o", (unsigned) value);
case ARGTYPE_CHAR:
tmp = fprintf(output, "'");
- tmp += display_char((int)gimme_arg(type, proc, arg_num));
+ tmp += display_char(value == -1 ? value : (char) value);
tmp += fprintf(output, "'");
return tmp;
case ARGTYPE_ADDR:
- arg = gimme_arg(type, proc, arg_num);
- if (!arg) {
+ if (!value)
return fprintf(output, "NULL");
- } else {
- return fprintf(output, "%p", (void *)arg);
- }
+ else
+ return fprintf(output, "0x%08lx", value);
case ARGTYPE_FORMAT:
- return display_format(type, proc, arg_num);
+ fprintf(stderr, "Should never encounter a format anywhere but at the top level (for now?)\n");
+ exit(1);
case ARGTYPE_STRING:
- return display_string(type, proc, arg_num, info,
+ return display_string(type, proc, (void*) value,
string_maxlength);
case ARGTYPE_STRING_N:
- return display_string(type, proc, arg_num, info,
+ return display_string(type, proc, (void*) value,
get_length(type, proc,
info->u.string_n_info.size_spec));
- case ARGTYPE_UNKNOWN:
+ case ARGTYPE_POINTER:
+ return display_pointer(type, proc, value, info);
+ case ARGTYPE_UNKNOWN:
default:
- return display_unknown(type, proc, arg_num);
+ return display_unknown(type, proc, value);
}
- return fprintf(output, "?");
+}
+
+int display_arg(enum tof type, struct process *proc, int arg_num,
+ arg_type_info * info)
+{
+ long arg;
+
+ if (info->type == ARGTYPE_VOID) {
+ return 0;
+ } else if (info->type == ARGTYPE_FORMAT) {
+ return display_format(type, proc, arg_num);
+ } else {
+ arg = gimme_arg(type, proc, arg_num);
+ return display_value(type, proc, arg, info);
+ }
}
static int display_char(int what)
@@ -103,25 +133,23 @@ static int display_char(int what)
case '\\':
return fprintf(output, "\\\\");
default:
- if ((what < 32) || (what > 126)) {
- return fprintf(output, "\\%03o", (unsigned char)what);
- } else {
+ if (isprint(what)) {
return fprintf(output, "%c", what);
+ } else {
+ return fprintf(output, "\\%03o", (unsigned char)what);
}
}
}
#define MIN(a,b) (((a)<(b)) ? (a) : (b))
-static int display_string(enum tof type, struct process *proc,
- int arg_num, arg_type_info *info, size_t maxlength)
+static int display_string(enum tof type, struct process *proc, void *addr,
+ size_t maxlength)
{
- void *addr;
unsigned char *str1;
int i;
int len = 0;
- addr = (void *)gimme_arg(type, proc, arg_num);
if (!addr) {
return fprintf(output, "NULL");
}
@@ -147,21 +175,17 @@ static int display_string(enum tof type,
return len;
}
-static int display_unknown(enum tof type, struct process *proc, int arg_num)
+static int display_unknown(enum tof type, struct process *proc, long value)
{
- long tmp;
-
- tmp = gimme_arg(type, proc, arg_num);
-
if (proc->mask_32bit) {
- if ((int)tmp < 1000000 && (int)tmp > -1000000)
- return fprintf(output, "%d", (int)tmp);
+ if ((int)value < 1000000 && (int)value > -1000000)
+ return fprintf(output, "%d", (int)value);
else
- return fprintf(output, "%p", (void *)tmp);
- } else if (tmp < 1000000 && tmp > -1000000) {
- return fprintf(output, "%ld", tmp);
+ return fprintf(output, "%p", (void *)value);
+ } else if (value < 1000000 && value > -1000000) {
+ return fprintf(output, "%ld", value);
} else {
- return fprintf(output, "%p", (void *)tmp);
+ return fprintf(output, "%p", (void *)value);
}
}
@@ -285,12 +309,12 @@ static int display_format(enum tof type,
len += fprintf(output, "'");
break;
} else if (c == 's') {
- arg_type_info *info =
- lookup_singleton(ARGTYPE_STRING);
len += fprintf(output, ", ");
len +=
display_string(type, proc,
- ++arg_num, info,
+ (void *)gimme_arg(type,
+ proc,
+ ++arg_num),
string_maxlength);
break;
} else if (c == 'p' || c == 'n') {
diff --git a/etc/ltrace.conf b/etc/ltrace.conf
index 50a41eb..547a125 100644
--- a/etc/ltrace.conf
+++ b/etc/ltrace.conf
@@ -23,6 +23,7 @@
; string[arg0] == (char *) [same as string[retval]]
; string[N] == (char *) [N>0] [show only up to N bytes]
; ignore == (any) [ignore arg, output blank]
+; type* == (type *) [pointer to any other type]
; Backwards-compatibility:
; string0 == (char *) [same as string[retval]]
@@ -77,7 +78,7 @@ int open64(string,int,octal); ; WARNING
int fnmatch(string, string, int);
; getopt.h
-int getopt_long(int,addr,string,addr,addr);
+int getopt_long(int,addr,string,addr,int*);
int getopt_long_only(int,addr,string,addr,addr);
; grp.h
diff --git a/ltrace.h b/ltrace.h
index d030ce8..e649bb1 100644
--- a/ltrace.h
+++ b/ltrace.h
@@ -43,6 +43,7 @@ enum arg_type {
ARGTYPE_STRING, /* NUL-terminated string */
ARGTYPE_STRING_N, /* String of known maxlen */
ARGTYPE_IGNORE, /* Leave parameter blank */
+ ARGTYPE_POINTER, /* Pointer to some other type */
ARGTYPE_COUNT /* number of ARGTYPE_* values */
};
@@ -53,6 +54,11 @@ typedef struct arg_type_info_t {
struct {
int size_spec;
} string_n_info;
+
+ // ARGTYPE_POINTER
+ struct {
+ struct arg_type_info_t *info;
+ } ptr_info;
} u;
} arg_type_info;
@@ -206,6 +212,7 @@ extern void continue_enabling_breakpoint
extern long gimme_arg(enum tof type, struct process *proc, int arg_num);
extern void save_register_args(enum tof type, struct process *proc);
extern int umovestr(struct process *proc, void *addr, int len, void *laddr);
+extern int umovelong(struct process *proc, void *addr, long *result);
extern int ffcheck(void *maddr);
extern void *sym2addr(struct process *, struct library_symbol *);
diff --git a/read_config_file.c b/read_config_file.c
index 3927af2..15c3f39 100644
--- a/read_config_file.c
+++ b/read_config_file.c
@@ -47,6 +47,7 @@ static arg_type_info arg_type_singletons
{ ARGTYPE_STRING },
{ ARGTYPE_STRING_N },
{ ARGTYPE_IGNORE },
+ { ARGTYPE_POINTER },
{ ARGTYPE_UNKNOWN }
};
@@ -64,7 +65,7 @@ static arg_type_info *str2type(char **st
while (tmp->name) {
if (!strncmp(*str, tmp->name, strlen(tmp->name))
- && index(" ,()#;012345[", *(*str + strlen(tmp->name)))) {
+ && index(" ,()#*;012345[", *(*str + strlen(tmp->name)))) {
*str += strlen(tmp->name);
return lookup_singleton(tmp->pt);
}
@@ -169,7 +170,7 @@ static int parse_argnum(char **str)
return n * multiplier;
}
-static arg_type_info *parse_type(char **str)
+static arg_type_info *parse_nonpointer_type(char **str)
{
arg_type_info *simple;
arg_type_info *info;
@@ -220,6 +221,19 @@ static arg_type_info *parse_type(char **
}
}
+static arg_type_info *parse_type(char **str)
+{
+ arg_type_info *info = parse_nonpointer_type(str);
+ while (**str == '*') {
+ arg_type_info *outer = malloc(sizeof(*info));
+ outer->type = ARGTYPE_POINTER;
+ outer->u.ptr_info.info = info;
+ (*str)++;
+ info = outer;
+ }
+ return info;
+}
+
static struct function *process_line(char *buf)
{
struct function fun;
diff --git a/sysdeps/README b/sysdeps/README
index 58abd08..1ec4935 100644
--- a/sysdeps/README
+++ b/sysdeps/README
@@ -24,6 +24,7 @@ void * get_stack_pointer(pid_t pid);
void * get_return_addr(pid_t pid, void * stack_pointer);
long gimme_arg(enum tof type, struct process * proc, int arg_num);
int umovestr(struct process * proc, void * addr, int len, void * laddr);
+int umovelong(struct process * proc, void * addr, long * result);
char * pid2name(pid_t pid);
void trace_me(void);
int trace_pid(pid_t pid);
diff --git a/sysdeps/linux-gnu/trace.c b/sysdeps/linux-gnu/trace.c
index 136d288..a1af202 100644
--- a/sysdeps/linux-gnu/trace.c
+++ b/sysdeps/linux-gnu/trace.c
@@ -151,6 +151,24 @@ #endif
}
}
+/* Read a single long from the process's memory address 'addr' */
+int umovelong(struct process *proc, void *addr, long *result)
+{
+ long pointed_to;
+
+ errno = 0;
+ pointed_to = ptrace(PTRACE_PEEKTEXT, proc->pid, addr, 0);
+ if (pointed_to == -1 && errno)
+ return -errno;
+
+ *result = pointed_to;
+ return 0;
+}
+
+/* Read a series of bytes starting at the process's memory address
+ 'addr' and continuing until a NUL ('\0') is seen or 'len' bytes
+ have been read.
+*/
int umovestr(struct process *proc, void *addr, int len, void *laddr)
{
union {
diff --git a/testsuite/ltrace.main/Makefile b/testsuite/ltrace.main/Makefile
index 57699d7..db88c98 100644
--- a/testsuite/ltrace.main/Makefile
+++ b/testsuite/ltrace.main/Makefile
@@ -19,7 +19,7 @@ CLEANFILES = *.log *.sum site.bak setval
.SUFFIXES:
clean:
- -rm -f main main-internal system_calls signals
+ -rm -f main main-internal system_calls signals parameters
-rm -f *.o *.so
-rm -f *.ltrace
-rm -f $(CLEANFILES)
diff --git a/testsuite/ltrace.main/parameters-lib.c b/testsuite/ltrace.main/parameters-lib.c
new file mode 100644
index 0000000..bc320cf
--- /dev/null
+++ b/testsuite/ltrace.main/parameters-lib.c
@@ -0,0 +1,38 @@
+#include <string.h>
+#include <stdio.h>
+
+void func_ignore(int a, int b, int c)
+{
+ printf("%d\n", a + b + c);
+}
+
+void func_intptr(int *i)
+{
+ printf("%d\n", *i);
+}
+
+void func_intptr_ret(int *i)
+{
+ *i = 42;
+}
+
+int func_strlen(char* p)
+{
+ strcpy(p, "Hello world");
+ return strlen(p);
+}
+
+void func_strfixed(char* p)
+{
+ strcpy(p, "Hello world");
+}
+
+void func_ppp(int*** ppp)
+{
+ printf("%d\n", ***ppp);
+}
+
+void func_stringp(char** sP)
+{
+ printf("%s\n", *sP);
+}
diff --git a/testsuite/ltrace.main/parameters.c b/testsuite/ltrace.main/parameters.c
new file mode 100644
index 0000000..e26e0a6
--- /dev/null
+++ b/testsuite/ltrace.main/parameters.c
@@ -0,0 +1,44 @@
+/* Ltrace Test : parameters.c.
+ Objectives : Verify that Ltrace can handle all the different
+ parameter types
+
+ This file was written by Steve Fink <sphink at gmail.com>. */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+
+void func_ignore(int a, int b, int c);
+void func_intptr(int *i);
+void func_intptr_ret(int *i);
+int func_strlen(char*);
+void func_strfixed(char*);
+void func_ppp(int***);
+void func_stringp(char**);
+
+int
+main ()
+{
+ int x = 17;
+ int *xP, **xPP;
+ char buf[200];
+ char *s;
+ func_ignore(1, 2, 3);
+ func_intptr(&x);
+ func_intptr_ret(&x);
+ func_strlen(buf);
+ printf("%s\n", buf);
+ func_strfixed(buf);
+ printf("%s\n", buf);
+ x = 80;
+ xP = &x;
+ xPP = &xP;
+ func_ppp(&xPP);
+ s = (char*) malloc(100);
+ strcpy(s, "Dude");
+ func_stringp(&s);
+}
diff --git a/testsuite/ltrace.main/parameters.conf b/testsuite/ltrace.main/parameters.conf
new file mode 100644
index 0000000..7690f89
--- /dev/null
+++ b/testsuite/ltrace.main/parameters.conf
@@ -0,0 +1,7 @@
+void func_ignore(int,ignore,int)
+void func_intptr(int*)
+void func_intptr_ret(+int*)
+int func_strlen(+string[retval])
+void func_strfixed(string[4])
+void func_ppp(int***)
+void func_stringp(string*)
diff --git a/testsuite/ltrace.main/parameters.exp b/testsuite/ltrace.main/parameters.exp
new file mode 100644
index 0000000..21a02b4
--- /dev/null
+++ b/testsuite/ltrace.main/parameters.exp
@@ -0,0 +1,52 @@
+# This file was written by Steve Fink <sphink at gmail.com>.
+# Based on main.c by Yao Qi <qiyao at cn.ibm.com>.
+
+set testfile "parameters"
+set srcfile ${testfile}.c
+set binfile ${testfile}
+set libfile "parameters-lib"
+set libsrc $srcdir/$subdir/$libfile.c
+set lib_sl $srcdir/$subdir/lib$testfile.so
+
+
+if [get_compiler_info $binfile] {
+ return -1
+}
+
+verbose "compiling source file now....."
+if { [ltrace_compile_shlib $libsrc $lib_sl debug ] != ""
+ || [ltrace_compile $srcdir/$subdir/$srcfile $srcdir/$subdir/$binfile executable [list debug shlib=$lib_sl] ] != ""} {
+ send_user "Testcase compile failed, so all tests in this file will automatically fail.\n"
+}
+
+# set options for ltrace.
+ltrace_options "-l" "$srcdir/$subdir/libparameters.so" "-F" "$srcdir/$subdir/parameters.conf"
+
+# Run PUT for ltarce.
+set exec_output [ltrace_runtest $srcdir/$subdir $srcdir/$subdir/$binfile]
+
+# Check the output of this program.
+verbose "ltrace runtest output: $exec_output\n"
+if [regexp {ELF from incompatible architecture} $exec_output] {
+ fail "32-bit ltrace can not perform on 64-bit PUTs and rebuild ltrace in 64 bit mode!"
+ return
+} elseif [ regexp {Couldn't get .hash data} $exec_output ] {
+ fail "Couldn't get .hash data!"
+ return
+}
+
+# Verify the output
+set pattern "func_ignore(1, *, *3)"
+ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern 1
+set pattern "func_intptr(17)"
+ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern 1
+set pattern "func_intptr_ret(42)"
+ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern 1
+set pattern "func_strlen(\\\"Hello world\\\") *= *11"
+ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern 1
+set pattern "func_strfixed(\\\"Hell\\\")"
+ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern 1
+set pattern "func_ppp(80)"
+ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern 1
+set pattern "func_stringp(\\\"Dude\\\")"
+ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern 1
--
1.4.1
More information about the Ltrace-devel
mailing list