Version 0.2.0

* First Debian unstable release
* Complete re-structured all the code to be able to add support for
  different architectures (but only i386 arch is supported in this
  version)
* Log also return values
* Log arguments (and return values) for syscalls
* Added preliminary support for various simultaneous processes
* getopt-like options
* New option: -a (alignment column)
* New option: -L (don't display library calls)
* New option: -s (maximum # of chars in strings)
* Now it reads config files with function names and parameter types
* Programs using clone() should work ok now
* debian/rules: gzipped only big files in /usr/doc/ltrace
* Debian: New Standards-Version: 2.4.0.0
* beginning to work on sparc port (not yet done)
diff --git a/BUGS b/BUGS
index 0c04896..7f61d96 100644
--- a/BUGS
+++ b/BUGS
@@ -1,2 +1,5 @@
-Too many... :)
-
+* options -p and -f don't work yet
+* Manual page is not accurate (config files...)
+* elf.c only supports elf32 binaries
+* netscape sometimes dies with SIGSEGV (is this still true?)
+* Only Linux/i386 is supported
diff --git a/COPYING b/COPYING
index e77696a..60549be 100644
--- a/COPYING
+++ b/COPYING
@@ -2,7 +2,7 @@
 		       Version 2, June 1991
 
  Copyright (C) 1989, 1991 Free Software Foundation, Inc.
-                          675 Mass Ave, Cambridge, MA 02139, USA
+                       59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  Everyone is permitted to copy and distribute verbatim copies
  of this license document, but changing it is not allowed.
 
@@ -305,7 +305,8 @@
 
     You should have received a copy of the GNU General Public License
     along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
 
 Also add information on how to contact you by electronic and paper mail.
 
diff --git a/KK b/KK
new file mode 100644
index 0000000..db0a403
--- /dev/null
+++ b/KK
@@ -0,0 +1,79 @@
+atexit(0x40006150)                                = 0
+__libc_init_first(2, 0xbffffb6e, 0xbffffb7d, 0, 0xbffffb82) = 0x40006150
+atexit(0x0804cc20)                                = 0
+socket(2, 2, 0, 0x0804a0d5, 0x4000b070)           = 5
+socket(4, 2, 0, 2, 2)                             = -1
+socket(3, 2, 0, 4, 2)                             = -1
+socket(5, 2, 0, 0x0804a0d5, 0x4000b070)           = -1
+strncpy(0xbffff9b4, "eth0", 16)                   = 0xbffff9b4
+memset(0xbffff828, '\000', 340)                   = 0xbffff828
+strcpy(0xbffff828, "eth0")                        = 0xbffff828
+strcpy(0xbffff7e8, "eth0")                        = 0xbffff7e8
+ioctl(5, 35091, 0xbffff7e8, 0xbffff7e8, 0xbffff9b4) = 0
+strcpy(0xbffff7e8, "eth0")                        = 0xbffff7e8
+ioctl(5, 35111, 0xbffff7e8, 0xbffff7e8, 0xbffff9b4) = 0
+strcpy(0xbffff7e8, "eth0")                        = 0xbffff7e8
+ioctl(5, 35101, 0xbffff7e8, 0xbffff7e8, 0xbffff9b4) = 0
+strcpy(0xbffff7e8, "eth0")                        = 0xbffff7e8
+ioctl(5, 35105, 0xbffff7e8, 0xbffff7e8, 0xbffff9b4) = 0
+strcpy(0xbffff7e8, "eth0")                        = 0xbffff7e8
+ioctl(5, 35184, 0xbffff7e8, 0xbffff7e8, 0xbffff9b4) = 0
+strcpy(0xbffff7e8, "eth0")                        = 0xbffff7e8
+ioctl(5, 35184, 0xbffff7e8, 0xbffff7e8, 0xbffff9b4) = 0
+strcpy(0xbffff7e8, "eth0")                        = 0xbffff7e8
+ioctl(5, 35095, 0xbffff7e8, 0xbffff9b4, 0xbffff828) = 0
+strcpy(0xbffff7e8, "eth0")                        = 0xbffff7e8
+ioctl(5, 35097, 0xbffff7e8, 0xbffff9b4, 0xbffff828) = 0
+strcpy(0xbffff7e8, "eth0")                        = 0xbffff7e8
+ioctl(5, 35099, 0xbffff7e8, 0xbffff9b4, 0xbffff828) = 0
+strcpy(0xbffff7e8, "eth0")                        = 0xbffff7e8
+ioctl(5, 35093, 0xbffff7e8, 0xbffff9b4, 0xbffff828) = 0
+strcpy(0xbffff7e8, "eth0")                        = 0xbffff7e8
+strcpy(0xbffff7e8, "eth0")                        = 0xbffff7e8
+fopen(0x0804cfe0, 0x0804cfde, 0xbffff7e8, 0xbffff828, 0xbffff9b4) = 0x0804f828
+fgets("Inter-|   Receive               "..., 255, 0x0804f828) = 0xbffff6d0
+fgets(" face |packets errs drop fifo fr"..., 255, 0x0804f828) = 0xbffff6d0
+strstr(" face |packets errs drop fifo fr"..., "bytes") = NULL
+fgets("    lo:     26    0    0    0   "..., 255, 0x0804f828) = 0xbffff6d0
+strncmp("lo:     26    0    0    0    0  "..., "eth0", 4) = 7
+fgets("  lo:0:      0    0    0    0   "..., 255, 0x0804f828) = 0xbffff6d0
+strncmp("lo:0:      0    0    0    0    0"..., "eth0", 4) = 7
+fgets("  eth0:      0    0    0    0   "..., 255, 0x0804f828) = 0xbffff6d0
+strncmp("eth0:      0    0    0    0    0"..., "eth0", 4) = 0
+strchr(0xbffff6d2, 58, 0xbffff7e8, 0xbffff828, 0xbffff9b4) = 0xbffff6d6
+strchr(0xbffff6d7, 58, 0xbffff7e8, 0xbffff828, 0xbffff9b4) = 0
+strncmp("0    0    0    0    0        0  "..., "No", 2) = -30
+sscanf(0xbffff6dd, 0x0804d02b, 0xbffff924, 0xbffff934, 0xbffff93c) = 11
+fclose(0x0804f828)                                = 0
+strncmp("eth0", "lo", 2)                          = -7
+printf("%-8.8s  Link encap:%s  ")                 = 31
+sprintf(0x0804f240, 0x0804d740, 0, 80, 78)        = 17
+printf("HWaddr %s  ")                             = 26
+printf("\n")                                      = 1
+inet_ntoa(0x010010ac, 0x0804ed64, 0xbffff828, 0x0804ef2c, 1) = 0x0804f828
+strcpy(0x0804f5d4, "172.16.0.1")                  = 0x0804f5d4
+printf("          %s addr:%s")                    = 30
+inet_ntoa(0xff0010ac, 0x0804ed64, 0xbffff828, 0x0804ef2c, 1) = 0x0804f828
+strcpy(0x0804f5d4, "172.16.0.255")                = 0x0804f5d4
+printf("  Bcast:%s  ")                            = 22
+inet_ntoa(0x00ffffff, 0x0804ed64, 0xbffff828, 0x0804ef2c, 1) = 0x0804f828
+strcpy(0x0804f5d4, "255.255.255.0")               = 0x0804f5d4
+printf("Mask:%s\n")                               = 19
+printf("          ")                              = 10
+printf("UP ")                                     = 3
+printf("BROADCAST ")                              = 10
+printf("RUNNING ")                                = 8
+printf("MULTICAST ")                              = 10
+printf(" MTU:%d  Metric:%d\n")                    = 20
+printf("          ")                              = 10
+printf("RX packets:%lu error:%lu dropped"...)     = 46
+printf("          ")                              = 10
+printf("TX packets:%lu error:%lu dropped"...)     = 58
+printf("          ")                              = 10
+printf("Interrupt:%d ")                           = 12
+printf("Base address:0x%x ")                      = 19
+printf("\n")                                      = 1
+printf("\n")                                      = 1
+close(5)                                          = 0
+exit(0)
++++ exited (status 0) +++
diff --git a/Makefile b/Makefile
index 112049f..5dde101 100644
--- a/Makefile
+++ b/Makefile
@@ -1,13 +1,23 @@
+##ARCH	:=	$(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/)
+OS	:=	$(shell uname -s)
+
+TOPDIR	=	$(shell pwd)
+
 CC	=	gcc
-CFLAGS	=	-O2 -g -Wall
+CFLAGS	=	-O2 -g -Wall -I$(TOPDIR) -I$(TOPDIR)/sysdeps/$(OS) -I- #-I$(TOPDIR)/sysdeps/$(ARCH)
 
-OBJ	=	ltrace.o functions.o elf.o i386.o symbols.o process.o syscall.o output.o signal.o
+OBJ	=	ltrace.o options.o elf.o output.o config_file.o	\
+		execute_program.o wait_for_something.o process_event.o \
+		display_args.o breakpoints.o
 
-all:		ltrace
+all:		dummy
+		$(MAKE) -C sysdeps/$(OS)
+		$(MAKE) ltrace
 
-ltrace:		ltrace.o $(OBJ)
+ltrace:		sysdeps/sysdep.o $(OBJ)
 
 clean:
+		$(MAKE) -C sysdeps/$(OS) clean
 		rm -f ltrace $(OBJ)
 
 dist:		clean
@@ -15,6 +25,12 @@
 
 install:	ltrace
 		install -d $(DESTDIR)/usr/bin $(DESTDIR)/usr/doc/ltrace $(DESTDIR)/usr/man/man1
+		install -d $(DESTDIR)/etc
 		install -s ltrace $(DESTDIR)/usr/bin
-		install -m 644 README $(DESTDIR)/usr/doc/ltrace
+		install -m 644 etc/ltrace.conf $(DESTDIR)/etc
+		install -m 644 COPYING README TODO BUGS $(DESTDIR)/usr/doc/ltrace
 		install -m 644 ltrace.1 $(DESTDIR)/usr/man/man1
+
+dummy:
+
+.EXPORT_ALL_VARIABLES:
diff --git a/README b/README
index dea41f4..81eca6c 100644
--- a/README
+++ b/README
@@ -2,7 +2,7 @@
 
                        A Dynamic Library Tracer
 
-         Copyright 1997 Juan Cespedes <cespedes@debian.org>
+         Copyright 1997,1998 Juan Cespedes <cespedes@debian.org>
 
 
 Contents
@@ -22,10 +22,12 @@
 
 2. Where can I find it
 ----------------------
-At the moment, it's only available as a Debian package, but it should
-work at least with any other i386 ELF Linux.  It's in:
- * ftp://ftp.etsit.upm.es/pub/Linux/local/ltrace_*
- * ftp://ftp.debian.org/debian/project/experimental/ltrace_*
+At the moment, it's only available as a Debian package.  Please let
+me know if you distribute it any other way.
+
+You may find it at:
+ * ftp://ftp.debian.org/debian/dists/unstable/main/source/utils/ltrace_*
+
 Alternatively, you may find it in any Debian mirror.  For more info,
 see ftp://ftp.debian.org/debian/README.mirrors
 
diff --git a/THOUGHTS b/THOUGHTS
deleted file mode 100644
index 42ffb0f..0000000
--- a/THOUGHTS
+++ /dev/null
@@ -1,25 +0,0 @@
-process_options();
-open_program();
-enable_all_breakpoints();
-execute_program();
-forever {
-	wait_for_something();
-	switch(what happened) {
-		signal:
-			log_it();
-		exit:
-			log_it();
-			if (no_more_processes()) { exit(0); }
-		syscall:
-			log_it();
-		sysret:
-			log_it();
-		breakpoint:
-			libcall:
-				enable_brk_on_libret();
-				log_it();
-			libret:
-				log_it();
-			singlestep:
-	}
-}
diff --git a/TODO b/TODO
index 29c5861..e4d947a 100644
--- a/TODO
+++ b/TODO
@@ -1,37 +1,12 @@
-* {enable,disable}_all_breakpoints should be process-dependent
-
-* All wait4's should be wait_for_child():
-  + A process may stop because:
-    - It execve()'d (needs breakpoints to be added) (DONE)
-    - It received a signal                          (DONE)
-    - It breakpointed at a library call             (DONE)
-    - It breakpointed at a library return
-    - It breakpointed at a syscall
-    - It breakpointed at a syscall return
-    - It breakpointed after a SINGLESTEP
-
-* ``struct_process'' should also have:
-  + The state of the process:
-    - uninitialized               (DONE)
-    - running
-    - within a given library call
-    - within a given syscall      (DONE)
-  + All the symbols it has breakpointed, and, for each of them:
-    - its addr
-    - the original value in the addr, if appropiate
-  + Whether a return from a libcall is pending, and if so:
-    - its return addr
-    - the original value in the return addr
-
-* I should parse a config file (/etc/ltrace.conf & ~/.ltracerc) to
-  handle different arguments to the library calls
-
-* ltrace should accept `-p' option. (hey, it's not as difficult as it
-  seems)
-
-* return values should be logged.  That implies:
-  + Breakpointing each return value
-  + Disabling breakpoints and displaying ``???'' as return value when
-    a new function is called
-
-* All architecture dependent stuff should be moved to ``arch.h''
+* Option -p (trace running process)
+* Option -f (trace children)
+* SYSCALLS:
+  + execve()		<- trace new program
+* Display different argument types:
+  + format
+  + stringN should not display `...' when limit of bytes is reached
+* Update /etc/ltrace.conf
+* SPARC:
+  + almost all...
+* netscape:
+  + Why does it shows so many `breakpointed at:' messages?
diff --git a/all.h b/all.h
deleted file mode 100644
index 94d9617..0000000
--- a/all.h
+++ /dev/null
@@ -1,135 +0,0 @@
-/* elf.c: */
-extern int read_elf(const char *);
-
-
-/*
- *	Lista de types:
- */
-
-#define	_T_INT		1
-#define	_T_ADDR		6
-
-#define	_T_UNKNOWN	-1
-#define	_T_VOID		0
-#define	_T_INT		1
-#define	_T_UINT		2
-#define	_T_OCTAL	3
-#define	_T_CHAR		4
-#define	_T_STRING	5
-#define	_T_ADDR		6
-#define	_T_FILE		7
-#define	_T_HEX		8
-#define	_T_FORMAT	9		/* printf-like format */
-
-#define	_T_OUTPUT	0x80		/* OR'ed if arg is an OUTPUT value */
-
-struct function {
-	const char * function_name;
-	int return_type;
-	int num_params;
-	int params_type[10];
-	struct function * next;
-};
-
-extern struct function * list_of_functions;
-
-extern void print_function(const char *, int pid, int esp);
-#ifndef _LTRACE_I386_H
-#define _LTRACE_I386_H
-
-#define BREAKPOINT {0xcc}
-#define BREAKPOINT_LENGTH 1
-
-struct breakpoint {
-	unsigned long addr;
-	unsigned char value[BREAKPOINT_LENGTH];
-};
-
-void insert_breakpoint(int pid, struct breakpoint * sbp);
-void delete_breakpoint(int pid, struct breakpoint * sbp);
-unsigned long get_eip(int pid);
-unsigned long get_esp(int pid);
-unsigned long get_orig_eax(int pid);
-unsigned long get_return(int pid, unsigned long esp);
-unsigned long get_arg(int pid, unsigned long esp, int arg_num);
-int is_there_a_breakpoint(int pid, unsigned long eip);
-void continue_after_breakpoint(int pid, struct breakpoint * sbp, int delete_it);
-void continue_process(int pid, int signal);
-void trace_me(void);
-void untrace_pid(int pid);
-
-#include "process.h"
-#define PROC_BREAKPOINT 1
-#define PROC_SYSCALL 2
-#define PROC_SYSRET 3
-int type_of_stop(struct process * proc, int *what);
-
-#endif
-#include <stdio.h>
-
-extern FILE * output;
-extern int opt_d;
-extern int opt_i;
-extern int opt_S;
-void send_left(const char * fmt, ...);
-void send_right(const char * fmt, ...);
-void send_line(const char * fmt, ...);
-#ifndef _LTRACE_PROCESS_H
-#define _LTRACE_PROCESS_H
-
-#include "i386.h"
-
-/* not ready yet */
-#if 0
-struct symbols_from_filename {
-	char * filename;
-	struct library_symbol * list_of_symbols;
-}
-
-struct library_symbol {
-	char * name;
-	unsigned long addr;
-	unsigned long return_addr;
-	unsigned char old_value[BREAKPOINT_LENGTH];
-	struct library_symbol * next;
-};
-#endif
-
-struct process {
-	char * filename;		/* from execve() (TODO) */
-	int pid;
-	int breakpoints_enabled;
-	struct breakpoint return_value;	/* if within a function */
-	int syscall_number;		/* outside syscall => -1 */
-	struct process * next;
-};
-
-extern struct process * list_of_processes;
-
-unsigned int instruction_pointer;
-
-int execute_process(const char * file, char * const argv[]);
-void wait_for_child(void);
-
-#endif
-extern char * signal_name[];
-#ifndef _LTRACE_SYMBOLS_H
-#define _LTRACE_SYMBOLS_H
-
-#include "i386.h"
-
-struct library_symbol {
-	char * name;
-	struct breakpoint sbp;
-	unsigned long return_addr;
-	struct library_symbol * next;
-};
-
-extern struct library_symbol * library_symbols;
-
-void enable_all_breakpoints(int pid);
-void disable_all_breakpoints(int pid);
-
-#endif
-
-extern char * syscall_list[];
diff --git a/breakpoints.c b/breakpoints.c
new file mode 100644
index 0000000..ded819d
--- /dev/null
+++ b/breakpoints.c
@@ -0,0 +1,35 @@
+#include "ltrace.h"
+#include "options.h"
+#include "output.h"
+
+void enable_all_breakpoints(struct process * proc)
+{
+	if (proc->breakpoints_enabled <= 0) {
+		struct library_symbol * tmp = proc->list_of_symbols;
+
+		if (opt_d>0) {
+			output_line(0, "Enabling breakpoints for pid %u...", proc->pid);
+		}
+		while(tmp) {
+			insert_breakpoint(proc->pid, &tmp->brk);
+			tmp = tmp->next;
+		}
+	}
+	proc->breakpoints_enabled = 1;
+}
+
+void disable_all_breakpoints(struct process * proc)
+{
+	if (proc->breakpoints_enabled) {
+		struct library_symbol * tmp = proc->list_of_symbols;
+
+		if (opt_d>0) {
+			output_line(0, "Disabling breakpoints for pid %u...", proc->pid);
+		}
+		while(tmp) {
+			delete_breakpoint(proc->pid, &tmp->brk);
+			tmp = tmp->next;
+		}
+	}
+	proc->breakpoints_enabled = 0;
+}
diff --git a/config_file.c b/config_file.c
new file mode 100644
index 0000000..71e7d3a
--- /dev/null
+++ b/config_file.c
@@ -0,0 +1,163 @@
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#include "ltrace.h"
+#include "config_file.h"
+#include "options.h"
+#include "output.h"
+
+/*
+ *	"void"		LT_PT_VOID
+ *	"int"		LT_PT_INT
+ *	"uint"		LT_PT_UINT
+ *	"octal"		LT_PT_OCTAL
+ *	"char"		LT_PT_CHAR
+ *	"string"	LT_PT_STRING
+ *	"format"	LT_PT_FORMAT
+ *	"addr"		LT_PT_ADDR
+ */
+
+struct function * list_of_functions = NULL;
+
+static struct list_of_pt_t {
+	char * name;
+	enum param_type pt;
+} list_of_pt[] = {
+	{ "void",	LT_PT_VOID },
+	{ "int",	LT_PT_INT },
+	{ "uint",	LT_PT_UINT },
+	{ "octal",	LT_PT_OCTAL },
+	{ "char",	LT_PT_CHAR },
+	{ "addr",	LT_PT_ADDR },
+	{ "file",	LT_PT_FILE },
+	{ "format",	LT_PT_FORMAT },
+	{ "string",	LT_PT_STRING },
+	{ "string0",	LT_PT_STRING0 },
+	{ "string1",	LT_PT_STRING1 },
+	{ "string2",	LT_PT_STRING2 },
+	{ "string3",	LT_PT_STRING3 },
+	{ NULL,		LT_PT_UNKNOWN }		/* Must finish with NULL */
+};
+
+static enum param_type str2type(char ** str)
+{
+	struct list_of_pt_t * tmp = &list_of_pt[0];
+
+	while(tmp->name) {
+		if (!strncmp(*str, tmp->name, strlen(tmp->name))
+			&& index(" ,)#", *(*str+strlen(tmp->name)))) {
+				*str += strlen(tmp->name);
+				return tmp->pt;
+		}
+		tmp++;
+	}
+	return LT_PT_UNKNOWN;
+}
+
+static void eat_spaces(char ** str)
+{
+	while(**str==' ') {
+		(*str)++;
+	}
+}
+
+static int line_no;
+static char * filename;
+
+struct function * process_line (char * buf) {
+	struct function fun;
+	struct function * fun_p;
+	char * str = buf;
+	char * tmp;
+	int i;
+
+	line_no++;
+	if (opt_d>1) {
+		output_line(0, "Reading line %d of `%s'", line_no, filename);
+	}
+	eat_spaces(&str);
+	fun.return_type = str2type(&str);
+	if (fun.return_type==LT_PT_UNKNOWN) {
+		if (opt_d>1) {
+			output_line(0, " Skipping line %d", line_no);
+		}
+		return NULL;
+	}
+	if (opt_d>2) {
+		output_line(0, " return_type = %d", fun.return_type);
+	}
+	eat_spaces(&str);
+	tmp = strpbrk(str, " (");
+	if (!tmp) {
+		output_line(0, "Syntax error in `%s', line %d", filename, line_no);
+		return NULL;
+	}
+	*tmp = '\0';
+	fun.name = strdup(str);
+	str = tmp+1;
+	if (opt_d>2) {
+		output_line(0, " name = %s", fun.name);
+	}
+	fun.params_right = 0;
+	for(i=0; i<MAX_ARGS; i++) {
+		eat_spaces(&str);
+		if (*str == ')') {
+			break;
+		}
+		if (str[0]=='+') {
+			fun.params_right++;
+			str++;
+		} else if (fun.params_right) {
+			fun.params_right++;
+		}
+		fun.param_types[i] = str2type(&str);
+		if (fun.return_type==LT_PT_UNKNOWN) {
+			output_line(0, "Syntax error in `%s', line %d", filename, line_no);
+			return NULL;
+		}
+		eat_spaces(&str);
+		if (*str==',') {
+			str++;
+			continue;
+		} else if (*str==')') {
+			continue;
+		} else {
+			output_line(0, "Syntax error in `%s', line %d", filename, line_no);
+			return NULL;
+		}
+	}
+	fun.num_params = i;
+	fun_p = malloc(sizeof(struct function));
+	memcpy(fun_p, &fun, sizeof(struct function));
+	return fun_p;
+}
+
+void read_config_file(char * file)
+{
+	FILE * stream;
+	char buf[1024];
+
+	filename = file;
+
+	if (opt_d) {
+		output_line(0, "Reading config file `%s'...", filename);
+	}
+
+	stream = fopen(filename, "r");
+	if (!stream) {
+		return;
+	}
+	line_no=0;
+	while (fgets(buf, 1024, stream)) {
+		struct function * tmp = process_line(buf);
+
+		if (tmp) {
+			if (opt_d) {
+				output_line(0, "New function: `%s'", tmp->name);
+			}
+			tmp->next = list_of_functions;
+			list_of_functions = tmp;
+		}
+	}
+}
diff --git a/config_file.h b/config_file.h
new file mode 100644
index 0000000..9230c0a
--- /dev/null
+++ b/config_file.h
@@ -0,0 +1,2 @@
+extern void read_config_file(char*);
+
diff --git a/debian/changelog b/debian/changelog
index c06caad..340ca18 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,5 +1,27 @@
+ltrace (0.2.0) unstable; urgency=low
+
+  * First `unstable' release
+  * Complete re-structured all the code to be able to add support for
+    different architectures (but only i386 arch is supported in this
+    version)
+  * Log also return values
+  * Log arguments (and return values) for syscalls
+  * Added preliminary support for various simultaneous processes
+  * getopt-like options
+  * New option: -a (alignment column)
+  * New option: -L (don't display library calls)
+  * New option: -s (maximum # of chars in strings)
+  * Now it reads config files with function names and parameter types
+  * Programs using clone() should work ok now
+  * debian/rules: gzipped only big files in /usr/doc/ltrace
+  * New Standards-Version: 2.4.0.0
+  * beginning to work on sparc port (not yet done)
+
+ -- Juan Cespedes <cespedes@debian.org>  Sun,  8 Mar 1998 22:27:30 +0100
+
 ltrace (0.1.7) experimental; urgency=low
 
+  * Internal release.
   * New Standards-Version (2.3.0.1)
   * Clean up structures a bit
   * Trying to log return values...
diff --git a/debian/conffiles b/debian/conffiles
index 0b4e677..1c10cee 100644
--- a/debian/conffiles
+++ b/debian/conffiles
@@ -1 +1 @@
-/etc/ltrace.rc
+/etc/ltrace.conf
diff --git a/debian/control b/debian/control
index 396ce14..8c54af0 100644
--- a/debian/control
+++ b/debian/control
@@ -2,7 +2,7 @@
 Section: utils
 Priority: optional
 Maintainer: Juan Cespedes <cespedes@debian.org>
-Standards-Version: 2.3.0.0
+Standards-Version: 2.4.0.0
 
 Package: ltrace
 Architecture: i386
@@ -10,5 +10,12 @@
 Description: A library call tracer
  ltrace is a library call tracer, i.e. a debugging tool which prints out
  a trace of all the dynamic library calls made by another process/program.
+ .
+ It also displays system calls, as well as `strace', but strace still
+ does a better job displaying arguments to system calls.
+ .
  The program to be traced need not be recompiled for this, so you can
- use it on binaries for which you don't have source.
+ use it on binaries for which you don't have the source handy.
+ .
+ This is still a work in progress, so some things may fail or don't work
+ as expected.
diff --git a/debian/copyright b/debian/copyright
index 106ee71..12fad64 100644
--- a/debian/copyright
+++ b/debian/copyright
@@ -4,7 +4,7 @@
 
 Copyrights
 ----------
-Copyright (C) 1997 Juan Cespedes <cespedes@debian.org>
+Copyright (C) 1997,1998 Juan Cespedes <cespedes@debian.org>
 
 
 License
diff --git a/debian/rules b/debian/rules
index 35be3a5..23bb348 100755
--- a/debian/rules
+++ b/debian/rules
@@ -1,6 +1,6 @@
 #! /usr/bin/make -f 
 #
-# Copyright (C) 1997 Juan Cespedes <cespedes@debian.org>
+# Copyright (C) 1997,1998 Juan Cespedes <cespedes@debian.org>
 
 build:
 		$(MAKE)
@@ -15,16 +15,17 @@
 		$(RM) -rf debian/tmp
 
 		install -d debian/tmp/DEBIAN
+		cp debian/conffiles debian/tmp/DEBIAN
 		$(MAKE) install DESTDIR=`pwd`/debian/tmp
-		cp -p README debian/tmp/usr/doc/ltrace
-		cp -p BUGS debian/tmp/usr/doc/ltrace
-		cp -p TODO debian/tmp/usr/doc/ltrace
+		$(RM) debian/tmp/usr/doc/ltrace/COPYING
 		cp -p debian/changelog debian/tmp/usr/doc/ltrace
-		gzip -9fv debian/tmp/usr/doc/ltrace/*
+		gzip -9f debian/tmp/usr/doc/ltrace/README debian/tmp/usr/doc/ltrace/changelog
 		cp -p debian/copyright debian/tmp/usr/doc/ltrace
 		gzip -9f debian/tmp/usr/man/man1/*
 		dpkg-shlibdeps debian/tmp/usr/bin/ltrace
 		dpkg-gencontrol
+		chown -R root.root debian/tmp
+		chmod -R u+rw,go-w debian/tmp
 		dpkg --build debian/tmp ..
 
 clean:
diff --git a/defs.h b/defs.h
new file mode 100644
index 0000000..85986f3
--- /dev/null
+++ b/defs.h
@@ -0,0 +1,13 @@
+
+#ifndef DEFAULT_ACOLUMN
+#define DEFAULT_ACOLUMN	50	/* default alignment column for results */
+#endif				/* (-a switch) */
+
+#ifndef MAX_ARGS
+#define MAX_ARGS        32      /* maximum number of args to a syscall */
+#endif
+
+#ifndef DEFAULT_STRLEN
+#define DEFAULT_STRLEN  32      /* default maximum # of bytes printed in */
+#endif				/* strings (-s switch) */
+
diff --git a/display_args.c b/display_args.c
new file mode 100644
index 0000000..e5ca197
--- /dev/null
+++ b/display_args.c
@@ -0,0 +1,130 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "ltrace.h"
+#include "options.h"
+
+static int display_char(char what);
+static int display_string(enum tof type, struct process * proc, int arg_num);
+static int display_stringN(int arg2, enum tof type, struct process * proc, int arg_num);
+static int display_unknown(enum tof type, struct process * proc, int arg_num);
+
+int display_arg(enum tof type, struct process * proc, int arg_num, enum param_type rt)
+{
+	int tmp;
+	long arg;
+
+	switch(rt) {
+		case LT_PT_VOID:
+			return 0;
+		case LT_PT_INT:
+			return fprintf(output, "%d", (int)gimme_arg(type, proc, arg_num));
+		case LT_PT_UINT:
+			return fprintf(output, "%u", (unsigned)gimme_arg(type, proc, arg_num));
+		case LT_PT_OCTAL:
+			return fprintf(output, "0%o", (unsigned)gimme_arg(type, proc, arg_num));
+		case LT_PT_CHAR:
+			tmp = fprintf(output, "'");
+			tmp += display_char((int)gimme_arg(type, proc, arg_num));
+			tmp += fprintf(output, "'");
+			return tmp;
+		case LT_PT_ADDR:
+			arg = gimme_arg(type, proc, arg_num);
+			if (!arg) {
+				return fprintf(output, "NULL");
+			} else {
+				return fprintf(output, "0x%08x", (unsigned)arg);
+			}
+		case LT_PT_FORMAT:
+		case LT_PT_STRING:
+			return display_string(type, proc, arg_num);
+		case LT_PT_STRING0:
+			return display_stringN(0, type, proc, arg_num);
+		case LT_PT_STRING1:
+			return display_stringN(1, type, proc, arg_num);
+		case LT_PT_STRING2:
+			return display_stringN(2, type, proc, arg_num);
+		case LT_PT_STRING3:
+			return display_stringN(3, type, proc, arg_num);
+		case LT_PT_UNKNOWN:
+		default:
+			return display_unknown(type, proc, arg_num);
+	}
+	return fprintf(output, "?");
+}
+
+static int display_char(char what)
+{
+	switch(what) {
+		case -1:	return fprintf(output, "EOF");
+		case '\r':	return fprintf(output, "\\r");
+		case '\n':	return fprintf(output, "\\n");
+		case '\t':	return fprintf(output, "\\t");
+		case '\\':	return fprintf(output, "\\");
+		default:
+			if ((what<32) || (what>126)) {
+				return fprintf(output, "\\%03o", what);
+			} else {
+				return fprintf(output, "%c", what);
+			}
+	}
+}
+
+static int display_string(enum tof type, struct process * proc, int arg_num)
+{
+	void * addr;
+	char * str1;
+	int i;
+	int len=0;
+
+	addr = (void *)gimme_arg(type, proc, arg_num);
+	if (!addr) {
+		return fprintf(output, "NULL");
+	}
+
+	str1 = malloc(opt_s+3);
+	if (!str1) {
+		return fprintf(output, "???");
+	}
+	umovestr(proc, addr, opt_s+1, str1);
+	len = fprintf(output, "\"");
+	for(i=0; len<opt_s+1; i++) {
+		if (str1[i]) {
+			len += display_char(str1[i]);
+		} else {
+			break;
+		}
+	}
+	len += fprintf(output, "\"");
+	if (str1[i]) {
+		len += fprintf(output, "...");
+	}
+	free(str1);
+	return len;
+}
+
+#define MIN(a,b) (((a)<(b)) ? (a) : (b))
+
+static int display_stringN(int arg2, enum tof type, struct process * proc, int arg_num)
+{
+	int a,b;
+	a = gimme_arg(type, proc, arg2-1);
+	b = opt_s;
+	opt_s = MIN(opt_s, a);
+	a = display_string(type, proc, arg_num);
+	opt_s = b;
+	return a;
+}
+
+static int display_unknown(enum tof type, struct process * proc, int arg_num)
+{
+	long tmp;
+
+	tmp = gimme_arg(type, proc, arg_num);
+
+	if (tmp<1000000 && tmp>-1000000) {
+		return fprintf(output, "%ld", tmp);
+	} else {
+		return fprintf(output, "0x%08lx", tmp);
+	}
+}
diff --git a/elf.c b/elf.c
index 08e4b67..f285011 100644
--- a/elf.c
+++ b/elf.c
@@ -8,29 +8,31 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
-#include <linux/elf.h>
+#include <elf.h>
 #include <sys/mman.h>
 #include <string.h>
+#include <unistd.h>
 
-#include "elf.h"
 #include "ltrace.h"
-#include "symbols.h"
+#include "elf.h"
+#include "options.h"
 #include "output.h"
 
-int read_elf(const char *filename)
+struct library_symbol * read_elf(const char *filename)
 {
+	struct library_symbol * library_symbols = NULL;
 	struct stat sbuf;
 	int fd;
 	void * addr;
-	struct elf32_hdr * hdr;
+	Elf32_Ehdr * hdr;
 	Elf32_Shdr * shdr;
-	struct elf32_sym * symtab = NULL;
+	Elf32_Sym * symtab = NULL;
 	int i;
 	char * strtab = NULL;
 	u_long symtab_len = 0;
 
 	if (opt_d>0) {
-		send_line("Reading symbol table from %s...", filename);
+		output_line(0, "Reading symbol table from %s...", filename);
 	}
 
 	fd = open(filename, O_RDONLY);
@@ -42,8 +44,8 @@
 		fprintf(stderr, "Can't stat \"%s\": %s\n", filename, sys_errlist[errno]);
 		exit(1);
 	}
-	if (sbuf.st_size < sizeof(struct elf32_hdr)) {
-		fprintf(stderr, "\"%s\" is not an ELF object\n", filename);
+	if (sbuf.st_size < sizeof(Elf32_Ehdr)) {
+		fprintf(stderr, "\"%s\" is not an ELF binary object\n", filename);
 		exit(1);
 	}
 	addr = mmap(NULL, sbuf.st_size, PROT_READ, MAP_SHARED, fd, 0);
@@ -53,7 +55,7 @@
 	}
 	hdr = addr;
 	if (strncmp(hdr->e_ident, ELFMAG, SELFMAG)) {
-		fprintf(stderr, "\"%s\" is not an ELF object\n", filename);
+		fprintf(stderr, "\"%s\" is not an ELF binary object\n", filename);
 		exit(1);
 	}
 	for(i=0; i<hdr->e_shnum; i++) {
@@ -61,9 +63,9 @@
 		if (shdr->sh_type == SHT_DYNSYM) {
 			if (!symtab) {
 #if 0
-				symtab = (struct elf32_sym *)shdr->sh_addr;
+				symtab = (Elf32_Sym *)shdr->sh_addr;
 #else
-				symtab = (struct elf32_sym *)(addr + shdr->sh_offset);
+				symtab = (Elf32_Sym *)(addr + shdr->sh_offset);
 #endif
 				symtab_len = shdr->sh_size;
 			}
@@ -75,14 +77,15 @@
 		}
 	}
 	if (opt_d>1) {
-		send_line("symtab: 0x%08x", (unsigned)symtab);
-		send_line("symtab_len: %lu", symtab_len);
-		send_line("strtab: 0x%08x", (unsigned)strtab);
+		output_line(0, "symtab: 0x%08x", (unsigned)symtab);
+		output_line(0, "symtab_len: %lu", symtab_len);
+		output_line(0, "strtab: 0x%08x", (unsigned)strtab);
 	}
 	if (!symtab) {
-		return 0;
+		close(fd);
+		return NULL;
 	}
-	for(i=0; i<symtab_len/sizeof(struct elf32_sym); i++) {
+	for(i=0; i<symtab_len/sizeof(Elf32_Sym); i++) {
 		if (!((symtab+i)->st_shndx) && (symtab+i)->st_value) {
 			struct library_symbol * tmp = library_symbols;
 
@@ -91,16 +94,18 @@
 				perror("malloc");
 				exit(1);
 			}
-			library_symbols->sbp.addr = ((symtab+i)->st_value);
+			library_symbols->brk.addr = (void *)((symtab+i)->st_value);
+			library_symbols->brk.enabled = 0;
 			library_symbols->name = strtab+(symtab+i)->st_name;
 			library_symbols->next = tmp;
 			if (opt_d>1) {
-				send_line("addr: 0x%08x, symbol: \"%s\"",
+				output_line(0, "addr: 0x%08x, symbol: \"%s\"",
 					(unsigned)((symtab+i)->st_value),
 					(strtab+(symtab+i)->st_name));
 			}
 		}
 	}
-	return 1;
+	close(fd);
+	return library_symbols;
 }
 
diff --git a/elf.h b/elf.h
index fbb9001..dc5bb46 100644
--- a/elf.h
+++ b/elf.h
@@ -1,3 +1,4 @@
+#include "ltrace.h"
 
-extern int read_elf(const char *);
+extern struct library_symbol * read_elf(const char *);
 
diff --git a/etc/ltrace.conf b/etc/ltrace.conf
new file mode 100644
index 0000000..1ce3e6c
--- /dev/null
+++ b/etc/ltrace.conf
@@ -0,0 +1,87 @@
+; ltrace.conf
+
+; Argument types:
+; +		== May vary (ie, is a returned value) (prefix)
+; void
+; int
+; uint		== (unsigned int)
+; octal		== (unsigned)			[written in octal]
+; char
+; addr		== (void *)			[unsigned, written in hexa]
+; file		== (FILE *)						[TODO]
+; format	== ((const char *), ...)	[printf() like]		[TODO]
+; string	== (char *)
+; stringN	== (char *)		[N>=0]	[show only up to (arg N) bytes]
+
+; errno.h
+addr __errno_location(void);
+
+; fcntl.h
+int open(string,int,octal);		; WARNING: 3rd argument may not be there
+
+; getopt.h
+int getopt_long(int,addr,string,addr,addr);
+
+; libintl.h
+string bindtextdomain(string, string);
+string textdomain(string);
+
+; libio.h
+int _IO_putc(char,file);
+
+; locale.h
+string setlocale(int, string);
+
+; stdio.h
+int fclose(file);
+addr fgets(+string, uint, file);
+int fprintf(file,format);
+int fputs(string,file);
+int printf(format);
+
+; unistd.h
+int close(int);
+int fork(void);
+int geteuid(void);
+int gethostname(+string2,int);
+int mkdir(string,octal);
+int read(int, +string0, uint);
+int sethostname(+string2,int);
+uint sleep(uint);
+int sync(void);
+int write(int, string3, uint);
+
+; stdlib.h
+int atexit(addr);
+void exit(int);
+void free(addr);
+addr malloc(int);
+
+; string.h
+addr memset(addr,char,int);
+string rindex(string,char);
+int strcmp(string,string);
+addr strcpy(addr,string);
+addr strdup(string);
+int strncmp(string,string,int);
+addr strncpy(addr,string3,uint);
+string strrchr(string,char);
+string strstr(string,string);
+
+; time.h
+int time(addr);
+
+; SYSCALLS
+addr SYS_brk(addr);
+int  SYS_close(int);
+int  SYS_execve(string,addr,addr);
+void SYS_exit(int);
+int  SYS_fork(void);
+int  SYS_getpid(void);
+;addr SYS_mmap(addr,int,int,int,int,int);
+int  SYS_munmap(addr,uint);
+int  SYS_open(string,int,octal);
+int  SYS_personality(uint);
+int  SYS_read(int,+string0,uint);
+int  SYS_write(int,string3,uint);
+int  SYS_sync(void);
diff --git a/etc/ltrace.rc b/etc/ltrace.rc
deleted file mode 100644
index 548c39d..0000000
--- a/etc/ltrace.rc
+++ /dev/null
@@ -1,37 +0,0 @@
-; +		== May vary (ie, is a returned value)
-; int
-; addr		== (void *)		[int, written in hexa]
-; file		== (FILE *)
-; format	== ((char *), ...)	[printf() like]
-; octal		== int			[written in octal]
-; string	== (char *)
-
-int atexit(addr);
-int close(int);
-int exit(int);
-int fclose(file);
-int fprintf(file,format);
-int free(addr);
-int gethostname(+string,int);
-int getopt_long(int,addr,string,addr,addr);
-addr malloc(int);
-addr memset(addr,char,int);
-int mkdir(string,octal);
-int open(string,int,octal);			<- OJO
-int printf(format);
-string rindex(string,char);
-int strcmp(string,string);
-int strncmp(string,string,int);
-int time(addr);
-
-; #define	_T_UNKNOWN	-1
-; #define	_T_VOID		0
-; #define	_T_INT		1
-; #define	_T_UINT		2
-; #define	_T_OCTAL	3
-; #define	_T_CHAR		4
-; #define	_T_STRING	5
-; #define	_T_ADDR		6
-; #define	_T_FILE		7
-; #define	_T_HEX		8
-; #define	_T_FORMAT	9		/* printf-like format */
diff --git a/execute_program.c b/execute_program.c
new file mode 100644
index 0000000..02d6471
--- /dev/null
+++ b/execute_program.c
@@ -0,0 +1,37 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+
+#include "ltrace.h"
+#include "options.h"
+#include "output.h"
+#include "sysdep.h"
+
+void execute_program(struct process * sp, char **argv)
+{
+	int pid;
+
+	if (opt_d) {
+		output_line(0, "Executing `%s'...", sp->filename);
+	}
+
+	pid = fork();
+	if (pid<0) {
+		perror("fork");
+		exit(1);
+	} else if (!pid) {	/* child */
+		trace_me();
+		execvp(sp->filename, argv);
+		fprintf(stderr, "Can't execute `%s': %s\n", sp->filename, strerror(errno));
+		exit(1);
+	}
+
+	if (opt_d) {
+		output_line(0, "PID=%d", pid);
+	}
+
+	sp->pid = pid;
+
+	return;
+}
diff --git a/functions.c b/functions.c
deleted file mode 100644
index 7070ecc..0000000
--- a/functions.c
+++ /dev/null
@@ -1,182 +0,0 @@
-#include <stdio.h>
-#include <string.h>
-#include <sys/ptrace.h>
-#include <stdlib.h>
-#include <ctype.h>
-
-#include "functions.h"
-#include "output.h"
-
-static int current_pid;
-
-struct function * list_of_functions = NULL;
-
-struct function functions_list[] = {
-	{"atexit",      _T_INT,     1, {_T_ADDR}},
-	{"close",       _T_INT,     1, {_T_INT}},
-	{"exit",        _T_INT,     1, {_T_INT}},
-	{"fclose",      _T_INT,     1, {_T_FILE}},
-	{"fprintf",     _T_INT,     2, {_T_FILE, _T_FORMAT}},
-	{"free",        _T_INT,     1, {_T_ADDR}},
-	{"gethostname", _T_INT,     2, {_T_STRING, _T_INT}},
-	{"getopt_long", _T_INT,     5, {_T_INT, _T_ADDR, _T_STRING, _T_ADDR, _T_ADDR}},
-	{"malloc",      _T_ADDR,    1, {_T_UINT}},
-	{"memset",      _T_ADDR,    3, {_T_ADDR, _T_CHAR, _T_UINT}},
-	{"mkdir",       _T_INT,     2, {_T_STRING, _T_OCTAL}},
-	{"open",        _T_INT,     3, {_T_STRING, _T_INT, _T_INT}},
-	{"printf",      _T_INT,     1, {_T_FORMAT}},
-	{"rindex",      _T_STRING,  2, {_T_STRING, _T_CHAR}},
-	{"strcmp",      _T_INT,     2, {_T_STRING, _T_STRING}},
-	{"strncmp",     _T_INT,     3, {_T_STRING, _T_STRING, _T_INT}},
-	{"time",        _T_UINT,    1, {_T_ADDR}},
-	{NULL,          _T_UNKNOWN, 5, {_T_UNKNOWN, _T_UNKNOWN, _T_UNKNOWN, _T_UNKNOWN, _T_UNKNOWN}},
-};
-
-static char * process_string(unsigned char * str)
-{
-	static char tmp[256];
-
-	tmp[0] = '\0';
-	while(*str) {
-		switch(*str) {
-			case '\r':	strcat(tmp,"\\r"); break;
-			case '\n':	strcat(tmp,"\\n"); break;
-			case '\t':	strcat(tmp,"\\t"); break;
-			case '\\':	strcat(tmp,"\\"); break;
-			default:
-				if ((*str<32) || (*str>126)) {
-					sprintf(tmp,"%s\\%03o", tmp, *str);
-				} else {
-					sprintf(tmp, "%s%c", tmp, *str);
-				}
-		}
-		str++;
-	}
-	return tmp;
-}
-
-static char * print_string(int addr)
-{
-	static char tmp[256];
-	int a;
-	int i=0;
-
-	tmp[0] = '\0';
-	while(1) {
-		a = ptrace(PTRACE_PEEKTEXT, current_pid, addr+i, 0);
-		*(int *)&tmp[i] = a;
-		if (!tmp[i] || !tmp[i+1] || !tmp[i+2] || !tmp[i+3] || i>100) {
-			break;
-		}
-		i += 4;
-	}
-	return process_string(tmp);
-}
-
-static char * print_param(int type, int esp)
-{
-	static char tmp[256];
-	int a;
-
-	a = ptrace(PTRACE_PEEKTEXT, current_pid, esp, 0);
-
-	switch(type) {
-		case _T_STRING:
-		case _T_FORMAT:
-			sprintf(tmp,"\"%s\"",print_string(a));
-			break;
-		default:
-			if (a<1000000 && a>-1000000) {
-				sprintf(tmp, "%d", a);
-			} else {
-				sprintf(tmp, "0x%08x", a);
-			}
-	}
-	return tmp;
-}
-
-void print_function(const char *name, int pid, int esp)
-{
-	struct function * tmp;
-	char message[1024];
-	int i;
-
-	current_pid = pid;
-
-	tmp = list_of_functions;
-	while(tmp) {
-		if (!strcmp(name, tmp->function_name)) {
-			break;
-		}
-	}
-	if (!tmp) {
-		tmp = &functions_list[0];
-		while(tmp->function_name) {
-			if (!strcmp(name, tmp->function_name)) {
-				break;
-			}
-			tmp++;
-		}
-	}
-	sprintf(message, "%s(", name);
-	if (tmp->num_params>0) {
-		sprintf(message, "%s%s", message, print_param(tmp->params_type[0], esp+4));
-	}
-	for(i=1; i<tmp->num_params; i++) {
-		sprintf(message, "%s,%s", message, print_param(tmp->params_type[i], esp+4*(i+1)));
-	}
-	send_left("%s", message);
-	send_right(") = ???");
-}
-
-static int func_type(char ** buf)
-{
-	int returned_value = 0;
-
-	if (**buf == '+') {
-		returned_value |= _T_OUTPUT;
-		(*buf)++;
-	}
-	if (!strcmp(*buf, "int")) {
-		returned_value |= _T_INT;
-		*buf += 3;
-	} else if (!strcmp(*buf, "addr")) {
-		returned_value |= _T_ADDR;
-		*buf += 4;
-	} else {
-		return -1;
-	}
-	return returned_value;
-}
-
-static int fill_fields(struct function * fun, char * buf)
-{
-	char * tmp = buf;
-
-	for(; (*tmp==' '); tmp++);
-	if ((fun->return_type = func_type(&buf)) == -1) {
-		return 0;
-	}
-	for(; (*tmp==' '); tmp++);
-
-	return 0;
-}
-
-void read_config_file(const char * filename)
-{
-	char buf[1024];
-	FILE * stream;
-	struct function tmp;
-
-	stream = fopen(filename, "r");
-	if (!stream) {
-		return;
-	}
-	while (fgets(buf, 1024, stream)) {
-		if (fill_fields(&tmp, buf)) {
-			tmp.next = list_of_functions;
-			list_of_functions = malloc(sizeof(struct function));
-			bcopy(&tmp, list_of_functions, sizeof(struct function));
-		}
-	}
-}
diff --git a/functions.h b/functions.h
deleted file mode 100644
index 2df9247..0000000
--- a/functions.h
+++ /dev/null
@@ -1,33 +0,0 @@
-
-/*
- *	Lista de types:
- */
-
-#define	_T_INT		1
-#define	_T_ADDR		6
-
-#define	_T_UNKNOWN	-1
-#define	_T_VOID		0
-#define	_T_INT		1
-#define	_T_UINT		2
-#define	_T_OCTAL	3
-#define	_T_CHAR		4
-#define	_T_STRING	5
-#define	_T_ADDR		6
-#define	_T_FILE		7
-#define	_T_HEX		8
-#define	_T_FORMAT	9		/* printf-like format */
-
-#define	_T_OUTPUT	0x80		/* OR'ed if arg is an OUTPUT value */
-
-struct function {
-	const char * function_name;
-	int return_type;
-	int num_params;
-	int params_type[10];
-	struct function * next;
-};
-
-extern struct function * list_of_functions;
-
-extern void print_function(const char *, int pid, int esp);
diff --git a/i386.c b/i386.c
deleted file mode 100644
index 4d62b43..0000000
--- a/i386.c
+++ /dev/null
@@ -1,144 +0,0 @@
-#include <sys/ptrace.h>
-#include <sys/types.h>
-#include <sys/resource.h>
-#include <sys/wait.h>
-#include <errno.h>
-#include <stdio.h>
-
-#include "i386.h"
-#include "ltrace.h"
-
-void insert_breakpoint(int pid, struct breakpoint * sbp)
-{
-	int a;
-
-	a = ptrace(PTRACE_PEEKTEXT, pid, sbp->addr, 0);
-	sbp->value[0] = a & 0xFF;
-	a &= 0xFFFFFF00;
-	a |= 0xCC;
-	ptrace(PTRACE_POKETEXT, pid, sbp->addr, a);
-}
-
-void delete_breakpoint(int pid, struct breakpoint * sbp)
-{
-	int a;
-
-	a = ptrace(PTRACE_PEEKTEXT, pid, sbp->addr, 0);
-	a &= 0xFFFFFF00;
-	a |= sbp->value[0];
-	ptrace(PTRACE_POKETEXT, pid, sbp->addr, a);
-}
-
-unsigned long get_eip(int pid)
-{
-	unsigned long eip;
-
-	eip = ptrace(PTRACE_PEEKUSER, pid, 4*EIP, 0);
-
-	return eip-1;			/* Length of breakpoint (0xCC) is 1 byte */
-}
-
-unsigned long get_esp(int pid)
-{
-	unsigned long esp;
-
-	esp = ptrace(PTRACE_PEEKUSER, pid, 4*UESP, 0);
-
-	return esp;
-}
-
-unsigned long get_orig_eax(int pid)
-{
-	return ptrace(PTRACE_PEEKUSER, pid, 4*ORIG_EAX);
-}
-
-unsigned long get_return(int pid, unsigned long esp)
-{
-	return ptrace(PTRACE_PEEKTEXT, pid, esp, 0);
-}
-
-unsigned long get_arg(int pid, unsigned long esp, int arg_num)
-{
-	return ptrace(PTRACE_PEEKTEXT, pid, esp+4*arg_num);
-}
-
-int is_there_a_breakpoint(int pid, unsigned long eip)
-{
-	int a;
-	a = ptrace(PTRACE_PEEKTEXT, pid, eip, 0);
-	if ((a & 0xFF) == 0xCC) {
-		return 1;
-	} else {
-		return 0;
-	}
-}
-
-void continue_process(int pid, int signal)
-{
-	ptrace(PTRACE_SYSCALL, pid, 1, signal);
-}
-
-void continue_after_breakpoint(int pid, struct breakpoint * sbp, int delete_it)
-{
-	delete_breakpoint(pid, sbp);
-	ptrace(PTRACE_POKEUSER, pid, 4*EIP, sbp->addr);
-	if (delete_it) {
-		continue_process(pid, 0);
-	} else {
-		int status;
-
-		ptrace(PTRACE_SINGLESTEP, pid, 0, 0);
-
-		pid = wait4(pid, &status, 0, NULL);
-		if (pid==-1) {
-			perror("wait4");
-			exit(1);
-		}
-		insert_breakpoint(pid, sbp);
-		continue_process(pid, 0);
-	}
-}
-
-void trace_me(void)
-{
-	if (ptrace(PTRACE_TRACEME, 0, 1, 0)<0) {
-		perror("PTRACE_TRACEME");
-		exit(1);
-	}
-}
-
-void untrace_pid(int pid)
-{
-	if (ptrace(PTRACE_DETACH, pid, 0, 0)<0) {
-		perror("PTRACE_DETACH");
-		exit(1);
-	}
-}
-
-/*
- * Return values:
- *  PROC_BREAKPOINT - Breakpoint
- *  PROC_SYSCALL - Syscall entry
- *  PROC_SYSRET - Syscall return
- */
-int type_of_stop(int pid, struct proc_arch * proc_arch, int *what)
-{
-	*what = get_orig_eax(pid);
-
-	if (*what!=-1) {
-		if (proc_arch->syscall_number != *what) {
-			proc_arch->syscall_number = *what;
-			return PROC_SYSCALL;
-		} else {
-			proc_arch->syscall_number = -1;
-			return PROC_SYSRET;
-		}
-	}
-
-	return PROC_BREAKPOINT;
-}
-
-void proc_arch_init(struct proc_arch *proc_arch)
-{
-	proc_arch->syscall_number=-1;
-}
diff --git a/i386.h b/i386.h
deleted file mode 100644
index aecb891..0000000
--- a/i386.h
+++ /dev/null
@@ -1,35 +0,0 @@
-#ifndef _LTRACE_I386_H
-#define _LTRACE_I386_H
-
-#define BREAKPOINT {0xcc}
-#define BREAKPOINT_LENGTH 1
-
-struct breakpoint {
-	unsigned long addr;
-	unsigned char value[BREAKPOINT_LENGTH];
-};
-
-void insert_breakpoint(int pid, struct breakpoint * sbp);
-void delete_breakpoint(int pid, struct breakpoint * sbp);
-unsigned long get_eip(int pid);
-unsigned long get_esp(int pid);
-unsigned long get_orig_eax(int pid);
-unsigned long get_return(int pid, unsigned long esp);
-unsigned long get_arg(int pid, unsigned long esp, int arg_num);
-int is_there_a_breakpoint(int pid, unsigned long eip);
-void continue_after_breakpoint(int pid, struct breakpoint * sbp, int delete_it);
-void continue_process(int pid, int signal);
-void trace_me(void);
-void untrace_pid(int pid);
-
-struct proc_arch {
-	int syscall_number;		/* outside syscall => -1 */
-};
-
-#define PROC_BREAKPOINT 1
-#define PROC_SYSCALL 2
-#define PROC_SYSRET 3
-int type_of_stop(int pid, struct proc_arch *proc_arch, int *what);
-void proc_arch_init(struct proc_arch *proc_arch);
-
-#endif
diff --git a/ltrace.1 b/ltrace.1
index 1d5ef9b..0d41e28 100644
--- a/ltrace.1
+++ b/ltrace.1
@@ -6,7 +6,7 @@
 
 .SH SYNOPSIS
 .B ltrace
-.I "[-d] [-o filename] command [arg ...]"
+.I "[-diLS] [-a column] [-s strsize] [-o filename] command [arg ...]"
 
 .SH DESCRIPTION
 .B ltrace
@@ -21,12 +21,28 @@
 
 .SH OPTIONS
 .TP
+.I \-a column
+Align return values in a secific column (default column 50).
 .I \-d
 Increase the debugging level.
 .TP
+.I \-f
+Trace child processes as they are created by
+currently  traced processes as a result of the fork(2)
+or clone(2) system calls.
+The new process is attached as soon as its pid is known.
+.TP
 .I \-i
 Print the instruction pointer at the time of the library call.
 .TP
+.I \-s
+Specify the maximum string size to print (the default is 32).
+.TP
+.I \-L
+DON'T display library calls (use it with the
+.I \-S
+option).
+.TP
 .I \-S
 Display system calls as well as library calls
 .TP
@@ -42,6 +58,15 @@
 .BR bug(1)
 program if you are under Debian GNU/Linux.
 
+.SH FILES
+.TP
+.I /etc/ltrace.conf
+System configuration file
+.TP
+.I ~/.ltrace.conf
+Personal config file, overrides
+.I /etc/ltrace.conf
+
 .SH AUTHOR
 Juan Cespedes <cespedes@debian.org>
 
diff --git a/ltrace.c b/ltrace.c
index facea03..a05f5b5 100644
--- a/ltrace.c
+++ b/ltrace.c
@@ -1,113 +1,60 @@
 #include <stdio.h>
 #include <stdlib.h>
-#include <sys/param.h>
-#include <errno.h>
 #include <unistd.h>
 #include <string.h>
+#include <errno.h>
+#include <sys/param.h>
 
+#include "ltrace.h"
 #include "elf.h"
-#include "process.h"
 #include "output.h"
+#include "config_file.h"
+#include "options.h"
 
-extern void read_config_file(const char *);
+char * command;
+struct process * list_of_processes = NULL;
 
-FILE * output = stderr;
-int opt_d = 0;		/* debug */
-int opt_i = 0;		/* instruction pointer */
-int opt_S = 0;		/* syscalls */
-
-static void usage(void)
-{
-	fprintf(stderr,"Usage: ltrace [-d] [-i] [-S] [-o filename] command [arg ...]\n\n");
-}
-
-static char * search_for_command(char * filename)
-{
-	static char pathname[MAXPATHLEN];
-	char *path;
-	int m, n;
-
-	if (strchr(filename, '/')) {
-		return filename;
-	}
-	for (path = getenv("PATH"); path && *path; path += m) {
-		if (strchr(path, ':')) {
-			n = strchr(path, ':') - path;
-			m = n + 1;
-		} else {
-			m = n = strlen(path);
-		}
-		strncpy(pathname, path, n);
-		if (n && pathname[n - 1] != '/') {
-			pathname[n++] = '/';
-		}
-		strcpy(pathname + n, filename);
-		if (!access(pathname, X_OK)) {
-			break;
-		}
-	}
-	if (access(pathname, X_OK)) {
-		return NULL;
-	} else {
-		return pathname;
-	}
-}
+static struct process * open_program(void);
 
 int main(int argc, char **argv)
 {
-	int pid;
-	char * command;
-
-	while ((argc>2) && (argv[1][0] == '-') && (argv[1][2] == '\0')) {
-		switch(argv[1][1]) {
-			case 'd':	opt_d++;
-					break;
-			case 'o':	output = fopen(argv[2], "w");
-					if (!output) {
-						fprintf(stderr, "Can't open %s for output: %s\n", argv[2], sys_errlist[errno]);
-						exit(1);
-					}
-					argc--; argv++;
-					break;
-			case 'i':	opt_i++;
-					break;
-			case 'S':	opt_S++;
-					break;
-			default:	fprintf(stderr, "Unknown option '%c'\n", argv[1][1]);
-					usage();
-					exit(1);
-		}
-		argc--; argv++;
-	}
-
-	if (argc<2) {
-		usage();
+	argv = process_options(argc, argv);
+	if (opt_p || opt_f) {
+		fprintf(stderr, "ERROR: Options -p and -f don't work yet\n");
 		exit(1);
 	}
-	command = search_for_command(argv[1]);
-	if (!command) {
-		fprintf(stderr, "%s: command not found\n", argv[1]);
-		exit(1);
+	read_config_file("/etc/ltrace.conf");
+	if (getenv("HOME")) {
+		char path[PATH_MAX];
+		sprintf(path, getenv("HOME"));	/* FIXME: buffer overrun */
+		strcat(path, "/.ltrace.conf");
+		read_config_file(path);
 	}
-	if (!read_elf(command)) {
-		fprintf(stderr, "%s: Not dynamically linked\n", command);
-		exit(1);
-	}
-
-	if (opt_d>0) {
-		send_line("Reading config file(s)...");
-	}
-	read_config_file("/etc/ltrace.cfg");
-	read_config_file(".ltracerc");
-
-	pid = execute_process(command, argv+1);
-	if (opt_d>0) {
-		send_line("pid %u launched", pid);
-	}
-
+	execute_program(open_program(), argv);
 	while(1) {
-		wait_for_child();
+		process_event(wait_for_something());
+	}
+}
+
+static struct process * open_program(void)
+{
+	list_of_processes = malloc(sizeof(struct process));
+	if (!list_of_processes) {
+		perror("malloc");
+		exit(1);
+	}
+	list_of_processes->filename = command;
+	list_of_processes->pid = 0;
+	list_of_processes->breakpoints_enabled = -1;
+	list_of_processes->current_syscall = -1;
+	list_of_processes->current_symbol = NULL;
+	list_of_processes->breakpoint_being_enabled = NULL;
+	list_of_processes->next = NULL;
+	if (opt_L) {
+		list_of_processes->list_of_symbols = read_elf(command);
+	} else {
+		list_of_processes->list_of_symbols = NULL;
 	}
 
-	exit(0);
+	return list_of_processes;
 }
diff --git a/ltrace.h b/ltrace.h
index 3dde957..54a5ee2 100644
--- a/ltrace.h
+++ b/ltrace.h
@@ -1,7 +1,135 @@
+#ifndef _HCK_LTRACE_H
+#define _HCK_LTRACE_H
+
+#include <sys/types.h>
 #include <stdio.h>
 
-extern FILE * output;
+#include "defs.h"
 
-extern int opt_d;
-extern int opt_i;
-extern int opt_S;
+/* BREAKPOINT_LENGTH is defined in "sysdep.h" */
+#include "sysdep.h"
+
+extern char * command;
+
+struct breakpoint {
+	void * addr;
+	unsigned char orig_value[BREAKPOINT_LENGTH];
+	int enabled;
+};
+
+enum param_type {
+	LT_PT_UNKNOWN=-1,
+	LT_PT_VOID,
+	LT_PT_INT,
+	LT_PT_UINT,
+	LT_PT_OCTAL,
+	LT_PT_CHAR,
+	LT_PT_ADDR,
+	LT_PT_FILE,
+	LT_PT_FORMAT,		/* printf-like format */
+	LT_PT_STRING,
+	LT_PT_STRING0,		/* stringN: string up to (arg N) bytes */
+	LT_PT_STRING1,
+	LT_PT_STRING2,
+	LT_PT_STRING3
+};
+
+enum tof {
+	LT_TOF_NONE,
+	LT_TOF_FUNCTION,	/* A real library function */
+	LT_TOF_SYSCALL		/* A syscall */
+};
+
+struct function {
+	const char * name;
+	enum param_type return_type;
+	int num_params;
+	enum param_type param_types[MAX_ARGS];
+	int params_right;
+	struct function * next;
+};
+
+extern struct function * list_of_functions;
+
+struct library_symbol {
+	char * name;
+	struct breakpoint brk;
+
+	struct library_symbol * next;
+};
+
+struct process {
+	char * filename;
+	pid_t pid;
+	int breakpoints_enabled;	/* -1:not enabled yet, 0:disabled, 1:enabled */
+
+	int current_syscall;			/* -1 for none */
+	struct library_symbol * current_symbol;	/* NULL for none */
+
+	struct breakpoint return_value;
+	struct library_symbol * list_of_symbols;
+
+	/* Arch-dependent: */
+	void * instruction_pointer;
+	void * stack_pointer;		/* To get return addr, args... */
+	void * return_addr;
+	struct breakpoint * breakpoint_being_enabled;
+
+	/* output: */
+	enum tof type_being_displayed;
+
+	struct process * next;
+};
+
+struct event {
+	struct process *proc;
+	enum {
+		LT_EV_UNKNOWN,
+		LT_EV_NONE,
+		LT_EV_SIGNAL,
+		LT_EV_EXIT,
+		LT_EV_EXIT_SIGNAL,
+		LT_EV_SYSCALL,
+		LT_EV_SYSRET,
+		LT_EV_BREAKPOINT
+	} thing;
+	union {
+		int ret_val;		/* _EV_EXIT */
+		int signum;		/* _EV_SIGNAL, _EV_EXIT_SIGNAL */
+		int sysnum;		/* _EV_SYSCALL, _EV_SYSRET */
+		void * brk_addr;	/* _EV_BREAKPOINT */
+	} e_un;
+};
+
+extern struct process * list_of_processes;
+
+extern void * instruction_pointer;
+
+struct event * wait_for_something(void);
+void process_event(struct event * event);
+void execute_program(struct process *, char **);
+int display_arg(enum tof type, struct process * proc, int arg_num, enum param_type rt);
+void enable_all_breakpoints(struct process * proc);
+void disable_all_breakpoints(struct process * proc);
+
+/* Arch-dependent stuff: */
+extern void trace_me(void);
+extern void * get_instruction_pointer(int pid);
+extern void * get_stack_pointer(int pid);
+extern void * get_return_addr(int pid, void * stack_pointer);
+extern void insert_breakpoint(int pid, struct breakpoint * sbp);
+extern void delete_breakpoint(int pid, struct breakpoint * sbp);
+extern int child_p(int sysnum);
+extern int syscall_p(pid_t pid, int status);
+extern void continue_process(pid_t pid);
+extern void continue_after_signal(pid_t pid, int signum);
+extern void continue_after_breakpoint(struct process * proc, struct breakpoint * sbp, int delete_it);
+extern void continue_enabling_breakpoint(pid_t pid, struct breakpoint * sbp);
+extern long gimme_arg(enum tof type, struct process * proc, int arg_num);
+extern int umovestr(struct process * proc, void * addr, int len, void * laddr);
+#if 0	/* not yet */
+extern int umoven(struct process * proc, void * addr, int len, void * laddr);
+#endif
+
+
+#endif
diff --git a/options.c b/options.c
new file mode 100644
index 0000000..f5b8874
--- /dev/null
+++ b/options.c
@@ -0,0 +1,118 @@
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <limits.h>
+
+#include "ltrace.h"
+#include "options.h"
+#include "defs.h"
+
+FILE * output;
+int opt_a = DEFAULT_ACOLUMN;	/* default alignment column for results */
+int opt_d = 0;			/* debug */
+int opt_i = 0;			/* instruction pointer */
+int opt_s = DEFAULT_STRLEN;	/* default maximum # of bytes printed in strings */
+int opt_S = 0;			/* display syscalls */
+int opt_L = 1;			/* display library calls */
+int opt_f = 0;			/* trace child processes as they are created */
+
+/* List of pids given to option -p: */
+struct opt_p_t * opt_p = NULL;	/* attach to process with a given pid */
+
+static void usage(void)
+{
+	fprintf(stderr, "Usage: ltrace [-dfiLS] [-a column] [-s strlen] [-o filename]\n"
+			"              [-p pid] ... [command [arg ...]]\n\n");
+}
+
+static char * search_for_command(char * filename)
+{
+	static char pathname[PATH_MAX];
+	char *path;
+	int m, n;
+
+	if (strchr(filename, '/')) {
+		return filename;
+	}
+	for (path = getenv("PATH"); path && *path; path += m) {
+		if (strchr(path, ':')) {
+			n = strchr(path, ':') - path;
+			m = n + 1;
+		} else {
+			m = n = strlen(path);
+		}
+		strncpy(pathname, path, n);
+		if (n && pathname[n - 1] != '/') {
+			pathname[n++] = '/';
+		}
+		strcpy(pathname + n, filename);
+		if (!access(pathname, X_OK)) {
+			return pathname;
+		}
+	}
+	return filename;
+}
+
+char ** process_options(int argc, char **argv)
+{
+	char *nextchar = NULL;
+
+	output = stderr;
+
+	while(1) {
+		if (!nextchar || !(*nextchar)) {
+			if (!argv[1] || argv[1][0] != '-' || !argv[1][1]) {
+				break;
+			}
+			nextchar = &argv[1][1];
+			argc--; argv++;
+		}
+		switch (*nextchar++) {
+			case 'a':	opt_a = atoi(argv[1]);
+					argc--; argv++;
+					break;
+			case 'd':	opt_d++;
+					break;
+			case 'o':	output = fopen(argv[1], "w");
+					if (!output) {
+						fprintf(stderr, "Can't open %s for output: %s\n", argv[1], strerror(errno));
+						exit(1);
+					}
+					argc--; argv++;
+					break;
+			case 'i':	opt_i++;
+					break;
+			case 's':	opt_s = atoi(argv[1]);
+					argc--; argv++;
+					break;
+			case 'L':	opt_L = 0;
+					break;
+			case 'S':	opt_S = 1;
+					break;
+			case 'f':	opt_f = 1;
+					break;
+			case 'p':
+				{
+					struct opt_p_t * tmp = malloc(sizeof(struct opt_p_t));
+					if (!tmp) {
+						perror("malloc");
+						exit(1);
+					}
+					tmp->pid = atoi(argv[1]);
+					argc--; argv++;
+					break;
+				}
+			default:	fprintf(stderr, "Unknown option '%c'\n", *(nextchar-1));
+					usage();
+					exit(1);
+		}
+	}
+
+	if (argc<2) {
+		usage();
+		exit(1);
+	}
+	command = search_for_command(argv[1]);
+	return &argv[1];
+}
diff --git a/options.h b/options.h
new file mode 100644
index 0000000..311a13b
--- /dev/null
+++ b/options.h
@@ -0,0 +1,19 @@
+#include <stdio.h>
+
+extern FILE * output;
+extern int opt_a;	/* default alignment column for results */
+extern int opt_d;	/* debug */
+extern int opt_i;	/* instruction pointer */
+extern int opt_s;	/* default maximum # of bytes printed in strings */
+extern int opt_L;	/* display library calls */
+extern int opt_S;	/* display system calls */
+extern int opt_f;	/* trace child processes */
+
+struct opt_p_t {
+	pid_t pid;
+	struct opt_p_t * next;
+};
+
+extern struct opt_p_t * opt_p;	/* attach to process with a given pid */
+
+extern char ** process_options(int argc, char **argv);
diff --git a/output.c b/output.c
index 142b725..7672c1a 100644
--- a/output.c
+++ b/output.c
@@ -2,56 +2,165 @@
 #include <stdarg.h>
 
 #include "ltrace.h"
-#include "process.h"
+#include "options.h"
+#include "output.h"
 
-static int new_line=1;
+static pid_t current_pid = 0;
+static int current_column = 0;
 
-void send_left(const char * fmt, ...)
+static void begin_of_line(enum tof type, struct process * proc)
 {
-	va_list args;
-
-	va_start(args, fmt);
-	if (opt_i) {
-		fprintf(output, "[%08x] ", instruction_pointer);
+	current_column = 0;
+	if (!proc) {
+		return;
 	}
-	vfprintf(output, fmt, args);
-	va_end(args);
-	new_line=0;
+	if (list_of_processes && list_of_processes->next) {
+		current_column += fprintf(output, "[pid %d] ", proc->pid);
+	}
+	if (opt_i) {
+		if (type==LT_TOF_FUNCTION) {
+			current_column += fprintf(output, "[%08x] ",
+				(unsigned)proc->return_addr);
+		} else {
+			current_column += fprintf(output, "[%08x] ",
+				(unsigned)proc->instruction_pointer);
+		}
+	}
 }
 
-void send_right(const char * fmt, ...)
+static struct function * name2func(char * name)
+{
+	struct function * tmp;
+
+	tmp = list_of_functions;
+	while(tmp) {
+		if (!strcmp(tmp->name, name)) {
+			return tmp;
+		}
+		tmp = tmp->next;
+	}
+	return NULL;
+}
+
+void output_line(struct process * proc, char *fmt, ...)
 {
 	va_list args;
 
-	if (new_line==0) {
-		va_start(args, fmt);
-		vfprintf(output, fmt, args);
+	if (current_pid) {
+		fprintf(output, " <unfinished ...>\n");
+	}
+	begin_of_line(LT_TOF_NONE, proc);
+
+        va_start(args, fmt);
+        vfprintf(output, fmt, args);
+        fprintf(output, "\n");
+        va_end(args);
+	current_pid=0;
+	current_column=0;
+}
+
+static void tabto(int col)
+{
+	if (current_column < col) {
+		fprintf(output, "%*s", col-current_column, "");
+	}
+}
+
+void output_left(enum tof type, struct process * proc, char * function_name)
+{
+	struct function * func;
+
+	if (current_pid) {
+#if 1						/* ugly hack :) */
+		if (current_pid == proc->pid
+			&& proc->type_being_displayed == LT_TOF_FUNCTION
+			&& proc->type_being_displayed == type) {
+				tabto(opt_a);
+				fprintf(output, "= ???\n");
+		} else
+#endif
+			fprintf(output, " <unfinished ...>\n");
+		current_pid=0;
+		current_column=0;
+	}
+	current_pid=proc->pid;
+	proc->type_being_displayed = type;
+	begin_of_line(type, proc);
+	current_column += fprintf(output, "%s(", function_name);
+
+	func = name2func(function_name);
+	if (!func) {
+		int i;
+		for(i=0; i<4; i++) {
+			current_column += display_arg(type, proc, i, LT_PT_UNKNOWN);
+			current_column += fprintf(output, ", ");
+		}
+		current_column += display_arg(type, proc, 4, LT_PT_UNKNOWN);
+		return;
+	} else {
+		int i;
+		for(i=0; i< func->num_params - func->params_right - 1; i++) {
+			current_column += display_arg(type, proc, i, func->param_types[i]);
+			current_column += fprintf(output, ", ");
+		}
+		if (func->num_params>func->params_right) {
+			current_column += display_arg(type, proc, i, func->param_types[i]);
+			if (func->params_right) {
+				current_column += fprintf(output, ", ");
+			}
+		}
+		if (!func->params_right && func->return_type == LT_PT_VOID) {
+			current_column += fprintf(output, ") ");
+			tabto(opt_a);
+			fprintf(output, "= <void>\n");
+			current_pid = 0;
+			current_column = 0;
+		}
+	}
+}
+
+void output_right(enum tof type, struct process * proc, char * function_name)
+{
+	struct function * func = name2func(function_name);
+
+	if (func && func->params_right==0 && func->return_type == LT_PT_VOID) {
+		return;
+	}
+
+	if (current_pid && current_pid!=proc->pid) {
+		fprintf(output, " <unfinished ...>\n");
+		begin_of_line(type, proc);
+		current_column += fprintf(output, "<... %s resumed> ", function_name);
+	} else if (!current_pid) {
+		begin_of_line(type, proc);
+		current_column += fprintf(output, "<... %s resumed> ", function_name);
+	}
+
+	if (!func) {
+		current_column += fprintf(output, ") ");
+		tabto(opt_a);
+		fprintf(output, "= ");
+		display_arg(type, proc, -1, LT_PT_UNKNOWN);
 		fprintf(output, "\n");
-		va_end(args);
+	} else {
+		int i;
+		for(i=func->num_params-func->params_right; i<func->num_params-1; i++) {
+			current_column += display_arg(type, proc, i, func->param_types[i]);
+			current_column += fprintf(output, ", ");
+		}
+		if (func->params_right) {
+			current_column += display_arg(type, proc, i, func->param_types[i]);
+		}
+		current_column += fprintf(output, ") ");
+			tabto(opt_a);
+			fprintf(output, "= ");
+		if (func->return_type == LT_PT_VOID) {
+			fprintf(output, "<void>");
+		} else {
+			display_arg(type, proc, -1, func->return_type);
+		}
+		fprintf(output, "\n");
 	}
-	new_line=1;
-}
-
-void send_line(const char * fmt, ...)
-{
-	va_list args;
-
-	va_start(args, fmt);
-	if (opt_i) {
-		fprintf(output, "[%08x] ", instruction_pointer);
-	}
-	vfprintf(output, fmt, args);
-	fprintf(output, "\n");
-	va_end(args);
-	new_line=1;
-}
-
-void print_libcall(const char name, int pid, int esp)
-{
-	fprintf(output, "libcall: %s\n", name);
-}
-
-void print_libret(const char name, int pid, int esp)
-{
-	fprintf(output, "libret: %s\n", name);
+	current_pid=0;
+	current_column=0;
 }
diff --git a/output.h b/output.h
index fe83523..1ffe095 100644
--- a/output.h
+++ b/output.h
@@ -1,3 +1,9 @@
-void send_left(const char * fmt, ...);
-void send_right(const char * fmt, ...);
-void send_line(const char * fmt, ...);
+#include <sys/types.h>
+
+#include "ltrace.h"
+
+void output_line(struct process * proc, char *fmt, ...);
+
+void output_left(enum tof type, struct process * proc, char * function_name);
+void output_right(enum tof type, struct process * proc, char * function_name);
+
diff --git a/process.c b/process.c
deleted file mode 100644
index 2852310..0000000
--- a/process.c
+++ /dev/null
@@ -1,216 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <errno.h>
-#include <signal.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/resource.h>
-#include <sys/wait.h>
-
-#include <asm/unistd.h>
-
-#include "i386.h"
-#include "ltrace.h"
-#include "process.h"
-#include "symbols.h"
-#include "functions.h"
-#include "syscall.h"
-#include "signal.h"
-#include "output.h"
-
-struct process * list_of_processes = NULL;
-
-unsigned int instruction_pointer;
-
-static void detach_process(int pid);
-static struct process * pid2proc(int pid);
-static void process_child(struct process * current_process);
-
-int execute_process(const char * file, char * const argv[])
-{
-	struct process * tmp;
-	int pid = fork();
-
-	if (pid<0) {
-		perror("fork");
-		exit(1);
-	} else if (!pid) {
-		trace_me();
-		execvp(file, argv);
-		fprintf(stderr, "Can't execute \"%s\": %s\n", argv[1], sys_errlist[errno]);
-		exit(1);
-	}
-
-	tmp = (struct process *)malloc(sizeof(struct process));
-	tmp->pid = pid;
-	tmp->breakpoints_enabled = 0;
-	proc_arch_init(&tmp->proc_arch);
-	tmp->within_function = 0;
-	tmp->next = list_of_processes;
-	list_of_processes = tmp;
-	
-	return pid;
-}
-
-static void detach_process(int pid)
-{
-	struct process *tmp, *tmp2;
-
-	if (list_of_processes && (pid == list_of_processes->pid)) {
-		tmp2 = list_of_processes->next;
-		free(list_of_processes);
-		list_of_processes = tmp2;
-	} else {
-		tmp = list_of_processes;
-		while(tmp && tmp->next) {
-			if (pid == tmp->next->pid) {
-				tmp2 = tmp->next->next;
-				free(tmp->next);
-				tmp->next = tmp2;
-			}
-			tmp = tmp->next;
-		}
-	}
-	if (!kill(pid,0)) {
-		disable_all_breakpoints(pid);
-		untrace_pid(pid);
-	}
-}
-
-static struct process * pid2proc(int pid)
-{
-	struct process * tmp;
-
-	tmp = list_of_processes;
-	while(tmp) {
-		if (pid == tmp->pid) {
-			return tmp;
-		}
-		tmp = tmp->next;
-	}
-	return NULL;
-}
-
-void wait_for_child(void)
-{
-	int pid;
-	int status;
-	struct process * current_process;
-
-	pid = wait4(-1, &status, 0, NULL);
-	if (pid==-1) {
-		if (errno == ECHILD) {
-			if (opt_d>0) {
-				send_line("No more children");
-			}
-			exit(0);
-		}
-		perror("wait4");
-		exit(1);
-	}
-	current_process = pid2proc(pid);
-	if (!current_process) {
-		fprintf(stderr, "wrong pid %d ???\n", pid);
-		exit(1);
-	}
-	if (!current_process->breakpoints_enabled) {
-		if (opt_d>0) {
-			send_line("Enabling breakpoints for pid %d...", pid);
-		}
-		enable_all_breakpoints(pid);
-		current_process->breakpoints_enabled=1;
-	}
-	if (WIFEXITED(status)) {
-		send_line("pid %u exited", pid);
-		detach_process(pid);
-		return;
-	}
-	if (WIFSIGNALED(status)) {
-		send_line("--- %s (%s) ---", signal_name[WSTOPSIG(status)], strsignal(WSTOPSIG(status)));
-		send_line("+++ killed by %s +++", signal_name[WSTOPSIG(status)]);
-		detach_process(pid);
-		return;
-	}
-	if (!WIFSTOPPED(status)) {
-		send_line("pid %u ???", pid);
-		exit(1);
-	}
-	if (WSTOPSIG(status) != SIGTRAP) {
-		send_line("--- %s (%s) ---", signal_name[WSTOPSIG(status)], strsignal(WSTOPSIG(status)));
-		continue_process(pid, WSTOPSIG(status));
-		return;
-	}
-	process_child(current_process);
-}
-
-static void process_child(struct process * current_process)
-{
-	int pid;
-	unsigned long eip;
-	int esp;
-	int function_seen;
-	int status;
-	struct library_symbol * tmp = NULL;
-
-	pid = current_process->pid;
-	eip = get_eip(pid);
-	instruction_pointer = eip;
-
-	switch (type_of_stop(current_process->pid, &current_process->proc_arch, &status)) {
-		case PROC_SYSCALL:
-			if (status==__NR_fork) {
-				disable_all_breakpoints(pid);
-			}
-			if (opt_S) {
-				send_line("SYSCALL: %s()", syscall_list[status]);
-			}
-			continue_process(pid, 0);
-			return;
-		case PROC_SYSRET:
-			if (status==__NR_fork) {
-				enable_all_breakpoints(pid);
-			}
-			if (opt_S && (opt_d>0)) {
-				send_line("SYSRET:  %u", status);
-			}
-			continue_process(pid, 0);
-			return;
-		case PROC_BREAKPOINT:
-		default:
-	}
-	/* pid is breakpointed... */
-	/* TODO: I could be here after a PTRACE_SINGLESTEP ... */
-	esp = get_esp(pid);
-	instruction_pointer = get_return(pid, esp);
-	tmp = library_symbols;
-	function_seen = 0;
-	if (eip == current_process->return_value.addr) {
-		function_seen = 1;
-#if 0
-		send_line("return");
-		print_libret(tmp->name, pid, esp);
-#endif
-		continue_after_breakpoint(pid, &current_process->return_value, 1);
-	} else while(tmp) {
-		if (eip == tmp->sbp.addr) {
-			function_seen = 1;
-			if (current_process->within_function) {
-				delete_breakpoint(pid, &current_process->return_value);
-			}
-			current_process->return_value.addr = instruction_pointer;
-			insert_breakpoint(pid, &current_process->return_value);
-			current_process->within_function=1;
-#if 0
-			print_libcall(tmp->name, pid, esp);
-#endif
-			continue_after_breakpoint(pid, &tmp->sbp, 0);
-			break;
-		}
-		tmp = tmp->next;
-	}
-	if (!function_seen) {
-		send_line("pid %u stopped; continuing it...", pid);
-		continue_process(pid, 0);
-	}
-}
diff --git a/process.h b/process.h
deleted file mode 100644
index 568f61d..0000000
--- a/process.h
+++ /dev/null
@@ -1,39 +0,0 @@
-#ifndef _LTRACE_PROCESS_H
-#define _LTRACE_PROCESS_H
-
-#include "i386.h"
-
-/* not ready yet */
-#if 0
-struct symbols_from_filename {
-	char * filename;
-	struct library_symbol * list_of_symbols;
-}
-
-struct library_symbol {
-	char * name;
-	unsigned long addr;
-	unsigned long return_addr;
-	unsigned char old_value[BREAKPOINT_LENGTH];
-	struct library_symbol * next;
-};
-#endif
-
-struct process {
-	char * filename;		/* from execve() (TODO) */
-	int pid;
-	int breakpoints_enabled;
-	int within_function;
-	struct breakpoint return_value;	/* if within a function */
-	struct proc_arch proc_arch;
-	struct process * next;
-};
-
-extern struct process * list_of_processes;
-
-extern unsigned int instruction_pointer;
-
-int execute_process(const char * file, char * const argv[]);
-void wait_for_child(void);
-
-#endif
diff --git a/process_event.c b/process_event.c
new file mode 100644
index 0000000..481f1bc
--- /dev/null
+++ b/process_event.c
@@ -0,0 +1,165 @@
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <string.h>
+
+#include "ltrace.h"
+#include "output.h"
+#include "options.h"
+
+static void process_signal(struct event * event);
+static void process_exit(struct event * event);
+static void process_exit_signal(struct event * event);
+static void process_syscall(struct event * event);
+static void process_sysret(struct event * event);
+static void process_breakpoint(struct event * event);
+
+void process_event(struct event * event)
+{
+	switch (event->thing) {
+		case LT_EV_NONE:
+			return;
+		case LT_EV_SIGNAL:
+			process_signal(event);
+			return;
+		case LT_EV_EXIT:
+			process_exit(event);
+			return;
+		case LT_EV_EXIT_SIGNAL:
+			process_exit_signal(event);
+			return;
+		case LT_EV_SYSCALL:
+			process_syscall(event);
+			return;
+		case LT_EV_SYSRET:
+			process_sysret(event);
+			return;
+		case LT_EV_BREAKPOINT:
+			process_breakpoint(event);
+			return;
+		default:
+			fprintf(stderr, "Error! unknown event?\n");
+			exit(1);
+	}
+}
+
+static char * shortsignal(int signum)
+{
+	static char * signalent0[] = {
+	#include "signalent.h"
+	};
+	int nsignals0 = sizeof signalent0 / sizeof signalent0[0];
+
+	if (signum<0 || signum>nsignals0) {
+		return "UNKNOWN_SIGNAL";
+	} else {
+		return signalent0[signum];
+	}
+}
+
+static char * sysname(int sysnum)
+{
+	static char result[128];
+	static char * syscalent0[] = {
+	#include "syscallent.h"
+	};
+	int nsyscals0 = sizeof syscalent0 / sizeof syscalent0[0];
+
+	if (sysnum<0 || sysnum>nsyscals0) {
+		sprintf(result, "SYS_%d", sysnum);
+		return result;
+	} else {
+		sprintf(result, "SYS_%s", syscalent0[sysnum]);
+		return result;
+	}
+}
+
+static void process_signal(struct event * event)
+{
+	output_line(event->proc, "--- %s (%s) ---",
+		shortsignal(event->e_un.signum), strsignal(event->e_un.signum));
+	continue_after_signal(event->proc->pid, event->e_un.signum);
+}
+
+static void process_exit(struct event * event)
+{
+	output_line(event->proc, "+++ exited (status %d) +++",
+		event->e_un.ret_val);
+}
+
+static void process_exit_signal(struct event * event)
+{
+	output_line(event->proc, "+++ killed by %s +++",
+		shortsignal(event->e_un.signum));
+}
+
+static void process_syscall(struct event * event)
+{
+	event->proc->current_syscall = event->e_un.sysnum;
+	if (opt_S) {
+		output_left(LT_TOF_SYSCALL, event->proc, sysname(event->e_un.sysnum));
+	}
+	if (child_p(event->e_un.sysnum)) {
+		disable_all_breakpoints(event->proc);
+		if (event->proc->current_symbol) {
+			delete_breakpoint(event->proc->pid, &event->proc->return_value);
+		}
+	}
+	continue_process(event->proc->pid);
+}
+
+static void process_sysret(struct event * event)
+{
+	if (opt_S) {
+		output_right(LT_TOF_SYSCALL, event->proc, sysname(event->e_un.sysnum));
+	}
+	if (child_p(event->e_un.sysnum)) {
+		enable_all_breakpoints(event->proc);
+		if (event->proc->current_symbol) {
+			insert_breakpoint(event->proc->pid, &event->proc->return_value);
+		}
+		if (opt_f) {
+			fprintf(stderr, "ERROR: Option `-f' doesn't work yet\n");
+			exit(1);
+		}
+	}
+	event->proc->current_syscall = -1;
+	continue_process(event->proc->pid);
+}
+
+static void process_breakpoint(struct event * event)
+{
+	struct library_symbol * tmp;
+
+	if (event->proc->breakpoint_being_enabled) {
+		continue_enabling_breakpoint(event->proc->pid, event->proc->breakpoint_being_enabled);
+		event->proc->breakpoint_being_enabled = NULL;
+		return;
+	}
+	if (event->proc->current_symbol && event->e_un.brk_addr == event->proc->return_value.addr) {
+		output_right(LT_TOF_FUNCTION, event->proc, event->proc->current_symbol->name);
+		continue_after_breakpoint(event->proc, &event->proc->return_value, 1);
+		event->proc->current_symbol = NULL;
+		return;
+	}
+
+	tmp = event->proc->list_of_symbols;
+	while(tmp) {
+		if (event->e_un.brk_addr == tmp->brk.addr) {
+			if (event->proc->current_symbol) {
+				delete_breakpoint(event->proc->pid, &event->proc->return_value);
+			}
+			event->proc->current_symbol = tmp;
+			event->proc->stack_pointer = get_stack_pointer(event->proc->pid);
+			event->proc->return_addr = get_return_addr(event->proc->pid, event->proc->stack_pointer);
+			output_left(LT_TOF_FUNCTION, event->proc, tmp->name);
+			event->proc->return_value.addr = event->proc->return_addr;
+			insert_breakpoint(event->proc->pid, &event->proc->return_value);
+			continue_after_breakpoint(event->proc, &tmp->brk, 0);
+			return;
+		}
+		tmp = tmp->next;
+	}
+	output_line(event->proc, "breakpointed at 0x%08x (?)",
+		(unsigned)event->e_un.brk_addr);
+	continue_process(event->proc->pid);
+}
diff --git a/signal.c b/signal.c
deleted file mode 100644
index 24b7c8b..0000000
--- a/signal.c
+++ /dev/null
@@ -1,35 +0,0 @@
-char * signal_name[] = { "SIG_0",
-			"SIGHUP",
-			"SIGINT",
-			"SIGQUIT",
-			"SIGKILL",
-			"SIGTRAP",
-			"SIGABRT",
-			"SIGBUS",
-			"SIGFPE",
-			"SIGKILL",
-
-			"SIGUSR1",
-			"SIGSEGV",
-			"SIGUSR2",
-			"SIGPIPE",
-			"SIGALRM",
-			"SIGTERM",
-			"SIGSTKFLT",
-			"SIGCHLD",
-			"SIGCONT",
-			"SIGSTOP",
-			"SIGTSTP",
-			"SIGTTIN",
-			"SIGTTOU",
-			"SIGURG",
-			"SIGXCPU",
-			"SIGXFSZ",
-			"SIGVTALRM",
-			"SIGPROF",
-			"SIGWINCH",
-			"SIGIO",
-			"SIGPWR",
-			"SIGUNUSED"
-};
-
diff --git a/signal.h b/signal.h
deleted file mode 100644
index 0e4a269..0000000
--- a/signal.h
+++ /dev/null
@@ -1 +0,0 @@
-extern char * signal_name[];
diff --git a/symbols.c b/symbols.c
deleted file mode 100644
index be109cb..0000000
--- a/symbols.c
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * This file contains functions related to the library_symbol struct
- */
-
-#include <stdio.h>
-
-#include "symbols.h"
-#include "i386.h"
-
-struct library_symbol * library_symbols = NULL;
-
-void enable_all_breakpoints(int pid)
-{
-	struct library_symbol * tmp = NULL;
-
-	tmp = library_symbols;
-	while(tmp) {
-		insert_breakpoint(pid, &tmp->sbp);
-		tmp = tmp->next;
-	}
-}
-
-void disable_all_breakpoints(int pid)
-{
-	struct library_symbol * tmp = NULL;
-
-	tmp = library_symbols;
-	while(tmp) {
-		delete_breakpoint(pid, &tmp->sbp);
-		tmp = tmp->next;
-	}
-}
-
diff --git a/symbols.h b/symbols.h
deleted file mode 100644
index 55747fa..0000000
--- a/symbols.h
+++ /dev/null
@@ -1,18 +0,0 @@
-#ifndef _LTRACE_SYMBOLS_H
-#define _LTRACE_SYMBOLS_H
-
-#include "i386.h"
-
-struct library_symbol {
-	char * name;
-	struct breakpoint sbp;
-	unsigned long return_addr;
-	struct library_symbol * next;
-};
-
-extern struct library_symbol * library_symbols;
-
-void enable_all_breakpoints(int pid);
-void disable_all_breakpoints(int pid);
-
-#endif
diff --git a/syscall.c b/syscall.c
deleted file mode 100644
index aca9623..0000000
--- a/syscall.c
+++ /dev/null
@@ -1,165 +0,0 @@
-char * syscall_list[] = { "setup",		/* 0 */
-			"exit",
-			"fork",
-			"read",
-			"write",
-			"open",
-			"close",
-			"waitpid",
-			"creat",
-			"link",
-			"unlink",		/* 10 */
-			"execve",
-			"chdir",
-			"time",
-			"mknod",
-			"chmod",
-			"chown",
-			"break",
-			"oldstat",
-			"lseek",
-			"getpid",		/* 20 */
-			"mount",
-			"umount",
-			"setuid",
-			"getuid",
-			"stime",
-			"ptrace",
-			"alarm",
-			"oldfstat",
-			"pause",
-			"utime",		/* 30 */
-			"stty",
-			"gtty",
-			"access",
-			"nice",
-			"ftime",
-			"sync",
-			"kill",
-			"rename",
-			"mkdir",
-			"rmdir",		/* 40 */
-			"dup",
-			"pipe",
-			"times",
-			"prof",
-			"brk",
-			"setgid",
-			"getgid",
-			"signal",
-			"geteuid",
-			"getegid",		/* 50 */
-			"acct",
-			"phys",
-			"lock",
-			"ioctl",
-			"fcntl",
-			"mpx",
-			"setpgid",
-			"ulimit",
-			"oldolduname",
-			"umask",		/* 60 */
-			"chroot",
-			"ustat",
-			"dup2",
-			"getppid",
-			"getpgrp",
-			"setsid",
-			"sigaction",
-			"sgetmask",
-			"ssetmask",
-			"setreuid",		/* 70 */
-			"setregid",
-			"sigsuspend",
-			"sigpending",
-			"sethostname",
-			"setrlimit",
-			"getrlimit",
-			"getrusage",
-			"gettimeofday",
-			"settimeofday",
-			"getgroups",		/* 80 */
-			"setgroups",
-			"select",
-			"symlink",
-			"oldlstat",
-			"readlink",
-			"uselib",
-			"swapon",
-			"reboot",
-			"readdir",
-			"mmap",			/* 90 */
-			"munmap",
-			"truncate",
-			"ftruncate",
-			"fchmod",
-			"fchown",
-			"getpriority",
-			"setpriority",
-			"profil",
-			"statfs",
-			"fstatfs",		/* 100 */
-			"ioperm",
-			"socketcall",
-			"syslog",
-			"setitimer",
-			"getitimer",
-			"stat",
-			"lstat",
-			"fstat",
-			"olduname",
-			"iopl",			/* 110 */
-			"vhangup",
-			"idle",
-			"vm86",
-			"wait4",
-			"swapoff",
-			"sysinfo",
-			"ipc",
-			"fsync",
-			"sigreturn",
-			"clone",		/* 120 */
-			"setdomainname",
-			"uname",
-			"modify_ldt",
-			"adjtimex",
-			"mprotect",
-			"sigprocmask",
-			"create_module",
-			"init_module",
-			"delete_module",
-			"get_kernel_syms",	/* 130 */
-			"quotactl",
-			"getpgid",
-			"fchdir",
-			"bdflush",
-			"sysfs",
-			"personality",
-			"afs_syscall",
-			"setfsuid",
-			"setfsgid",
-			"_llseek",		/* 140 */
-			"getdents",
-			"_newselect",
-			"flock",
-			"msync",
-			"readv",
-			"writev",
-			"getsid",
-			"fdatasync",
-			"_sysctl",
-			"mlock",		/* 150 */
-			"munlock",
-			"mlockall",
-			"munlockall",
-			"sched_setparam",
-			"sched_getparam",
-			"sched_setscheduler",
-			"sched_getscheduler",
-			"sched_yield",
-			"sched_get_priority_max",
-			"sched_get_priority_min",	/* 160 */
-			"sched_rr_get_interval",
-			"nanosleep",
-			"mremap",
-};
diff --git a/syscall.h b/syscall.h
deleted file mode 100644
index 3ca9072..0000000
--- a/syscall.h
+++ /dev/null
@@ -1,2 +0,0 @@
-
-extern char * syscall_list[];
diff --git a/sysdeps/Linux/Makefile b/sysdeps/Linux/Makefile
new file mode 100644
index 0000000..2cfb878
--- /dev/null
+++ b/sysdeps/Linux/Makefile
@@ -0,0 +1,31 @@
+ARCH	:=	$(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/)
+
+CFLAGS	+=	-I$(TOPDIR)/sysdeps/Linux/$(ARCH)
+
+OBJ	=	trace.o
+
+all:		sysdep.h signalent.h syscallent.h ../sysdep.o
+
+sysdep.h:	$(ARCH)/arch.h
+		cat $(ARCH)/arch.h > sysdep.h
+
+signalent.h:
+		cp $(ARCH)/signalent.h signalent.h
+
+syscallent.h:
+		cp $(ARCH)/syscallent.h syscallent.h
+
+../sysdep.o:	os.o $(ARCH)/arch.o
+		$(LD) -r -o ../sysdep.o os.o $(ARCH)/arch.o
+
+os.o:		$(OBJ)
+		$(LD) -r -o os.o $(OBJ)
+
+$(ARCH)/arch.o:	dummy
+		$(MAKE) -C $(ARCH)
+
+clean:
+		$(MAKE) -C $(ARCH) clean
+		rm -f $(OBJ) sysdep.h signalent.h syscallent.h os.o sysdep.o ../sysdep.o
+
+dummy:
diff --git a/sysdeps/Linux/i386/Makefile b/sysdeps/Linux/i386/Makefile
new file mode 100644
index 0000000..2af3c25
--- /dev/null
+++ b/sysdeps/Linux/i386/Makefile
@@ -0,0 +1,10 @@
+OBJ	=	breakpoint.o trace.o regs.o
+
+all:		arch.o
+
+arch.o:		$(OBJ)
+		$(LD) -r -o arch.o $(OBJ)
+
+clean:
+		$(RM) $(OBJ) arch.o
+
diff --git a/sysdeps/Linux/i386/arch.h b/sysdeps/Linux/i386/arch.h
new file mode 100644
index 0000000..adfee31
--- /dev/null
+++ b/sysdeps/Linux/i386/arch.h
@@ -0,0 +1,5 @@
+#include <sys/types.h>
+
+#define BREAKPOINT_VALUE {0xcc}
+#define BREAKPOINT_LENGTH 1
+#define DECR_PC_AFTER_BREAK 1
diff --git a/sysdeps/Linux/i386/breakpoint.c b/sysdeps/Linux/i386/breakpoint.c
new file mode 100644
index 0000000..dfde2ad
--- /dev/null
+++ b/sysdeps/Linux/i386/breakpoint.c
@@ -0,0 +1,23 @@
+#include <sys/ptrace.h>
+#include "ltrace.h"
+
+void insert_breakpoint(int pid, struct breakpoint * sbp)
+{
+	int a;
+
+	a = ptrace(PTRACE_PEEKTEXT, pid, sbp->addr, 0);
+	sbp->orig_value[0] = a & 0xFF;
+	a &= 0xFFFFFF00;
+	a |= 0xCC;
+	ptrace(PTRACE_POKETEXT, pid, sbp->addr, a);
+}
+
+void delete_breakpoint(int pid, struct breakpoint * sbp)
+{
+	int a;
+
+	a = ptrace(PTRACE_PEEKTEXT, pid, sbp->addr, 0);
+	a &= 0xFFFFFF00;
+	a |= sbp->orig_value[0];
+	ptrace(PTRACE_POKETEXT, pid, sbp->addr, a);
+}
diff --git a/sysdeps/Linux/i386/regs.c b/sysdeps/Linux/i386/regs.c
new file mode 100644
index 0000000..fb737d1
--- /dev/null
+++ b/sysdeps/Linux/i386/regs.c
@@ -0,0 +1,18 @@
+#include <sys/types.h>
+#include <sys/ptrace.h>
+
+int get_instruction_pointer(pid_t pid)
+{
+	return ptrace(PTRACE_PEEKUSER, pid, 4*EIP, 0);
+}
+
+int get_stack_pointer(pid_t pid)
+{
+	return ptrace(PTRACE_PEEKUSER, pid, 4*UESP, 0);
+}
+
+int get_return_addr(pid_t pid, void * stack_pointer)
+{
+	return ptrace(PTRACE_PEEKTEXT, pid, stack_pointer, 0);
+}
+
diff --git a/sysdeps/Linux/i386/signalent.h b/sysdeps/Linux/i386/signalent.h
new file mode 100644
index 0000000..e2c1337
--- /dev/null
+++ b/sysdeps/Linux/i386/signalent.h
@@ -0,0 +1,32 @@
+	"SIG_0",	/* 0 */
+	"SIGHUP",	/* 1 */
+	"SIGINT",	/* 2 */
+	"SIGQUIT",	/* 3 */
+	"SIGILL",	/* 4 */
+	"SIGTRAP",	/* 5 */
+	"SIGABRT",	/* 6 */
+	"SIGBUS",	/* 7 */
+	"SIGFPE",	/* 8 */
+	"SIGKILL",	/* 9 */
+	"SIGUSR1",	/* 10 */
+	"SIGSEGV",	/* 11 */
+	"SIGUSR2",	/* 12 */
+	"SIGPIPE",	/* 13 */
+	"SIGALRM",	/* 14 */
+	"SIGTERM",	/* 15 */
+	"SIGSTKFLT",	/* 16 */
+	"SIGCHLD",	/* 17 */
+	"SIGCONT",	/* 18 */
+	"SIGSTOP",	/* 19 */
+	"SIGTSTP",	/* 20 */
+	"SIGTTIN",	/* 21 */
+	"SIGTTOU",	/* 22 */
+	"SIGURG",	/* 23 */
+	"SIGXCPU",	/* 24 */
+	"SIGXFSZ",	/* 25 */
+	"SIGVTALRM",	/* 26 */
+	"SIGPROF",	/* 27 */
+	"SIGWINCH",	/* 28 */
+	"SIGIO",	/* 29 */
+	"SIGPWR",	/* 30 */
+	"SIGUNUSED",	/* 31 */
diff --git a/sysdeps/Linux/i386/syscallent.h b/sysdeps/Linux/i386/syscallent.h
new file mode 100644
index 0000000..36b9021
--- /dev/null
+++ b/sysdeps/Linux/i386/syscallent.h
@@ -0,0 +1,164 @@
+	"setup",		/* 0 */
+	"exit",			/* 1 */
+	"fork",			/* 2 */
+	"read",			/* 3 */
+	"write",		/* 4 */
+	"open",			/* 5 */
+	"close",		/* 6 */
+	"waitpid",		/* 7 */
+	"creat",		/* 8 */
+	"link",			/* 9 */
+	"unlink",		/* 10 */
+	"execve",		/* 11 */
+	"chdir",		/* 12 */
+	"time",			/* 13 */
+	"mknod",		/* 14 */
+	"chmod",		/* 15 */
+	"chown",		/* 16 */
+	"break",		/* 17 */
+	"oldstat",		/* 18 */
+	"lseek",		/* 19 */
+	"getpid",		/* 20 */
+	"mount",		/* 21 */
+	"umount",		/* 22 */
+	"setuid",		/* 23 */
+	"getuid",		/* 24 */
+	"stime",		/* 25 */
+	"ptrace",		/* 26 */
+	"alarm",		/* 27 */
+	"oldfstat",		/* 28 */
+	"pause",		/* 29 */
+	"utime",		/* 30 */
+	"stty",			/* 31 */
+	"gtty",			/* 32 */
+	"access",		/* 33 */
+	"nice",			/* 34 */
+	"ftime",		/* 35 */
+	"sync",			/* 36 */
+	"kill",			/* 37 */
+	"rename",		/* 38 */
+	"mkdir",		/* 39 */
+	"rmdir",		/* 40 */
+	"dup",			/* 41 */
+	"pipe",			/* 42 */
+	"times",		/* 43 */
+	"prof",			/* 44 */
+	"brk",			/* 45 */
+	"setgid",		/* 46 */
+	"getgid",		/* 47 */
+	"signal",		/* 48 */
+	"geteuid",		/* 49 */
+	"getegid",		/* 50 */
+	"acct",			/* 51 */
+	"phys",			/* 52 */
+	"lock",			/* 53 */
+	"ioctl",		/* 54 */
+	"fcntl",		/* 55 */
+	"mpx",			/* 56 */
+	"setpgid",		/* 57 */
+	"ulimit",		/* 58 */
+	"oldolduname",		/* 59 */
+	"umask",		/* 60 */
+	"chroot",		/* 61 */
+	"ustat",		/* 62 */
+	"dup2",			/* 63 */
+	"getppid",		/* 64 */
+	"getpgrp",		/* 65 */
+	"setsid",		/* 66 */
+	"sigaction",		/* 67 */
+	"sgetmask",		/* 68 */
+	"ssetmask",		/* 69 */
+	"setreuid",		/* 70 */
+	"setregid",		/* 71 */
+	"sigsuspend",		/* 72 */
+	"sigpending",		/* 73 */
+	"sethostname",		/* 74 */
+	"setrlimit",		/* 75 */
+	"getrlimit",		/* 76 */
+	"getrusage",		/* 77 */
+	"gettimeofday",		/* 78 */
+	"settimeofday",		/* 79 */
+	"getgroups",		/* 80 */
+	"setgroups",		/* 81 */
+	"select",		/* 82 */
+	"symlink",		/* 83 */
+	"oldlstat",		/* 84 */
+	"readlink",		/* 85 */
+	"uselib",		/* 86 */
+	"swapon",		/* 87 */
+	"reboot",		/* 88 */
+	"readdir",		/* 89 */
+	"mmap",			/* 90 */
+	"munmap",		/* 91 */
+	"truncate",		/* 92 */
+	"ftruncate",		/* 93 */
+	"fchmod",		/* 94 */
+	"fchown",		/* 95 */
+	"getpriority",		/* 96 */
+	"setpriority",		/* 97 */
+	"profil",		/* 98 */
+	"statfs",		/* 99 */
+	"fstatfs",		/* 100 */
+	"ioperm",		/* 101 */
+	"socketcall",		/* 102 */
+	"syslog",		/* 103 */
+	"setitimer",		/* 104 */
+	"getitimer",		/* 105 */
+	"stat",			/* 106 */
+	"lstat",		/* 107 */
+	"fstat",		/* 108 */
+	"olduname",		/* 109 */
+	"iopl",			/* 110 */
+	"vhangup",		/* 111 */
+	"idle",			/* 112 */
+	"vm86",			/* 113 */
+	"wait4",		/* 114 */
+	"swapoff",		/* 115 */
+	"sysinfo",		/* 116 */
+	"ipc",			/* 117 */
+	"fsync",		/* 118 */
+	"sigreturn",		/* 119 */
+	"clone",		/* 120 */
+	"setdomainname",	/* 121 */
+	"uname",		/* 122 */
+	"modify_ldt",		/* 123 */
+	"adjtimex",		/* 124 */
+	"mprotect",		/* 125 */
+	"sigprocmask",		/* 126 */
+	"create_module",	/* 127 */
+	"init_module",		/* 128 */
+	"delete_module",	/* 129 */
+	"get_kernel_syms",	/* 130 */
+	"quotactl",		/* 131 */
+	"getpgid",		/* 132 */
+	"fchdir",		/* 133 */
+	"bdflush",		/* 134 */
+	"sysfs",		/* 135 */
+	"personality",		/* 136 */
+	"afs_syscall",		/* 137 */
+	"setfsuid",		/* 138 */
+	"setfsgid",		/* 139 */
+	"_llseek",		/* 140 */
+	"getdents",		/* 141 */
+	"_newselect",		/* 142 */
+	"flock",		/* 143 */
+	"msync",		/* 144 */
+	"readv",		/* 145 */
+	"writev",		/* 146 */
+	"getsid",		/* 147 */
+	"fdatasync",		/* 148 */
+	"_sysctl",		/* 149 */
+	"mlock",		/* 150 */
+	"munlock",		/* 151 */
+	"mlockall",		/* 152 */
+	"munlockall",		/* 153 */
+	"sched_setparam",	/* 154 */
+	"sched_getparam",	/* 155 */
+	"sched_setscheduler",	/* 156 */
+	"sched_getscheduler",	/* 157 */
+	"sched_yield",		/* 158 */
+	"sched_get_priority_max",/* 159 */
+	"sched_get_priority_min",/* 160 */
+	"sched_rr_get_interval",/* 161 */
+	"nanosleep",		/* 162 */
+	"mremap",		/* 163 */
diff --git a/sysdeps/Linux/i386/trace.c b/sysdeps/Linux/i386/trace.c
new file mode 100644
index 0000000..b08ae44
--- /dev/null
+++ b/sysdeps/Linux/i386/trace.c
@@ -0,0 +1,85 @@
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <sys/ptrace.h>
+
+#include "ltrace.h"
+
+/* Returns syscall number if `pid' stopped because of a syscall.
+ * Returns -1 otherwise
+ */
+int syscall_p(pid_t pid, int status)
+{
+	if (WIFSTOPPED(status) && WSTOPSIG(status)==SIGTRAP) {
+		int tmp = ptrace(PTRACE_PEEKUSER, pid, 4*ORIG_EAX);
+		if (tmp>=0) {
+			return tmp;
+		}
+	}
+	return -1;
+}
+
+void continue_after_breakpoint(struct process *proc, struct breakpoint * sbp, int delete_it)
+{
+	delete_breakpoint(proc->pid, sbp);
+	ptrace(PTRACE_POKEUSER, proc->pid, 4*EIP, sbp->addr);
+	if (delete_it) {
+		continue_process(proc->pid);
+	} else {
+		proc->breakpoint_being_enabled = sbp;
+		ptrace(PTRACE_SINGLESTEP, proc->pid, 0, 0);
+	}
+}
+
+long gimme_arg(enum tof type, struct process * proc, int arg_num)
+{
+	if (arg_num==-1) {		/* return value */
+		return ptrace(PTRACE_PEEKUSER, proc->pid, 4*EAX);
+	}
+
+	if (type==LT_TOF_FUNCTION) {
+		return ptrace(PTRACE_PEEKTEXT, proc->pid, proc->stack_pointer+4*(arg_num+1));
+	} else if (type==LT_TOF_SYSCALL) {
+#if 0
+		switch(arg_num) {
+			case 0:	return ptrace(PTRACE_PEEKUSER, proc->pid, 4*EBX);
+			case 1:	return ptrace(PTRACE_PEEKUSER, proc->pid, 4*ECX);
+			case 2:	return ptrace(PTRACE_PEEKUSER, proc->pid, 4*EDX);
+			case 3:	return ptrace(PTRACE_PEEKUSER, proc->pid, 4*ESI);
+			case 4:	return ptrace(PTRACE_PEEKUSER, proc->pid, 4*EDI);
+			default:
+				fprintf(stderr, "gimme_arg called with wrong arguments\n");
+				exit(2);
+		}
+#else
+		return ptrace(PTRACE_PEEKUSER, proc->pid, 4*arg_num);
+#endif
+	} else {
+		fprintf(stderr, "gimme_arg called with wrong arguments\n");
+		exit(1);
+	}
+
+	return 0;
+}
+
+int umovestr(struct process * proc, void * addr, int len, void * laddr)
+{
+	long a;
+	int i;
+	int offset=0;
+
+	while(offset<len) {
+		a = ptrace(PTRACE_PEEKTEXT, proc->pid, addr+offset, 0);
+		for(i=0; i<sizeof(long); i++) {
+			if (((char*)&a)[i] && offset+i < len) {
+				*(char *)(laddr+offset+i) = ((char*)&a)[i];
+			} else {
+				*(char *)(laddr+offset+i) = '\0';
+				return 0;
+			}
+		}
+		offset += sizeof(long);
+	}
+	*(char *)(laddr+offset) = '\0';
+	return 0;
+}
diff --git a/sysdeps/Linux/sparc/Makefile b/sysdeps/Linux/sparc/Makefile
new file mode 100644
index 0000000..b71ce1f
--- /dev/null
+++ b/sysdeps/Linux/sparc/Makefile
@@ -0,0 +1,9 @@
+OBJ	=	breakpoint.o regs.o trace.o
+
+all:		arch.o
+
+arch.o:		$(OBJ)
+		$(LD) -r -o arch.o $(OBJ)
+
+clean:
+		$(RM) $(OBJ) arch.o
diff --git a/sysdeps/Linux/sparc/arch.h b/sysdeps/Linux/sparc/arch.h
new file mode 100644
index 0000000..83b437d
--- /dev/null
+++ b/sysdeps/Linux/sparc/arch.h
@@ -0,0 +1,6 @@
+#include <sys/types.h>
+
+#define BREAKPOINT_VALUE {0x91, 0xd0, 0x20, 0x01}
+#define BREAKPOINT_LENGTH 4
+#define DECR_PC_AFTER_BREAK 0
+
diff --git a/sysdeps/Linux/sparc/breakpoint.c b/sysdeps/Linux/sparc/breakpoint.c
new file mode 100644
index 0000000..c0a700b
--- /dev/null
+++ b/sysdeps/Linux/sparc/breakpoint.c
@@ -0,0 +1,17 @@
+#include <sys/ptrace.h>
+#include "ltrace.h"
+
+void insert_breakpoint(int pid, struct breakpoint * sbp)
+{
+	unsigned long a;
+
+	a = ptrace(PTRACE_PEEKTEXT, pid, sbp->addr, 0);
+	*(unsigned long *)sbp->orig_value = a;
+	a = ((0x91 * 256 + 0xd0) * 256 + 0x20) * 256 + 0x01;
+	ptrace(PTRACE_POKETEXT, pid, sbp->addr, a);
+}
+
+void delete_breakpoint(int pid, struct breakpoint * sbp)
+{
+	ptrace(PTRACE_POKETEXT, pid, sbp->addr, *(long *)sbp->orig_value);
+}
diff --git a/sysdeps/Linux/sparc/regs.c b/sysdeps/Linux/sparc/regs.c
new file mode 100644
index 0000000..73e9e42
--- /dev/null
+++ b/sysdeps/Linux/sparc/regs.c
@@ -0,0 +1,18 @@
+#include <sys/types.h>
+#include <sys/ptrace.h>
+
+int get_instruction_pointer(pid_t pid)
+{
+	return ptrace(PTRACE_PEEKUSER, pid, PT_PC, 0);
+}
+
+int get_stack_pointer(pid_t pid)
+{
+	return -1;
+}
+
+int get_return_addr(pid_t pid, void * stack_pointer)
+{
+	return -1;
+}
+
diff --git a/sysdeps/Linux/sparc/signalent.h b/sysdeps/Linux/sparc/signalent.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/sysdeps/Linux/sparc/signalent.h
diff --git a/sysdeps/Linux/sparc/syscallent.h b/sysdeps/Linux/sparc/syscallent.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/sysdeps/Linux/sparc/syscallent.h
diff --git a/sysdeps/Linux/sparc/trace.c b/sysdeps/Linux/sparc/trace.c
new file mode 100644
index 0000000..4671877
--- /dev/null
+++ b/sysdeps/Linux/sparc/trace.c
@@ -0,0 +1,66 @@
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <sys/ptrace.h>
+
+#include "ltrace.h"
+
+/* Returns syscall number if `pid' stopped because of a syscall.
+ * Returns -1 otherwise
+ */
+int syscall_p(pid_t pid, int status)
+{
+#if 0
+	if (WIFSTOPPED(status) && WSTOPSIG(status)==SIGTRAP) {
+		int tmp = ptrace(PTRACE_PEEKUSER, pid, 4*ORIG_EAX);
+		if (tmp>=0) {
+			return tmp;
+		}
+	}
+#endif
+	return -1;
+}
+
+void continue_after_breakpoint(struct process *proc, struct breakpoint * sbp, int delete_it)
+{
+	delete_breakpoint(proc->pid, sbp);
+	ptrace(PTRACE_POKEUSER, proc->pid, PT_PC, sbp->addr);
+	if (delete_it) {
+		continue_process(proc->pid);
+	} else {
+		proc->breakpoint_being_enabled = sbp;
+		ptrace(PTRACE_SINGLESTEP, proc->pid, 0, 0);
+	}
+}
+
+long gimme_arg(enum tof type, struct process * proc, int arg_num)
+{
+#if 0
+	if (arg_num==-1) {		/* return value */
+		return ptrace(PTRACE_PEEKUSER, proc->pid, 4*EAX);
+	}
+
+	if (type==LT_TOF_FUNCTION) {
+		return ptrace(PTRACE_PEEKTEXT, proc->pid, proc->stack_pointer+4*(arg_num+1));
+	} else if (type==LT_TOF_SYSCALL) {
+#if 0
+		switch(arg_num) {
+			case 0:	return ptrace(PTRACE_PEEKUSER, proc->pid, 4*EBX);
+			case 1:	return ptrace(PTRACE_PEEKUSER, proc->pid, 4*ECX);
+			case 2:	return ptrace(PTRACE_PEEKUSER, proc->pid, 4*EDX);
+			case 3:	return ptrace(PTRACE_PEEKUSER, proc->pid, 4*ESI);
+			case 4:	return ptrace(PTRACE_PEEKUSER, proc->pid, 4*EDI);
+			default:
+				fprintf(stderr, "gimme_arg called with wrong arguments\n");
+				exit(2);
+		}
+#else
+		return ptrace(PTRACE_PEEKUSER, proc->pid, 4*arg_num);
+#endif
+	} else {
+		fprintf(stderr, "gimme_arg called with wrong arguments\n");
+		exit(1);
+	}
+#endif
+	return 0;
+}
diff --git a/sysdeps/Linux/trace.c b/sysdeps/Linux/trace.c
new file mode 100644
index 0000000..33bf244
--- /dev/null
+++ b/sysdeps/Linux/trace.c
@@ -0,0 +1,48 @@
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/ptrace.h>
+#include <asm/unistd.h>
+
+#include "ltrace.h"
+#include "options.h"
+
+/* Returns 1 if a new child is about to be created
+   (ie, with fork() or clone())
+   Returns 0 otherwise. */
+int child_p(int sysnum)
+{
+	return (sysnum == __NR_fork || sysnum == __NR_clone);
+}
+
+void trace_me(void)
+{
+	if (ptrace(PTRACE_TRACEME, 0, 1, 0)<0) {
+		perror("PTRACE_TRACEME");
+		exit(1);
+	}
+}
+
+void continue_after_signal(pid_t pid, int signum)
+{
+	/* We should always trace syscalls to be able to control fork(), clone(), execve()... */
+#if 0
+	if (opt_S) {
+		ptrace(PTRACE_SYSCALL, pid, 1, signum);
+	} else {
+		ptrace(PTRACE_CONT, pid, 1, signum);
+	}
+#else
+	ptrace(PTRACE_SYSCALL, pid, 1, signum);
+#endif
+}
+
+void continue_process(pid_t pid)
+{
+	continue_after_signal(pid, 0);
+}
+
+void continue_enabling_breakpoint(pid_t pid, struct breakpoint * sbp)
+{
+	insert_breakpoint(pid, sbp);
+	continue_process(pid);
+}
diff --git a/tests/execl b/tests/execl
deleted file mode 100755
index e39f5c6..0000000
--- a/tests/execl
+++ /dev/null
Binary files differ
diff --git a/tests/execl.c b/tests/execl.c
deleted file mode 100644
index 5ed7e19..0000000
--- a/tests/execl.c
+++ /dev/null
@@ -1,4 +0,0 @@
-main()
-{
-	execl("/home/cespedes/debian/hck/ltrace-0.1.2/tests/hello",0);
-}
diff --git a/tests/fork b/tests/fork
deleted file mode 100755
index 9a19d31..0000000
--- a/tests/fork
+++ /dev/null
Binary files differ
diff --git a/tests/fork.c b/tests/fork.c
deleted file mode 100644
index 61b792a..0000000
--- a/tests/fork.c
+++ /dev/null
@@ -1,6 +0,0 @@
-main()
-{
-fork();
-printf("hola\n");
-sleep(1);
-}
diff --git a/tests/hello b/tests/hello
deleted file mode 100755
index a3ead2e..0000000
--- a/tests/hello
+++ /dev/null
Binary files differ
diff --git a/tests/hello.c b/tests/hello.c
deleted file mode 100644
index 499df67..0000000
--- a/tests/hello.c
+++ /dev/null
@@ -1,4 +0,0 @@
-main()
-{
-printf("Hello, world!\n");
-}
diff --git a/tests/int b/tests/int
deleted file mode 100755
index 0802f1f..0000000
--- a/tests/int
+++ /dev/null
Binary files differ
diff --git a/tests/int.c b/tests/int.c
deleted file mode 100644
index 8e8e3a0..0000000
--- a/tests/int.c
+++ /dev/null
@@ -1,4 +0,0 @@
-main()
-{
-__asm__("int $3");
-}
diff --git a/tests/kill b/tests/kill
deleted file mode 100755
index 85ca59f..0000000
--- a/tests/kill
+++ /dev/null
Binary files differ
diff --git a/tests/kill.c b/tests/kill.c
deleted file mode 100644
index 05b57d3..0000000
--- a/tests/kill.c
+++ /dev/null
@@ -1,6 +0,0 @@
-#include <signal.h>
-
-main()
-{
-kill(0,SIGSTOP);
-}
diff --git a/tests/kill.s b/tests/kill.s
deleted file mode 100644
index a0cc8c8..0000000
--- a/tests/kill.s
+++ /dev/null
@@ -1,21 +0,0 @@
-	.file	"kill.c"
-	.version	"01.01"
-gcc2_compiled.:
-.text
-	.align 16
-.globl main
-	.type	 main,@function
-main:
-	pushl %ebp
-	movl %esp,%ebp
-	pushl $19
-	pushl $0
-	call kill
-	addl $8,%esp
-.L4:
-	movl %ebp,%esp
-	popl %ebp
-	ret
-.Lfe1:
-	.size	 main,.Lfe1-main
-	.ident	"GCC: (GNU) 2.7.2.2"
diff --git a/tests/kill2 b/tests/kill2
deleted file mode 100755
index 73f1378..0000000
--- a/tests/kill2
+++ /dev/null
Binary files differ
diff --git a/tests/kill2.o b/tests/kill2.o
deleted file mode 100644
index 1818eea..0000000
--- a/tests/kill2.o
+++ /dev/null
Binary files differ
diff --git a/tests/kill2.s b/tests/kill2.s
deleted file mode 100644
index 445f170..0000000
--- a/tests/kill2.s
+++ /dev/null
@@ -1,27 +0,0 @@
-	.file	"kill.c"
-	.version	"01.01"
-gcc2_compiled.:
-.text
-	.align 16
-.globl main
-	.type	 main,@function
-main:
-	movl $37,%eax
-	movl $0,%ebx
-	movl $19,%ecx
-	int $0x80
-	ret
-
-	pushl %ebp
-	movl %esp,%ebp
-	pushl $19
-	pushl $0
-	call kill
-	addl $8,%esp
-.L4:
-	movl %ebp,%esp
-	popl %ebp
-	ret
-.Lfe1:
-	.size	 main,.Lfe1-main
-	.ident	"GCC: (GNU) 2.7.2.2"
diff --git a/tests/kill3.o b/tests/kill3.o
deleted file mode 100644
index 640af58..0000000
--- a/tests/kill3.o
+++ /dev/null
Binary files differ
diff --git a/tests/kill3.s b/tests/kill3.s
deleted file mode 100644
index 3f780c4..0000000
--- a/tests/kill3.s
+++ /dev/null
@@ -1,29 +0,0 @@
-	.file	"kill.c"
-	.version	"01.01"
-gcc2_compiled.:
-.text
-	.align 16
-.globl main
-	.type	 main,@function
-main:
-	xorl %eax,%eax
-	movb $37,%al
-	xorl %ebx,%ebx
-	xorl %ecx,%ecx
-	movb $19,%ecx
-	int $0x80
-	ret
-
-	pushl %ebp
-	movl %esp,%ebp
-	pushl $19
-	pushl $0
-	call kill
-	addl $8,%esp
-.L4:
-	movl %ebp,%esp
-	popl %ebp
-	ret
-.Lfe1:
-	.size	 main,.Lfe1-main
-	.ident	"GCC: (GNU) 2.7.2.2"
diff --git a/tests/trap b/tests/trap
deleted file mode 100755
index 5530e99..0000000
--- a/tests/trap
+++ /dev/null
Binary files differ
diff --git a/tests/trap.c b/tests/trap.c
deleted file mode 100644
index 8e8e3a0..0000000
--- a/tests/trap.c
+++ /dev/null
@@ -1,4 +0,0 @@
-main()
-{
-__asm__("int $3");
-}
diff --git a/wait_for_something.c b/wait_for_something.c
new file mode 100644
index 0000000..8b0fe1f
--- /dev/null
+++ b/wait_for_something.c
@@ -0,0 +1,96 @@
+#define	_GNU_SOURCE	1
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <signal.h>
+#include <string.h>
+
+#include "ltrace.h"
+#include "options.h"
+#include "output.h"
+
+static struct event event;
+
+/* This should also update `current_process' */
+
+static struct process * pid2proc(int pid);
+
+struct event * wait_for_something(void)
+{
+	pid_t pid;
+	int status;
+	int tmp;
+
+	pid = wait(&status);
+	if (pid==-1) {
+		if (errno==ECHILD) {
+			if (opt_d) {
+				output_line(0, "No more children");
+			}
+			exit(0);
+		}
+		perror("wait");
+		exit(1);
+	}
+	event.proc = pid2proc(pid);
+	if (!event.proc) {
+		fprintf(stderr, "signal from wrong pid %u ?!?\n", pid);
+		exit(1);
+	}
+	event.proc->instruction_pointer = get_instruction_pointer(pid);
+	if (opt_d>1) {
+		output_line(0,"signal from pid %u", pid);
+	}
+	if (event.proc->breakpoints_enabled == -1) {
+		if (opt_d>0) {
+			output_line(0,"Enabling breakpoints for pid %u...", pid);
+		}
+		enable_all_breakpoints(event.proc);
+		event.thing = LT_EV_NONE;
+		continue_process(event.proc->pid);
+		return &event;
+	}
+	tmp = syscall_p(pid, status);
+	if (tmp>=0) {
+		event.thing = (event.proc->current_syscall >= 0) ? LT_EV_SYSRET : LT_EV_SYSCALL;
+		event.e_un.sysnum = tmp;
+		return &event;
+	}
+	if (WIFEXITED(status)) {
+		event.thing = LT_EV_EXIT;
+		event.e_un.ret_val = WEXITSTATUS(status);
+		return &event;
+	}
+	if (WIFSIGNALED(status)) {
+		event.thing = LT_EV_EXIT_SIGNAL;
+		event.e_un.signum = WTERMSIG(status);
+		return &event;
+	}
+	if (!WIFSTOPPED(status)) {
+		event.thing = LT_EV_UNKNOWN;
+		return &event;
+	}
+	if (WSTOPSIG(status) != SIGTRAP) {
+		event.thing = LT_EV_SIGNAL;
+		event.e_un.signum = WSTOPSIG(status);
+		return &event;
+	}
+	event.thing = LT_EV_BREAKPOINT;
+	event.e_un.brk_addr = event.proc->instruction_pointer - DECR_PC_AFTER_BREAK;
+	return &event;
+}
+
+static struct process * pid2proc(int pid)
+{
+	struct process * tmp;
+
+	tmp = list_of_processes;
+	while(tmp) {
+		if (pid == tmp->pid) {
+			return tmp;
+		}
+		tmp = tmp->next;
+	}
+	return NULL;
+}
+