aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJuan Cespedes <cespedes@debian.org>1998-03-08 22:31:44 +0100
committerJuan Cespedes <cespedes@debian.org>1998-03-08 22:31:44 +0100
commit5e01f654d83a95f2acffa86df57a4c2db9b0cae9 (patch)
tree52440efff51fc1473c436939f4505225ee7edaeb
parentc40e64afa6a897bb7eb6fd4dc21f622632ae215a (diff)
downloadltrace-5e01f654d83a95f2acffa86df57a4c2db9b0cae9.tar.gz
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)
-rw-r--r--BUGS7
-rw-r--r--COPYING5
-rw-r--r--KK79
-rw-r--r--Makefile26
-rw-r--r--README12
-rw-r--r--THOUGHTS25
-rw-r--r--TODO49
-rw-r--r--all.h135
-rw-r--r--breakpoints.c35
-rw-r--r--config_file.c163
-rw-r--r--config_file.h2
-rw-r--r--debian/changelog22
-rw-r--r--debian/conffiles2
-rw-r--r--debian/control11
-rw-r--r--debian/copyright2
-rwxr-xr-xdebian/rules11
-rw-r--r--defs.h13
-rw-r--r--display_args.c130
-rw-r--r--elf.c45
-rw-r--r--elf.h3
-rw-r--r--etc/ltrace.conf87
-rw-r--r--etc/ltrace.rc37
-rw-r--r--execute_program.c37
-rw-r--r--functions.c182
-rw-r--r--functions.h33
-rw-r--r--i386.c144
-rw-r--r--i386.h35
-rw-r--r--ltrace.127
-rw-r--r--ltrace.c129
-rw-r--r--ltrace.h136
-rw-r--r--options.c118
-rw-r--r--options.h19
-rw-r--r--output.c169
-rw-r--r--output.h12
-rw-r--r--process.c216
-rw-r--r--process.h39
-rw-r--r--process_event.c165
-rw-r--r--signal.c35
-rw-r--r--signal.h1
-rw-r--r--symbols.c33
-rw-r--r--symbols.h18
-rw-r--r--syscall.c165
-rw-r--r--syscall.h2
-rw-r--r--sysdeps/Linux/Makefile31
-rw-r--r--sysdeps/Linux/i386/Makefile10
-rw-r--r--sysdeps/Linux/i386/arch.h5
-rw-r--r--sysdeps/Linux/i386/breakpoint.c23
-rw-r--r--sysdeps/Linux/i386/regs.c18
-rw-r--r--sysdeps/Linux/i386/signalent.h32
-rw-r--r--sysdeps/Linux/i386/syscallent.h164
-rw-r--r--sysdeps/Linux/i386/trace.c85
-rw-r--r--sysdeps/Linux/sparc/Makefile9
-rw-r--r--sysdeps/Linux/sparc/arch.h6
-rw-r--r--sysdeps/Linux/sparc/breakpoint.c17
-rw-r--r--sysdeps/Linux/sparc/regs.c18
-rw-r--r--sysdeps/Linux/sparc/signalent.h0
-rw-r--r--sysdeps/Linux/sparc/syscallent.h0
-rw-r--r--sysdeps/Linux/sparc/trace.c66
-rw-r--r--sysdeps/Linux/trace.c48
-rwxr-xr-xtests/execlbin4213 -> 0 bytes
-rw-r--r--tests/execl.c4
-rwxr-xr-xtests/forkbin4332 -> 0 bytes
-rw-r--r--tests/fork.c6
-rwxr-xr-xtests/hellobin4178 -> 0 bytes
-rw-r--r--tests/hello.c4
-rwxr-xr-xtests/intbin4005 -> 0 bytes
-rw-r--r--tests/int.c4
-rwxr-xr-xtests/killbin4095 -> 0 bytes
-rw-r--r--tests/kill.c6
-rw-r--r--tests/kill.s21
-rwxr-xr-xtests/kill2bin4111 -> 0 bytes
-rw-r--r--tests/kill2.obin820 -> 0 bytes
-rw-r--r--tests/kill2.s27
-rw-r--r--tests/kill3.obin812 -> 0 bytes
-rw-r--r--tests/kill3.s29
-rwxr-xr-xtests/trapbin4004 -> 0 bytes
-rw-r--r--tests/trap.c4
-rw-r--r--wait_for_something.c96
78 files changed, 1934 insertions, 1415 deletions
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 @@ the "copyright" line and a pointer to where the full notice is found.
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 @@ dist: clean
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 @@ calls instead of system calls.
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 @@ Source: ltrace
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 @@ Depends: ${shlibs:Depends}
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 @@ Dynamic Library Tracer ``ltrace''.
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 @@ binary-arch: build
$(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 @@ int read_elf(const char *filename)
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 @@ int read_elf(const char *filename)
}
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 @@ int read_elf(const char *filename)
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 @@ int read_elf(const char *filename)
}
}
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 @@ int read_elf(const char *filename)
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 @@ ltrace \- A library call tracer
.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 @@ Its use is very similar to
.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 @@ If you like to report a bug, send a notice to the author, or use the
.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 struct process * open_program(void);
-static char * search_for_command(char * filename)
+int main(int argc, char **argv)
{
- static char pathname[MAXPATHLEN];
- char *path;
- int m, n;
-
- if (strchr(filename, '/')) {
- return filename;
+ argv = process_options(argc, argv);
+ if (opt_p || opt_f) {
+ fprintf(stderr, "ERROR: Options -p and -f don't work yet\n");
+ exit(1);
}
- 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;
- }
+ 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 (access(pathname, X_OK)) {
- return NULL;
- } else {
- return pathname;
+ execute_program(open_program(), argv);
+ while(1) {
+ process_event(wait_for_something());
}
}
-int main(int argc, char **argv)
+static struct process * open_program(void)
{
- 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();
- exit(1);
- }
- command = search_for_command(argv[1]);
- if (!command) {
- fprintf(stderr, "%s: command not found\n", argv[1]);
+ list_of_processes = malloc(sizeof(struct process));
+ if (!list_of_processes) {
+ perror("malloc");
exit(1);
}
- 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);
- }
-
- while(1) {
- wait_for_child();
+ 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"
+
+/* 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
+
-extern int opt_d;
-extern int opt_i;
-extern int opt_S;
+#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);
+ current_column = 0;
+ if (!proc) {
+ return;
+ }
+ if (list_of_processes && list_of_processes->next) {
+ current_column += fprintf(output, "[pid %d] ", proc->pid);
+ }
if (opt_i) {
- fprintf(output, "[%08x] ", instruction_pointer);
+ if (type==LT_TOF_FUNCTION) {
+ current_column += fprintf(output, "[%08x] ",
+ (unsigned)proc->return_addr);
+ } else {
+ current_column += fprintf(output, "[%08x] ",
+ (unsigned)proc->instruction_pointer);
+ }
}
- vfprintf(output, fmt, args);
- va_end(args);
- new_line=0;
}
-void send_right(const char * fmt, ...)
+static struct function * name2func(char * name)
{
- va_list args;
+ struct function * tmp;
- if (new_line==0) {
- va_start(args, fmt);
- vfprintf(output, fmt, args);
- fprintf(output, "\n");
- va_end(args);
+ tmp = list_of_functions;
+ while(tmp) {
+ if (!strcmp(tmp->name, name)) {
+ return tmp;
+ }
+ tmp = tmp->next;
}
- new_line=1;
+ return NULL;
}
-void send_line(const char * fmt, ...)
+void output_line(struct process * proc, char *fmt, ...)
{
va_list args;
- va_start(args, fmt);
- if (opt_i) {
- fprintf(output, "[%08x] ", instruction_pointer);
+ 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, "");
}
- vfprintf(output, fmt, args);
- fprintf(output, "\n");
- va_end(args);
- new_line=1;
}
-void print_libcall(const char name, int pid, int esp)
+void output_left(enum tof type, struct process * proc, char * function_name)
{
- fprintf(output, "libcall: %s\n", 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 print_libret(const char name, int pid, int esp)
+void output_right(enum tof type, struct process * proc, char * function_name)
{
- fprintf(output, "libret: %s\n", 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");
+ } 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");
+ }
+ 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;
+}
+