[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