diff options
-rw-r--r-- | Makefile | 10 | ||||
-rw-r--r-- | README | 5 | ||||
-rw-r--r-- | TODO | 55 | ||||
-rw-r--r-- | debian/changelog | 20 | ||||
-rw-r--r-- | debian/copyright | 4 | ||||
-rw-r--r-- | elf.c | 17 | ||||
-rw-r--r-- | i386.c | 31 | ||||
-rw-r--r-- | i386.h | 14 | ||||
-rw-r--r-- | ltrace.1 | 2 | ||||
-rw-r--r-- | ltrace.c | 30 | ||||
-rw-r--r-- | ltrace.h | 3 | ||||
-rw-r--r-- | process.c | 121 | ||||
-rw-r--r-- | process.h | 26 | ||||
-rw-r--r-- | symbols.h | 5 | ||||
-rw-r--r-- | syscall.c | 165 | ||||
-rw-r--r-- | syscall.h | 2 | ||||
-rwxr-xr-x | tests/execl | bin | 4213 -> 4213 bytes | |||
-rw-r--r-- | tests/execl.c | 2 |
18 files changed, 419 insertions, 93 deletions
@@ -1,11 +1,9 @@ CC = gcc CFLAGS = -O2 -g -Wall -OBJ = ltrace.o functions.o elf.o i386.o symbols.o process.o +OBJ = ltrace.o functions.o elf.o i386.o symbols.o process.o syscall.o -all: build - -build: ltrace +all: ltrace ltrace: ltrace.o $(OBJ) @@ -15,8 +13,8 @@ clean: dist: clean ( cd .. ; tar zcvf ltrace-`date +%y%m%d`.tgz ltrace ) -install: build - install -d $(DESTDIR)/usr/bin $(DESTDIR)/usr/doc/ltrace $(DESTDIR)/etc $(DESTDIR)/usr/man/man1 +install: ltrace + install -d $(DESTDIR)/usr/bin $(DESTDIR)/usr/doc/ltrace $(DESTDIR)/usr/man/man1 install -s ltrace $(DESTDIR)/usr/bin install -m 644 README $(DESTDIR)/usr/doc/ltrace install -m 644 ltrace.1 $(DESTDIR)/usr/man/man1 @@ -34,7 +34,7 @@ other i386 based POSIX system, such as Hurd or *BSD. ------- Too many to list here :). If you like to submit a bug report, or a feature request, either do that against the Debian `ltrace' package, -or mail me (Juan Cespedes <cespedes@etsit.upm.es>) +or mail ``Juan Cespedes <cespedes@etsit.upm.es>''. 5. Licence ---------- @@ -52,5 +52,6 @@ or mail me (Juan Cespedes <cespedes@etsit.upm.es>) 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. @@ -1,16 +1,39 @@ -------------------------------------------------------------------------------- -``struct_process'' should also have: - * All the symbols it has breakpointed, and, for each of them: - - its addr - - its return addr, if any - - whether the return addr is breakpointed (ie, if the symbol is ``active'') - - the original value in the addr, and in the return addr, if appropiate - - - * The state of the process: - - uninitialized - - running - - within a given syscall -------------------------------------------------------------------------------- -I should parse a config file (/etc/ltrace.conf & ~/.ltracerc) to -handle different arguments to the library calls -------------------------------------------------------------------------------- +* {enable,disable}_all_breakpoints should be process-dependent + +* All wait4's should be moved to chld_handler(): + + A process may stop because: + - It execve()'d (needs breakpoints to be added) + - 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 + +* ``struct_process'' should also have: + + All the symbols it has breakpointed, and, for each of them: + - its addr + - its return addr, if any + - whether the return addr is breakpointed (ie, if the symbol is ``active'') + - the original value in the addr, and in the return addr, if appropiate + - + + The state of the process: + - uninitialized + - running + - within a given syscall + +* I should parse a config file (/etc/ltrace.conf & ~/.ltracerc) to + handle different arguments to the library calls + +* main() should find the program in the PATH. + +* 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 + +* ltrace should accept '-s' option to trace syscalls, too. + +* All architecture dependent stuff should be moved to ``arch.h'' diff --git a/debian/changelog b/debian/changelog index 2eb56e1..71e9cd9 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,17 @@ +ltrace (0.1.2) experimental; urgency=low + + * Updated ``TODO'' + * Added process.c:execute_process + * Added i386.c:type_of_stop + * Hopefully, system dependent stuff is now only in i386.[ch] and process.[ch] + * `-d' can now be used many times: many levels of debug + * removed breakpoint for children detecting fork()s. + Now, *every* program should work ok + * struct process now also has a field for the process filename + * Added "syscall.c" with a list of system call names in Linux/i386 + + -- Juan Cespedes <cespedes@etsit.upm.es> Sat, 23 Aug 1997 15:00:23 +0200 + ltrace (0.1.1) experimental; urgency=low * Added ``TODO'' @@ -5,9 +19,11 @@ ltrace (0.1.1) experimental; urgency=low * Added ``process.[ch]'': init_sighandler, pid2proc * Removed ``trace.c'' * Added rudimentary support for multiple processes - * Now tracing syscalls (fork() needs a special treatment) + * Now tracing syscalls (fork() needs a special treatment (TODO)) + * Added process.c:detach_process + * Added i386.c:trace_me,untrace_pid - -- Juan Cespedes <cespedes@etsit.upm.es> Fri, 22 Aug 1997 21:01:59 +0200 + -- Juan Cespedes <cespedes@etsit.upm.es> Sat, 23 Aug 1997 02:09:14 +0200 ltrace (0.1.0) experimental; urgency=low diff --git a/debian/copyright b/debian/copyright index 65f1b7a..f4c4cfa 100644 --- a/debian/copyright +++ b/debian/copyright @@ -18,6 +18,6 @@ General Public License for more details. A copy of the GNU General Public License is available as `/usr/doc/copyright/GPL.gz' in the Debian GNU/Linux distribution or on the World Wide Web at `http://www.gnu.org/copyleft/gpl.html'. You can -also obtain it by writing to the Free Software Foundation, Inc., 675 -Mass Ave, Cambridge, MA 02139, USA. +also obtain it by writing to the Free Software Foundation, Inc., +59 Temple Place - Suite 330, Boston, MA 02111-1307, USA @@ -5,17 +5,12 @@ #include <stdio.h> #include <errno.h> #include <stdlib.h> -#include <unistd.h> #include <sys/types.h> -#include <sys/ptrace.h> -#include <sys/resource.h> -#include <sys/wait.h> #include <sys/stat.h> #include <fcntl.h> #include <linux/elf.h> #include <sys/mman.h> #include <string.h> -#include <signal.h> #include "elf.h" #include "ltrace.h" @@ -33,6 +28,10 @@ int read_elf(const char *filename) char * strtab = NULL; u_long symtab_len = 0; + if (opt_d>0) { + fprintf(output, "Reading symbol table from %s...\n", filename); + } + fd = open(filename, O_RDONLY); if (fd==-1) { fprintf(stderr, "Can't open \"%s\": %s\n", filename, sys_errlist[errno]); @@ -70,15 +69,11 @@ int read_elf(const char *filename) } if (shdr->sh_type == SHT_STRTAB) { if (!strtab) { -#if 0 strtab = (char *)(addr + shdr->sh_offset); -#else - strtab = (char *)(addr + shdr->sh_offset); -#endif } } } - if (debug>0) { + if (opt_d>1) { fprintf(output, "symtab: 0x%08x\n", (unsigned)symtab); fprintf(output, "symtab_len: %lu\n", symtab_len); fprintf(output, "strtab: 0x%08x\n", (unsigned)strtab); @@ -98,7 +93,7 @@ int read_elf(const char *filename) library_symbols->addr = ((symtab+i)->st_value); library_symbols->name = strtab+(symtab+i)->st_name; library_symbols->next = tmp; - if (debug>0) { + if (opt_d>1) { fprintf(output, "addr: 0x%08x, symbol: \"%s\"\n", (unsigned)((symtab+i)->st_value), (strtab+(symtab+i)->st_name)); @@ -5,6 +5,7 @@ #include <errno.h> #include <stdio.h> +#include "i386.h" #include "ltrace.h" void insert_breakpoint(int pid, unsigned long addr, unsigned char * value) @@ -110,3 +111,33 @@ void trace_me(void) } } +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(struct process * proc, int *what) +{ + *what = get_orig_eax(proc->pid); + + if (*what!=-1) { + if (proc->syscall_number != *what) { + proc->syscall_number = *what; + return PROC_SYSCALL; + } else { + proc->syscall_number = -1; + return PROC_SYSRET; + } + } + + return PROC_BREAKPOINT; +} @@ -1,3 +1,6 @@ +#ifndef _LTRACE_I386_H +#define _LTRACE_I386_H + #define BREAKPOINT {0xcc} #define BREAKPOINT_LENGTH 1 @@ -10,5 +13,14 @@ 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, unsigned long eip, unsigned char * value, int delete_it); -void trace_me(void); 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 @@ -22,7 +22,7 @@ Its use is very similar to .SH OPTIONS .TP .I \-d -Enable debugging +Increase the debugging level. .TP .I \-o filename Write the trace output to the file @@ -1,18 +1,18 @@ #include <stdio.h> #include <errno.h> #include <unistd.h> -#include <sys/wait.h> -#include <signal.h> #include "elf.h" +#include "i386.h" #include "symbols.h" #include "functions.h" #include "process.h" extern void read_config_file(const char *); -int debug = 0; FILE * output = stderr; +int opt_d = 0; +int opt_i = 0; unsigned long return_addr; unsigned char return_value; @@ -20,7 +20,7 @@ struct library_symbol * current_symbol; static void usage(void) { - fprintf(stderr," Usage: ltrace [-d][-o output] <program> [<arguments>...]\n"); + fprintf(stderr,"Usage: ltrace [-d] [-o filename] command [arg ...]\n\n"); } int main(int argc, char **argv) @@ -29,7 +29,7 @@ int main(int argc, char **argv) while ((argc>2) && (argv[1][0] == '-') && (argv[1][2] == '\0')) { switch(argv[1][1]) { - case 'd': debug++; + case 'd': opt_d++; break; case 'o': output = fopen(argv[2], "w"); if (!output) { @@ -38,6 +38,8 @@ int main(int argc, char **argv) } argc--; argv++; break; + case 'i': opt_i++; + break; default: fprintf(stderr, "Unknown option '%c'\n", argv[1][1]); usage(); exit(1); @@ -56,18 +58,16 @@ int main(int argc, char **argv) init_sighandler(); - pid = attach_process(argv[1], argv+1); - fprintf(output, "pid %u attached\n", pid); - -#if 1 - /* Enable breakpoints: */ - fprintf(output, "Enabling breakpoints...\n"); - enable_all_breakpoints(pid); -#endif - fprintf(output, "Reading config file(s)...\n"); + if (opt_d>0) { + fprintf(output, "Reading config file(s)...\n"); + } read_config_file("/etc/ltrace.cfg"); read_config_file(".ltracerc"); - continue_process(pid, 0); + + pid = execute_process(argv[1], argv+1); + if (opt_d>0) { + fprintf(output, "pid %u launched\n", pid); + } while(1) { pause(); @@ -1,3 +1,4 @@ -extern int debug; extern FILE * output; +extern int opt_d; +extern int opt_i; @@ -7,19 +7,20 @@ #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 "i386.h" +#include "syscall.h" struct process * list_of_processes = NULL; -int attach_process(const char * file, char * const argv[]) +int execute_process(const char * file, char * const argv[]) { - int status; int pid = fork(); - struct process * tmp; if (pid<0) { perror("fork"); @@ -30,21 +31,48 @@ int attach_process(const char * file, char * const argv[]) fprintf(stderr, "Can't execute \"%s\": %s\n", argv[1], sys_errlist[errno]); exit(1); } - /* Wait until execve... */ - if (wait4(pid, &status, 0, NULL)==-1) { - perror("wait4"); - exit(1); - } - if (!(WIFSTOPPED(status) && (WSTOPSIG(status)==SIGTRAP))) { - fprintf(stderr, "Unknown exit status for process %s\n", file); - exit(1); - } + + return pid; +} + +struct process * attach_process(int pid) +{ + struct process * tmp; + tmp = (struct process *)malloc(sizeof(struct process)); tmp->pid = pid; + tmp->syscall_number = -1; tmp->next = list_of_processes; list_of_processes = tmp; - - return pid; + + return tmp; +} + +/* + * TODO: All the breakpoints should be disabled. + */ +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)) { + untrace_pid(pid); + } } struct process * pid2proc(int pid) @@ -75,7 +103,7 @@ static void chld_handler() int function_seen; int status; struct library_symbol * tmp = NULL; - unsigned int orig_eax; + struct process * current_process; signal(SIGCHLD, chld_handler); @@ -88,45 +116,70 @@ static void chld_handler() return; } if (pid==-1) { -fprintf(stderr, "errno=%d\n", errno); - if (errno == ECHILD) { - fprintf(output, "No more children\n"); - exit(0); - } perror("wait4"); exit(1); } + current_process = pid2proc(pid); + if (!current_process) { + /* + * I should assume here that this process is new, so I + * have to enable breakpoints + */ + if (opt_d>0) { + fprintf(output, "new process %d. Attaching it...\n", pid); + } + current_process = attach_process(pid); + if (opt_d>0) { + fprintf(output, "Enabling breakpoints for pid %d...\n", pid); + } + enable_all_breakpoints(pid); + } if (WIFEXITED(status)) { fprintf(output, "pid %u exited\n", pid); + detach_process(pid); return; } if (WIFSIGNALED(status)) { fprintf(output, "pid %u exited on signal %u\n", pid, WTERMSIG(status)); + detach_process(pid); return; } if (!WIFSTOPPED(status)) { fprintf(output, "pid %u ???\n", pid); - return; + exit(1); } - fprintf(output, "<pid:%u> ", pid); eip = get_eip(pid); -orig_eax = get_orig_eax(pid); -if (orig_eax!=-1) { -fprintf(output,"[0x%08lx] SYSCALL: %u\n", eip, orig_eax); -continue_process(pid, 0); -return; -} if (WSTOPSIG(status) != SIGTRAP) { fprintf(output, "[0x%08lx] Signal: %u\n", eip, WSTOPSIG(status)); continue_process(pid, WSTOPSIG(status)); return; } - /* pid is stopped... */ + if (opt_d>0) { + fprintf(output, "<pid:%u> ", pid); + } + switch (type_of_stop(current_process, &status)) { + case PROC_SYSCALL: + if (status==__NR_fork) { + disable_all_breakpoints(pid); + } + fprintf(output, "[0x%08lx] SYSCALL: %s()\n", eip, syscall_list[status]); + continue_process(pid, 0); + return; + case PROC_SYSRET: + if (status==__NR_fork) { + enable_all_breakpoints(pid); + } + if (opt_d>0) { + fprintf(output, "[0x%08lx] SYSRET: %u\n", eip, status); + } + continue_process(pid, 0); + return; + case PROC_BREAKPOINT: + default: + } + /* pid is breakpointed... */ + /* TODO: I may be here after a PTRACE_SINGLESTEP ... */ esp = get_esp(pid); -#if 0 - fprintf(output,"EIP = 0x%08x\n", eip); - fprintf(output,"ESP = 0x%08x\n", esp); -#endif fprintf(output,"[0x%08lx] ", get_return(pid,esp)); tmp = library_symbols; function_seen = 0; @@ -1,9 +1,33 @@ +#ifndef _LTRACE_PROCESS_H +#define _LTRACE_PROCESS_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() */ int pid; + int syscall_number; /* outside syscall => syscall_number=-1 */ struct process * next; }; extern struct process * list_of_processes; -int attach_process(const char * file, char * const argv[]); +int execute_process(const char * file, char * const argv[]); void init_sighandler(void); + +#endif @@ -1,3 +1,6 @@ +#ifndef _LTRACE_SYMBOLS_H +#define _LTRACE_SYMBOLS_H + #include "i386.h" struct library_symbol { @@ -12,3 +15,5 @@ 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 new file mode 100644 index 0000000..36d6678 --- /dev/null +++ b/syscall.c @@ -0,0 +1,165 @@ +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", + "acct", + "phys", + "lock", + "ioctl", + "fcntl", + "mpx", + "setpgid", + "ulimit", + "oldolduname", + "umask", + "chroot", + "ustat", + "dup2", + "getppid", + "getpgrp", + "setsid", + "sigaction", + "sgetmask", + "ssetmask", + "setreuid", + "setregid", + "sigsuspend", + "sigpending", + "sethostname", + "setrlimit", + "getrlimit", + "getrusage", + "gettimeofday", + "settimeofday", + "getgroups", + "setgroups", + "select", + "symlink", + "oldlstat", + "readlink", + "uselib", + "swapon", + "reboot", + "readdir", + "mmap", + "munmap", + "truncate", + "ftruncate", + "fchmod", + "fchown", + "getpriority", + "setpriority", + "profil", + "statfs", + "fstatfs", + "ioperm", + "socketcall", + "syslog", + "setitimer", + "getitimer", + "stat", + "lstat", + "fstat", + "olduname", + "iopl", + "vhangup", + "idle", + "vm86", + "wait4", + "swapoff", + "sysinfo", + "ipc", + "fsync", + "sigreturn", + "clone", + "setdomainname", + "uname", + "modify_ldt", + "adjtimex", + "mprotect", + "sigprocmask", + "create_module", + "init_module", + "delete_module", + "get_kernel_syms", + "quotactl", + "getpgid", + "fchdir", + "bdflush", + "sysfs", + "personality", + "afs_syscall", + "setfsuid", + "setfsgid", + "_llseek", + "getdents", + "_newselect", + "flock", + "msync", + "readv", + "writev", + "getsid", + "fdatasync", + "_sysctl", + "mlock", + "munlock", + "mlockall", + "munlockall", + "sched_setparam", + "sched_getparam", + "sched_setscheduler", + "sched_getscheduler", + "sched_yield", + "sched_get_priority_max", + "sched_get_priority_min", + "sched_rr_get_interval", + "nanosleep", + "mremap", +}; diff --git a/syscall.h b/syscall.h new file mode 100644 index 0000000..3ca9072 --- /dev/null +++ b/syscall.h @@ -0,0 +1,2 @@ + +extern char * syscall_list[]; diff --git a/tests/execl b/tests/execl Binary files differindex 17f439f..e39f5c6 100755 --- a/tests/execl +++ b/tests/execl diff --git a/tests/execl.c b/tests/execl.c index 6745651..5ed7e19 100644 --- a/tests/execl.c +++ b/tests/execl.c @@ -1,4 +1,4 @@ main() { - execl("/home/cespedes/debian/hck/ltrace-0.1.1/tests/hello",0); + execl("/home/cespedes/debian/hck/ltrace-0.1.2/tests/hello",0); } |