diff options
-rw-r--r-- | BUGS | 4 | ||||
-rw-r--r-- | README | 26 | ||||
-rw-r--r-- | TODO | 10 | ||||
-rw-r--r-- | debian/changelog | 8 | ||||
-rw-r--r-- | elf.c | 11 | ||||
-rw-r--r-- | functions.c | 7 | ||||
-rw-r--r-- | i386.c | 6 | ||||
-rw-r--r-- | ltrace.1 | 6 | ||||
-rw-r--r-- | ltrace.c | 12 | ||||
-rw-r--r-- | output.c | 6 | ||||
-rw-r--r-- | process.c | 104 | ||||
-rw-r--r-- | process.h | 8 |
12 files changed, 105 insertions, 103 deletions
@@ -1,2 +1,2 @@ -* When a process fork()s, the child will continue receiving SIGTRAPs, - and will probably die due to that. +Too many... :) + @@ -8,10 +8,11 @@ Contents -------- 1. Introduction - 2. How does it work - 3. Where does it work - 4. Bugs - 5. Licence + 2. Where can I find it + 3. How does it work + 4. Where does it work + 5. Bugs + 6. Licence 1. Introduction @@ -19,24 +20,33 @@ Contents ltrace is a debugging tool, similar to strace, but it traces library calls instead of system calls. -2. How does it work +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_* +Alternatively, you may find it in any Debian mirror. For more info, +see ftp://ftp.debian.org/debian/README.mirrors + +3. How does it work ------------------- Using i386 software breakpoints, just like gdb. -3. Where does it work +4. Where does it work --------------------- At the time of writting, it works only with Intel ELF executables. It has been used only in Debian/GNU Linux, but it should work without any problem in any other i386 Linux, such as SuSe or RedHat, and maybe in other i386 based POSIX system, such as Hurd or *BSD. -4. Bugs +5. Bugs ------- 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 ``Juan Cespedes <cespedes@etsit.upm.es>''. -5. Licence +6. Licence ---------- Copyright (C) 1997 Juan Cespedes <cespedes@etsit.upm.es> @@ -10,16 +10,16 @@ - It breakpointed at a syscall return * ``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 - 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 diff --git a/debian/changelog b/debian/changelog index 14a6d7c..09c255e 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,11 @@ +ltrace (0.1.4) experimental; urgency=low + + * Updated execute_process() + * No longer uses signals to wait for children. Should be a little faster. + * Now every function uses output.c:send_*() instead of `FILE * output' + + -- Juan Cespedes <cespedes@etsit.upm.es> Mon, 25 Aug 1997 16:08:36 +0200 + ltrace (0.1.3) experimental; urgency=low * Added options `-i', `-S' @@ -15,6 +15,7 @@ #include "elf.h" #include "ltrace.h" #include "symbols.h" +#include "output.h" int read_elf(const char *filename) { @@ -29,7 +30,7 @@ int read_elf(const char *filename) u_long symtab_len = 0; if (opt_d>0) { - fprintf(output, "Reading symbol table from %s...\n", filename); + send_line("Reading symbol table from %s...", filename); } fd = open(filename, O_RDONLY); @@ -74,9 +75,9 @@ int read_elf(const char *filename) } } 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); + send_line("symtab: 0x%08x", (unsigned)symtab); + send_line("symtab_len: %lu", symtab_len); + send_line("strtab: 0x%08x", (unsigned)strtab); } if (!symtab) { return 0; @@ -94,7 +95,7 @@ int read_elf(const char *filename) library_symbols->name = strtab+(symtab+i)->st_name; library_symbols->next = tmp; if (opt_d>1) { - fprintf(output, "addr: 0x%08x, symbol: \"%s\"\n", + send_line("addr: 0x%08x, symbol: \"%s\"", (unsigned)((symtab+i)->st_value), (strtab+(symtab+i)->st_name)); } diff --git a/functions.c b/functions.c index 9a55b84..7070ecc 100644 --- a/functions.c +++ b/functions.c @@ -4,9 +4,8 @@ #include <stdlib.h> #include <ctype.h> -extern FILE * output; - #include "functions.h" +#include "output.h" static int current_pid; @@ -126,8 +125,8 @@ void print_function(const char *name, int pid, int esp) for(i=1; i<tmp->num_params; i++) { sprintf(message, "%s,%s", message, print_param(tmp->params_type[i], esp+4*(i+1))); } - fprintf(output, "%s) = ???\n", message); - fflush(output); + send_left("%s", message); + send_right(") = ???"); } static int func_type(char ** buf) @@ -89,12 +89,8 @@ void continue_after_breakpoint(int pid, unsigned long eip, unsigned char * value ptrace(PTRACE_SINGLESTEP, pid, 0, 0); - pid = wait4(-1, &status, 0, NULL); + pid = wait4(pid, &status, 0, NULL); if (pid==-1) { - if (errno == ECHILD) { - fprintf(output, "No more children\n"); - exit(0); - } perror("wait4"); exit(1); } @@ -17,7 +17,7 @@ which are called by the executed process and the signals which are received by that process. .PP Its use is very similar to -.BR strace (1). +.BR strace(1). .SH OPTIONS .TP @@ -38,7 +38,9 @@ rather than to stderr. .SH BUGS At the moment, there are too many bugs to list here. .PP -If you like to report a bug, send a notice to the author. +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 AUTHOR Juan Cespedes <cespedes@etsit.upm.es> @@ -4,6 +4,7 @@ #include "elf.h" #include "process.h" +#include "output.h" extern void read_config_file(const char *); @@ -52,24 +53,19 @@ int main(int argc, char **argv) exit(1); } - init_sighandler(); - if (opt_d>0) { - fprintf(output, "Reading config file(s)...\n"); + send_line("Reading config file(s)..."); } read_config_file("/etc/ltrace.cfg"); read_config_file(".ltracerc"); pid = execute_process(argv[1], argv+1); if (opt_d>0) { - fprintf(output, "pid %u launched\n", pid); + send_line("pid %u launched", pid); } while(1) { - pause(); - if (!list_of_processes) { - break; - } + wait_for_child(); } exit(0); @@ -1,3 +1,4 @@ +#include <stdio.h> #include <stdarg.h> #include "ltrace.h" @@ -24,10 +25,8 @@ void send_right(const char * fmt, ...) if (new_line==0) { va_start(args, fmt); - if (opt_i) { - fprintf(output, "[%08x] ", instruction_pointer); - } vfprintf(output, fmt, args); + fprintf(output, "\n"); va_end(args); } new_line=1; @@ -42,6 +41,7 @@ void send_line(const char * fmt, ...) fprintf(output, "[%08x] ", instruction_pointer); } vfprintf(output, fmt, args); + fprintf(output, "\n"); va_end(args); new_line=1; } @@ -22,8 +22,13 @@ 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) { @@ -35,27 +40,18 @@ int execute_process(const char * file, char * const argv[]) fprintf(stderr, "Can't execute \"%s\": %s\n", argv[1], sys_errlist[errno]); exit(1); } - - return pid; -} - -struct process * attach_process(int pid) -{ - struct process * tmp; tmp = (struct process *)malloc(sizeof(struct process)); tmp->pid = pid; + tmp->breakpoints_enabled = 0; tmp->syscall_number = -1; tmp->next = list_of_processes; list_of_processes = tmp; - - return tmp; + + return pid; } -/* - * TODO: All the breakpoints should be disabled. - */ -void detach_process(int pid) +static void detach_process(int pid) { struct process *tmp, *tmp2; @@ -75,11 +71,12 @@ void detach_process(int pid) } } if (!kill(pid,0)) { + disable_all_breakpoints(pid); untrace_pid(pid); } } -struct process * pid2proc(int pid) +static struct process * pid2proc(int pid) { struct process * tmp; @@ -93,82 +90,76 @@ struct process * pid2proc(int pid) return NULL; } -static void chld_handler(); -void init_sighandler(void) -{ - signal(SIGCHLD, chld_handler); -} - -static void chld_handler() +void wait_for_child(void) { int pid; - unsigned long eip; - int esp; - int function_seen; int status; - struct library_symbol * tmp = NULL; struct process * current_process; - signal(SIGCHLD, chld_handler); - - pid = wait4(-1, &status, WNOHANG, NULL); - if (!pid) { - if (errno!=0) { - perror("wait4"); - exit(1); - } - return; - } + pid = wait4(-1, &status, 0, NULL); if (pid==-1) { + if (errno == ECHILD) { + send_line("No more children"); + 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); + fprintf(stderr, "wrong pid %d ???\n", pid); + exit(1); + } + if (!current_process->breakpoints_enabled) { if (opt_d>0) { - fprintf(output, "Enabling breakpoints for pid %d...\n", pid); + send_line("Enabling breakpoints for pid %d...", pid); } enable_all_breakpoints(pid); + current_process->breakpoints_enabled=1; } if (WIFEXITED(status)) { - fprintf(output, "pid %u exited\n", pid); + send_line("pid %u exited", pid); detach_process(pid); return; } if (WIFSIGNALED(status)) { - fprintf(output, "pid %u exited on signal %u\n", pid, WTERMSIG(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)) { - fprintf(output, "pid %u ???\n", pid); + send_line("pid %u ???", pid); exit(1); } - eip = get_eip(pid); - instruction_pointer = eip; if (WSTOPSIG(status) != SIGTRAP) { - send_line("--- %s (%s) ---\n", signal_name[WSTOPSIG(status)], strsignal(WSTOPSIG(status))); + send_line("--- %s (%s) ---", signal_name[WSTOPSIG(status)], strsignal(WSTOPSIG(status))); continue_process(pid, WSTOPSIG(status)); return; } - if (opt_d>0) { - fprintf(output, "<pid:%u> ", pid); - } + 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, &status)) { case PROC_SYSCALL: if (status==__NR_fork) { disable_all_breakpoints(pid); } if (opt_S) { - send_line("SYSCALL: %s()\n", syscall_list[status]); + send_line("SYSCALL: %s()", syscall_list[status]); } continue_process(pid, 0); return; @@ -177,7 +168,7 @@ static void chld_handler() enable_all_breakpoints(pid); } if (opt_S && (opt_d>0)) { - send_line("SYSRET: %u\n", status); + send_line("SYSRET: %u", status); } continue_process(pid, 0); return; @@ -188,7 +179,6 @@ static void chld_handler() /* TODO: I may be here after a PTRACE_SINGLESTEP ... */ esp = get_esp(pid); instruction_pointer = get_return(pid, esp); - send_line(""); tmp = library_symbols; function_seen = 0; while(tmp) { @@ -201,7 +191,7 @@ static void chld_handler() tmp = tmp->next; } if (!function_seen) { - fprintf(output, "pid %u stopped; continuing it...\n", pid); + send_line("pid %u stopped; continuing it...", pid); continue_process(pid, 0); } } @@ -15,13 +15,13 @@ struct library_symbol { unsigned char old_value[BREAKPOINT_LENGTH]; struct library_symbol * next; }; - #endif struct process { - char * filename; /* from execve() */ + char * filename; /* from execve() (TODO) */ int pid; - int syscall_number; /* outside syscall => syscall_number=-1 */ + int breakpoints_enabled; + int syscall_number; /* outside syscall => -1 */ struct process * next; }; @@ -30,6 +30,6 @@ extern struct process * list_of_processes; unsigned int instruction_pointer; int execute_process(const char * file, char * const argv[]); -void init_sighandler(void); +void wait_for_child(void); #endif |