aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--BUGS4
-rw-r--r--README26
-rw-r--r--TODO10
-rw-r--r--debian/changelog8
-rw-r--r--elf.c11
-rw-r--r--functions.c7
-rw-r--r--i386.c6
-rw-r--r--ltrace.16
-rw-r--r--ltrace.c12
-rw-r--r--output.c6
-rw-r--r--process.c104
-rw-r--r--process.h8
12 files changed, 105 insertions, 103 deletions
diff --git a/BUGS b/BUGS
index 72f42cb..0c04896 100644
--- a/BUGS
+++ b/BUGS
@@ -1,2 +1,2 @@
-* When a process fork()s, the child will continue receiving SIGTRAPs,
- and will probably die due to that.
+Too many... :)
+
diff --git a/README b/README
index 4a25592..66a8a33 100644
--- a/README
+++ b/README
@@ -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>
diff --git a/TODO b/TODO
index 432a967..72850d0 100644
--- a/TODO
+++ b/TODO
@@ -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'
diff --git a/elf.c b/elf.c
index 9f56820..03918aa 100644
--- a/elf.c
+++ b/elf.c
@@ -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)
diff --git a/i386.c b/i386.c
index c68f8a0..c2e9a98 100644
--- a/i386.c
+++ b/i386.c
@@ -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);
}
diff --git a/ltrace.1 b/ltrace.1
index e0951be..6b37fe7 100644
--- a/ltrace.1
+++ b/ltrace.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>
diff --git a/ltrace.c b/ltrace.c
index 33bb24c..6bd617f 100644
--- a/ltrace.c
+++ b/ltrace.c
@@ -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);
diff --git a/output.c b/output.c
index 93a409f..f4173a3 100644
--- a/output.c
+++ b/output.c
@@ -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;
}
diff --git a/process.c b/process.c
index 4f557be..c78390b 100644
--- a/process.c
+++ b/process.c
@@ -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);
}
}
diff --git a/process.h b/process.h
index 36c1bc2..f14dc95 100644
--- a/process.h
+++ b/process.h
@@ -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