diff options
-rw-r--r-- | BUGS | 2 | ||||
-rw-r--r-- | Makefile.in | 3 | ||||
-rw-r--r-- | README | 4 | ||||
-rw-r--r-- | breakpoints.c | 159 | ||||
-rw-r--r-- | config.h.in | 3 | ||||
-rwxr-xr-x | configure | 111 | ||||
-rw-r--r-- | configure.in | 3 | ||||
-rw-r--r-- | debian/changelog | 8 | ||||
-rw-r--r-- | debian/control | 2 | ||||
-rw-r--r-- | debian/copyright | 2 | ||||
-rwxr-xr-x | debian/rules | 2 | ||||
-rw-r--r-- | debug.c | 21 | ||||
-rw-r--r-- | debug.h | 20 | ||||
-rw-r--r-- | demangle.c | 117 | ||||
-rw-r--r-- | dict.c | 151 | ||||
-rw-r--r-- | dict.h | 18 | ||||
-rw-r--r-- | elf.c | 24 | ||||
-rw-r--r-- | execute_program.c | 58 | ||||
-rw-r--r-- | ltrace.c | 17 | ||||
-rw-r--r-- | ltrace.h | 2 | ||||
-rw-r--r-- | options.c | 2 | ||||
-rw-r--r-- | proc.c | 1 | ||||
-rw-r--r-- | process_event.c | 39 | ||||
-rw-r--r-- | read_config_file.c | 26 | ||||
-rw-r--r-- | wait_for_something.c | 18 |
25 files changed, 367 insertions, 446 deletions
@@ -2,4 +2,4 @@ * Manual page is not accurate (config files...) * elf.c only supports elf32 binaries * netscape sometimes dies with SIGSEGV (is this still true?) -* It only works on Linux/i386, Linux/m68k, and Linux/arm +* It lacks support for several Linux archs, and many operating systems diff --git a/Makefile.in b/Makefile.in index 37f4873..2ca7e1f 100644 --- a/Makefile.in +++ b/Makefile.in @@ -21,7 +21,8 @@ LIBS = @LIBS@ OBJ = ltrace.o options.o elf.o output.o read_config_file.o \ execute_program.o wait_for_something.o process_event.o \ - display_args.o breakpoints.o proc.o demangle.o + display_args.o breakpoints.o proc.o demangle.o dict.o \ + debug.o all: ltrace @@ -2,7 +2,7 @@ A Dynamic Library Tracer - Copyright 1997-2002 Juan Cespedes <cespedes@debian.org> + Copyright 1997-2003 Juan Cespedes <cespedes@debian.org> Contents @@ -67,7 +67,7 @@ This file is very incomplete and out-of-date. 6. License ---------- - Copyright (C) 1997-2002 Juan Cespedes <cespedes@debian.org> + Copyright (C) 1997-2003 Juan Cespedes <cespedes@debian.org> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/breakpoints.c b/breakpoints.c index 9b113a7..73dd638 100644 --- a/breakpoints.c +++ b/breakpoints.c @@ -2,10 +2,6 @@ #include "config.h" #endif -#include "ltrace.h" -#include "options.h" -#include "output.h" - #include <stdlib.h> #include <assert.h> @@ -13,134 +9,43 @@ #include <sys/ptrace.h> #endif -/*****************************************************************************/ - -/* - Dictionary code done by Morten Eriksen <mortene@sim.no>. - - FIXME: should we merge with dictionary code in demangle.c? 19990704 mortene. -*/ - -struct dict_entry { - struct process * proc; - struct breakpoint brk; /* addr field of struct is the hash key. */ - struct dict_entry * next; -}; - -#define DICTTABLESIZE 997 /* Semi-randomly selected prime number. */ -static struct dict_entry * dict_buckets[DICTTABLESIZE]; -static int dict_initialized = 0; - -static void dict_init(void); -static void dict_clear(void); -static struct breakpoint * dict_enter(struct process * proc, void * brkaddr); -struct breakpoint * dict_find_entry(struct process * proc, void * brkaddr); -static void dict_apply_to_all(void (* func)(struct process *, struct breakpoint *, void * data), void * data); - - -static void -dict_init(void) { - int i; - /* FIXME: is this necessary? Check with ANSI C spec. 19990702 mortene. */ - for (i = 0; i < DICTTABLESIZE; i++) dict_buckets[i] = NULL; - dict_initialized = 1; -} - -static void -dict_clear(void) { - int i; - struct dict_entry * entry, * nextentry; - - for (i = 0; i < DICTTABLESIZE; i++) { - for (entry = dict_buckets[i]; entry != NULL; entry = nextentry) { - nextentry = entry->next; - free(entry); - } - dict_buckets[i] = NULL; - } -} - -static struct breakpoint * -dict_enter(struct process * proc, void * brkaddr) { - struct dict_entry * entry, * newentry; - unsigned int bucketpos = ((unsigned long int)brkaddr) % DICTTABLESIZE; - - newentry = malloc(sizeof(struct dict_entry)); - if (!newentry) { - perror("malloc"); - return NULL; - } - - newentry->proc = proc; - newentry->brk.addr = brkaddr; - newentry->brk.enabled = 0; - newentry->next = NULL; - - entry = dict_buckets[bucketpos]; - while (entry && entry->next) entry = entry->next; - - if (entry) entry->next = newentry; - else dict_buckets[bucketpos] = newentry; - - if (opt_d > 2) - output_line(0, "new brk dict entry at %p\n", brkaddr); - - return &(newentry->brk); -} - -struct breakpoint * -dict_find_entry(struct process * proc, void * brkaddr) { - unsigned int bucketpos = ((unsigned long int)brkaddr) % DICTTABLESIZE; - struct dict_entry * entry = dict_buckets[bucketpos]; - while (entry) { - if ((entry->brk.addr == brkaddr) && (entry->proc == proc)) break; - entry = entry->next; - } - return entry ? &(entry->brk) : NULL; -} - -static void -dict_apply_to_all(void (* func)(struct process *, struct breakpoint *, void * data), void * data) { - int i; - - for (i = 0; i < DICTTABLESIZE; i++) { - struct dict_entry * entry = dict_buckets[i]; - while (entry) { - func(entry->proc, &(entry->brk), data); - entry = entry->next; - } - } -} - -#undef DICTTABLESIZE +#include "ltrace.h" +#include "options.h" +#include "debug.h" +#include "dict.h" /*****************************************************************************/ struct breakpoint * address2bpstruct(struct process * proc, void * addr) { - return dict_find_entry(proc, addr); + return dict_find_entry(proc->breakpoints, addr); } void insert_breakpoint(struct process * proc, void * addr) { struct breakpoint * sbp; - if (!dict_initialized) { - dict_init(); - atexit(dict_clear); + if (!proc->breakpoints) { + proc->breakpoints = dict_init(dict_key2hash_int, dict_key_cmp_int); + /* atexit(brk_dict_clear); */ /* why bother to do this on exit? */ + } + sbp = dict_find_entry(proc->breakpoints, addr); + if (!sbp) { + sbp = malloc(sizeof(struct breakpoint)); + if (!sbp) { + return; /* TODO FIXME XXX: error_mem */ + } + dict_enter(proc->breakpoints, addr, sbp); + sbp->addr = addr; + sbp->enabled = 0; } - - sbp = dict_find_entry(proc, addr); - if (!sbp) sbp = dict_enter(proc, addr); - if (!sbp) return; - sbp->enabled++; if (sbp->enabled==1 && proc->pid) enable_breakpoint(proc->pid, sbp); } void delete_breakpoint(struct process * proc, void * addr) { - struct breakpoint * sbp = dict_find_entry(proc, addr); + struct breakpoint * sbp = dict_find_entry(proc->breakpoints, addr); assert(sbp); /* FIXME: remove after debugging has been done. */ /* This should only happen on out-of-memory conditions. */ if (sbp == NULL) return; @@ -151,9 +56,10 @@ delete_breakpoint(struct process * proc, void * addr) { } static void -enable_bp_cb(struct process * proc, struct breakpoint * sbp, void * data) { - struct process * myproc = (struct process *)data; - if (myproc == proc && sbp->enabled) enable_breakpoint(proc->pid, sbp); +enable_bp_cb(void * addr, void * sbp, void * proc) { + if (((struct breakpoint *)sbp)->enabled) { + enable_breakpoint(((struct process *)proc)->pid, sbp); + } } void @@ -174,27 +80,24 @@ enable_all_breakpoints(struct process * proc) { } #endif - if (opt_d>0) { - output_line(0, "Enabling breakpoints for pid %u...", proc->pid); - } - dict_apply_to_all(enable_bp_cb, proc); + debug(1, "Enabling breakpoints for pid %u...", proc->pid); + dict_apply_to_all(proc->breakpoints, enable_bp_cb, proc); } proc->breakpoints_enabled = 1; } static void -disable_bp_cb(struct process * proc, struct breakpoint * sbp, void * data) { - struct process * myproc = (struct process *)data; - if (myproc == proc && sbp->enabled) disable_breakpoint(proc->pid, sbp); +disable_bp_cb(void * addr, void * sbp, void * proc) { + if (((struct breakpoint *)sbp)->enabled) { + disable_breakpoint(((struct process *)proc)->pid, sbp); + } } void disable_all_breakpoints(struct process * proc) { if (proc->breakpoints_enabled) { - if (opt_d>0) { - output_line(0, "Disabling breakpoints for pid %u...", proc->pid); - } - dict_apply_to_all(disable_bp_cb, proc); + debug(1, "Disabling breakpoints for pid %u...", proc->pid); + dict_apply_to_all(proc->breakpoints, disable_bp_cb, proc); } proc->breakpoints_enabled = 0; } diff --git a/config.h.in b/config.h.in index 17769ca..1a271ed 100644 --- a/config.h.in +++ b/config.h.in @@ -24,8 +24,5 @@ /* Define if you have the <getopt.h> header file. */ #undef HAVE_GETOPT_H -/* Define if you have the dl library (-ldl). */ -#undef HAVE_LIBDL - /* Define if you have the iberty library (-liberty). */ #undef HAVE_LIBIBERTY @@ -859,63 +859,16 @@ test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL_PROGRAM}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' -echo $ac_n "checking for dlopen in -ldl""... $ac_c" 1>&6 -echo "configure:864: checking for dlopen in -ldl" >&5 -ac_lib_var=`echo dl'_'dlopen | sed 'y%./+-%__p_%'` -if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then - echo $ac_n "(cached) $ac_c" 1>&6 -else - ac_save_LIBS="$LIBS" -LIBS="-ldl $LIBS" -cat > conftest.$ac_ext <<EOF -#line 872 "configure" -#include "confdefs.h" -/* Override any gcc2 internal prototype to avoid an error. */ -/* We use char because int might match the return type of a gcc2 - builtin and then its argument prototype would still apply. */ -char dlopen(); - -int main() { -dlopen() -; return 0; } -EOF -if { (eval echo configure:883: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then - rm -rf conftest* - eval "ac_cv_lib_$ac_lib_var=yes" -else - echo "configure: failed program was:" >&5 - cat conftest.$ac_ext >&5 - rm -rf conftest* - eval "ac_cv_lib_$ac_lib_var=no" -fi -rm -f conftest* -LIBS="$ac_save_LIBS" - -fi -if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then - echo "$ac_t""yes" 1>&6 - ac_tr_lib=HAVE_LIB`echo dl | sed -e 's/[^a-zA-Z0-9_]/_/g' \ - -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'` - cat >> confdefs.h <<EOF -#define $ac_tr_lib 1 -EOF - - LIBS="-ldl $LIBS" - -else - echo "$ac_t""no" 1>&6 -fi - echo $ac_n "checking for cplus_demangle in -liberty""... $ac_c" 1>&6 -echo "configure:911: checking for cplus_demangle in -liberty" >&5 +echo "configure:864: checking for cplus_demangle in -liberty" >&5 ac_lib_var=`echo iberty'_'cplus_demangle | sed 'y%./+-%__p_%'` if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else ac_save_LIBS="$LIBS" -LIBS="-liberty -ldl $LIBS" +LIBS="-liberty $LIBS" cat > conftest.$ac_ext <<EOF -#line 919 "configure" +#line 872 "configure" #include "confdefs.h" /* Override any gcc2 internal prototype to avoid an error. */ /* We use char because int might match the return type of a gcc2 @@ -926,7 +879,7 @@ int main() { cplus_demangle() ; return 0; } EOF -if { (eval echo configure:930: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:883: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_lib_$ac_lib_var=yes" else @@ -955,7 +908,7 @@ fi echo $ac_n "checking ltrace version""... $ac_c" 1>&6 -echo "configure:959: checking ltrace version" >&5 +echo "configure:912: checking ltrace version" >&5 ltrace_version=`sed -n '1s/ltrace (\([0-9.]\+\)).*/\1/p' ${srcdir}/debian/changelog` sed -e "s/@VERSION@/${ltrace_version}/g" \ @@ -965,7 +918,7 @@ echo "$ac_t""$ltrace_version" 1>&6 echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6 -echo "configure:969: checking how to run the C preprocessor" >&5 +echo "configure:922: checking how to run the C preprocessor" >&5 # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= @@ -980,13 +933,13 @@ else # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. cat > conftest.$ac_ext <<EOF -#line 984 "configure" +#line 937 "configure" #include "confdefs.h" #include <assert.h> Syntax Error EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:990: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:943: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then : @@ -997,13 +950,13 @@ else rm -rf conftest* CPP="${CC-cc} -E -traditional-cpp" cat > conftest.$ac_ext <<EOF -#line 1001 "configure" +#line 954 "configure" #include "confdefs.h" #include <assert.h> Syntax Error EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:1007: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:960: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then : @@ -1014,13 +967,13 @@ else rm -rf conftest* CPP="${CC-cc} -nologo -E" cat > conftest.$ac_ext <<EOF -#line 1018 "configure" +#line 971 "configure" #include "confdefs.h" #include <assert.h> Syntax Error EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:1024: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:977: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then : @@ -1045,12 +998,12 @@ fi echo "$ac_t""$CPP" 1>&6 echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6 -echo "configure:1049: checking for ANSI C header files" >&5 +echo "configure:1002: checking for ANSI C header files" >&5 if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 1054 "configure" +#line 1007 "configure" #include "confdefs.h" #include <stdlib.h> #include <stdarg.h> @@ -1058,7 +1011,7 @@ else #include <float.h> EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:1062: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:1015: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -1075,7 +1028,7 @@ rm -f conftest* if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat > conftest.$ac_ext <<EOF -#line 1079 "configure" +#line 1032 "configure" #include "confdefs.h" #include <string.h> EOF @@ -1093,7 +1046,7 @@ fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat > conftest.$ac_ext <<EOF -#line 1097 "configure" +#line 1050 "configure" #include "confdefs.h" #include <stdlib.h> EOF @@ -1114,7 +1067,7 @@ if test "$cross_compiling" = yes; then : else cat > conftest.$ac_ext <<EOF -#line 1118 "configure" +#line 1071 "configure" #include "confdefs.h" #include <ctype.h> #define ISLOWER(c) ('a' <= (c) && (c) <= 'z') @@ -1125,7 +1078,7 @@ if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2); exit (0); } EOF -if { (eval echo configure:1129: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null +if { (eval echo configure:1082: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null then : else @@ -1152,17 +1105,17 @@ for ac_hdr in getopt.h do ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'` echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6 -echo "configure:1156: checking for $ac_hdr" >&5 +echo "configure:1109: checking for $ac_hdr" >&5 if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 1161 "configure" +#line 1114 "configure" #include "confdefs.h" #include <$ac_hdr> EOF ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out" -{ (eval echo configure:1166: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } +{ (eval echo configure:1119: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; } ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"` if test -z "$ac_err"; then rm -rf conftest* @@ -1189,12 +1142,12 @@ fi done echo $ac_n "checking for working const""... $ac_c" 1>&6 -echo "configure:1193: checking for working const" >&5 +echo "configure:1146: checking for working const" >&5 if eval "test \"`echo '$''{'ac_cv_c_const'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 1198 "configure" +#line 1151 "configure" #include "confdefs.h" int main() { @@ -1243,7 +1196,7 @@ ccp = (char const *const *) p; ; return 0; } EOF -if { (eval echo configure:1247: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then +if { (eval echo configure:1200: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then rm -rf conftest* ac_cv_c_const=yes else @@ -1264,12 +1217,12 @@ EOF fi echo $ac_n "checking for uid_t in sys/types.h""... $ac_c" 1>&6 -echo "configure:1268: checking for uid_t in sys/types.h" >&5 +echo "configure:1221: checking for uid_t in sys/types.h" >&5 if eval "test \"`echo '$''{'ac_cv_type_uid_t'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 1273 "configure" +#line 1226 "configure" #include "confdefs.h" #include <sys/types.h> EOF @@ -1298,12 +1251,12 @@ EOF fi echo $ac_n "checking for pid_t""... $ac_c" 1>&6 -echo "configure:1302: checking for pid_t" >&5 +echo "configure:1255: checking for pid_t" >&5 if eval "test \"`echo '$''{'ac_cv_type_pid_t'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 1307 "configure" +#line 1260 "configure" #include "confdefs.h" #include <sys/types.h> #if STDC_HEADERS @@ -1333,12 +1286,12 @@ fi for ac_func in getopt getopt_long do echo $ac_n "checking for $ac_func""... $ac_c" 1>&6 -echo "configure:1337: checking for $ac_func" >&5 +echo "configure:1290: checking for $ac_func" >&5 if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then echo $ac_n "(cached) $ac_c" 1>&6 else cat > conftest.$ac_ext <<EOF -#line 1342 "configure" +#line 1295 "configure" #include "confdefs.h" /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $ac_func(); below. */ @@ -1361,7 +1314,7 @@ $ac_func(); ; return 0; } EOF -if { (eval echo configure:1365: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then +if { (eval echo configure:1318: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then rm -rf conftest* eval "ac_cv_func_$ac_func=yes" else diff --git a/configure.in b/configure.in index 35acb4a..98dd645 100644 --- a/configure.in +++ b/configure.in @@ -12,8 +12,7 @@ AC_PROG_CC AC_PROG_INSTALL dnl Checks for libraries. -AC_CHECK_LIB(dl, dlopen) -AC_CHECK_LIB(iberty, cplus_demangle,,,-ldl) +AC_CHECK_LIB(iberty, cplus_demangle,,,) AC_MSG_CHECKING(ltrace version) changequote(<<, >>) diff --git a/debian/changelog b/debian/changelog index 00f14b9..89b41ad 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,11 @@ +ltrace (0.3.27) unstable; urgency=low + + * Removed dependency on libdl (it is no longer needed) + * Wrote generic dictionary, used in demangle.c and breakpoints.c + * Added debug.c for better debugging output + + -- Juan Cespedes <cespedes@debian.org> Fri, 31 Jan 2003 18:58:55 +0100 + ltrace (0.3.26) unstable; urgency=low * Fixed `ltrace -L' in powerpc diff --git a/debian/control b/debian/control index 1de2c81..3e546bb 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: 3.5.5 +Standards-Version: 3.5.6 Build-Depends: binutils-dev Package: ltrace diff --git a/debian/copyright b/debian/copyright index 1893192..31535aa 100644 --- a/debian/copyright +++ b/debian/copyright @@ -4,7 +4,7 @@ Dynamic Library Tracer ``ltrace''. Copyrights ---------- -Copyright (C) 1997-2002 Juan Cespedes <cespedes@debian.org> +Copyright (C) 1997-2003 Juan Cespedes <cespedes@debian.org> ARMLinux port: Copyright (C) 1998 Pat Beirne <pbeirne@home.com> m68k port: Copyright (C) 1998 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de> diff --git a/debian/rules b/debian/rules index 6cd930a..5f7eb45 100755 --- a/debian/rules +++ b/debian/rules @@ -1,6 +1,6 @@ #! /usr/bin/make -f # -# Copyright (C) 1997-2002 Juan Cespedes <cespedes@debian.org> +# Copyright (C) 1997-2003 Juan Cespedes <cespedes@debian.org> .PHONY: binary binary-indep binary-arch clean @@ -0,0 +1,21 @@ +#include <stdio.h> +#include <stdarg.h> + +#include "debug.h" +#include "options.h" +#include "output.h" + +void +debug_(int level, char *file, int line, char *func, char *fmt, ...) { + char buf[1024]; + va_list args; + + if (opt_d < level) { + return; + } + va_start(args, fmt); + vsnprintf(buf, 1024, fmt, args); + va_end(args); + + output_line(NULL, "DEBUG: %s:%d: %s(): %s", file, line, func, buf); +} @@ -0,0 +1,20 @@ +#include <features.h> + +void debug_(int level, char *file, int line, char *func, char *fmt, ...); + +# define debug(level, expr...) debug_(level, __FILE__, __LINE__, DEBUG_FUNCTION, expr) + +/* Version 2.4 and later of GCC define a magical variable `__PRETTY_FUNCTION__' + which contains the name of the function currently being defined. + This is broken in G++ before version 2.6. + C9x has a similar variable called __func__, but prefer the GCC one since + it demangles C++ function names. */ +# if __GNUC_PREREQ (2, 4) +# define DEBUG_FUNCTION __PRETTY_FUNCTION__ +# else +# if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L +# define DEBUG_FUNCTION __func__ +# else +# define DEBUG_FUNCTION ((__const char *) 0) +# endif +# endif @@ -12,128 +12,33 @@ #include "output.h" #include "demangle.h" -/*****************************************************************************/ - -/* - The string dictionary code done by Morten Eriksen <mortene@sim.no>. - - FIXME: since this is a generic string dictionary, it should perhaps - be cleaned up a bit, "object-ified" and placed in its own .c + .h - pair of files? 19990702 mortene. -*/ - -struct dict_entry -{ - unsigned int key; - const char * mangled, * demangled; - struct dict_entry * next; -}; +#include "dict.h" -#define DICTTABLESIZE 997 /* Semi-randomly selected prime number. */ -static struct dict_entry * dict_buckets[DICTTABLESIZE]; -static int dict_initialized = 0; - -static void dict_init(void); -static void dict_clear(void); -static void dict_enter(const char * mangled, const char * demangled); -static const char * dict_find_entry(const char * mangled); -static unsigned int dict_hash_string(const char * s); - - -static void -dict_init(void) { - int i; - /* FIXME: is this necessary? Check with ANSI C spec. 19990702 mortene. */ - for (i = 0; i < DICTTABLESIZE; i++) dict_buckets[i] = NULL; - dict_initialized = 1; -} +/*****************************************************************************/ -static void -dict_clear(void) { - int i; - struct dict_entry * entry, * nextentry; - - for (i = 0; i < DICTTABLESIZE; i++) { - for (entry = dict_buckets[i]; entry != NULL; entry = nextentry) { - nextentry = entry->next; - free((void *)(entry->mangled)); - if (entry->mangled != entry->demangled) - free((void *)(entry->demangled)); - free(entry); - } - dict_buckets[i] = NULL; - } -} +static struct dict * d = NULL; static void -dict_enter(const char * mangled, const char * demangled) { - struct dict_entry * entry, * newentry; - unsigned int key = dict_hash_string(mangled); - - newentry = malloc(sizeof(struct dict_entry)); - if (!newentry) { - perror("malloc"); - return; - } - - newentry->key = key; - newentry->mangled = mangled; - newentry->demangled = demangled; - newentry->next = NULL; - - entry = dict_buckets[key % DICTTABLESIZE]; - while (entry && entry->next) entry = entry->next; - - if (entry) entry->next = newentry; - else dict_buckets[key % DICTTABLESIZE] = newentry; - - if (opt_d > 2) - output_line(0, "new dict entry: '%s' -> '%s'\n", mangled, demangled); -} - -static const char * -dict_find_entry(const char * mangled) { - unsigned int key = dict_hash_string(mangled); - struct dict_entry * entry = dict_buckets[key % DICTTABLESIZE]; - while (entry) { - if ((entry->key == key) && (strcmp(entry->mangled, mangled) == 0)) break; - entry = entry->next; - } - return entry ? entry->demangled : NULL; +my_demangle_dict_clear(void) { + /* FIXME TODO XXX: I should also free all (key,value) pairs */ + dict_clear(d); } -static unsigned int -dict_hash_string(const char * s) { - unsigned int total = 0, shift = 0; - - while (*s) { - total = total ^ ((*s) << shift); - shift += 5; - if (shift > 24) shift -= 24; - s++; - } - return total; -} - -#undef DICTTABLESIZE - -/*****************************************************************************/ - const char * my_demangle(const char * function_name) { const char * tmp, * fn_copy; - if (!dict_initialized) { - dict_init(); - atexit(dict_clear); + if (!d) { + d = dict_init(dict_key2hash_string, dict_key_cmp_string); + atexit(my_demangle_dict_clear); } - tmp = dict_find_entry(function_name); + tmp = dict_find_entry(d, (void *)function_name); if (!tmp) { fn_copy = strdup(function_name); tmp = cplus_demangle(function_name+strspn(function_name, "_"), DMGL_ANSI | DMGL_PARAMS); if (!tmp) tmp = fn_copy; - if (tmp) dict_enter(fn_copy, tmp); + if (tmp) dict_enter(d, (void *)fn_copy, (void *)tmp); } return tmp; } @@ -0,0 +1,151 @@ +#include <stdio.h> +#include <stdlib.h> + +#include "debug.h" + +/* + Dictionary based on code by Morten Eriksen <mortene@sim.no>. +*/ + +#include "dict.h" + +struct dict_entry { + unsigned int hash; + void * key; + void * value; + struct dict_entry * next; +}; + +/* #define DICTTABLESIZE 97 */ +#define DICTTABLESIZE 997 /* Semi-randomly selected prime number. */ +/* #define DICTTABLESIZE 9973 */ +/* #define DICTTABLESIZE 99991 */ +/* #define DICTTABLESIZE 999983 */ + +struct dict { + struct dict_entry * buckets[DICTTABLESIZE]; + unsigned int (*key2hash)(void *); + int (*key_cmp)(void *, void *); +}; + +struct dict * +dict_init(unsigned int (*key2hash)(void *), int (*key_cmp)(void *, void *)) { + struct dict * d; + int i; + + d = malloc(sizeof(struct dict)); + if (!d) { + perror("malloc()"); + exit(1); + } + for (i = 0; i < DICTTABLESIZE; i++) { /* better use memset()? */ + d->buckets[i] = NULL; + } + d->key2hash = key2hash; + d->key_cmp = key_cmp; + return d; +} + +void +dict_clear(struct dict * d) { + int i; + struct dict_entry * entry, * nextentry; + + for (i = 0; i < DICTTABLESIZE; i++) { + for (entry = d->buckets[i]; entry != NULL; entry = nextentry) { + nextentry = entry->next; + free(entry); + } + d->buckets[i] = NULL; + } + free(d); +} + +int +dict_enter(struct dict * d, void * key, void * value) { + struct dict_entry * entry, * newentry; + unsigned int hash = d->key2hash(key); + unsigned int bucketpos = hash % DICTTABLESIZE; + + newentry = malloc(sizeof(struct dict_entry)); + if (!newentry) { + perror("malloc"); + exit(1); + } + + newentry->hash = hash; + newentry->key = key; + newentry->value = value; + newentry->next = NULL; + + entry = d->buckets[bucketpos]; + while (entry && entry->next) entry = entry->next; + + if (entry) entry->next = newentry; + else d->buckets[bucketpos] = newentry; + + debug(3, "new dict entry at %p[%d]: (%p,%p)\n", d, bucketpos, key, value); + return 0; +} + +void * +dict_find_entry(struct dict * d, void * key) { + unsigned int hash = d->key2hash(key); + unsigned int bucketpos = hash % DICTTABLESIZE; + struct dict_entry * entry; + + for (entry = d->buckets[bucketpos]; entry; entry = entry->next) { + if (hash != entry->hash) { + continue; + } + if (!d->key_cmp(key, entry->key)) { + break; + } + } + return entry ? entry->value : NULL; +} + +void +dict_apply_to_all(struct dict * d, void (*func)(void *key, void *value, void *data), void *data) { + int i; + + for (i = 0; i < DICTTABLESIZE; i++) { + struct dict_entry * entry = d->buckets[i]; + while (entry) { + func(entry->key, entry->value, data); + entry = entry->next; + } + } +} + +/*****************************************************************************/ + +unsigned int +dict_key2hash_string(void * key) { + const char * s = (const char *)key; + unsigned int total = 0, shift = 0; + + while (*s) { + total = total ^ ((*s) << shift); + shift += 5; + if (shift > 24) shift -= 24; + s++; + } + return total; +} + +int +dict_key_cmp_string(void * key1, void * key2) { + return strcmp((const char *)key1, (const char *)key2); +} + +unsigned int +dict_key2hash_int(void * key) { + return (unsigned int)key; +} + +int +dict_key_cmp_int(void * key1, void * key2) { + return key1 - key2; +} + @@ -0,0 +1,18 @@ +/* + Dictionary based on code by Morten Eriksen <mortene@sim.no>. +*/ + +struct dict; + +extern struct dict * dict_init(unsigned int (*key2hash)(void *), + int (*key_cmp)(void *, void *)); +extern void dict_clear(struct dict * d); +extern int dict_enter(struct dict * d, void * key, void * value); +extern void * dict_find_entry(struct dict * d, void * key); +extern void dict_apply_to_all(struct dict * d, + void (*func)(void *key, void *value, void *data), void *data); + +extern unsigned int dict_key2hash_string(void * key); +extern int dict_key_cmp_string(void * key1, void * key2); +extern unsigned int dict_key2hash_int(void * key); +extern int dict_key_cmp_int(void * key1, void * key2); @@ -21,8 +21,7 @@ #include "ltrace.h" #include "elf.h" -#include "options.h" -#include "output.h" +#include "debug.h" static void do_init_elf(struct ltelf *lte, const char *filename); static void do_close_elf(struct ltelf *lte); @@ -42,9 +41,7 @@ static void do_init_elf(struct ltelf *lte, const char *filename) { struct stat sbuf; - if (opt_d > 0) { - output_line(0, "Reading ELF from %s...", filename); - } + debug(1, "Reading ELF from %s...", filename); lte->fd = open(filename, O_RDONLY); if (lte->fd == -1) { @@ -137,11 +134,9 @@ do_load_elf_symtab(struct ltelf *lte) { } } - if (opt_d > 1) { - output_line(0, "symtab: 0x%08x", (unsigned)lte->symtab); - output_line(0, "symtab_len: %lu", lte->symtab_len); - output_line(0, "strtab: 0x%08x", (unsigned)lte->strtab); - } + debug(2, "symtab: 0x%08x", (unsigned)lte->symtab); + debug(2, "symtab_len: %lu", lte->symtab_len); + debug(2, "strtab: 0x%08x", (unsigned)lte->strtab); } static void @@ -165,14 +160,9 @@ add_library_symbol( library_symbols->name = <e->strtab[lte->symtab[i].st_name]; library_symbols->next = tmp; - if (opt_d > 1) { - output_line( - 0, - "addr: 0x%08x, symbol: \"%s\"", + debug(2, "addr: 0x%08x, symbol: \"%s\"", (unsigned)lte->symtab[i].st_value, - <e->strtab[lte->symtab[i].st_name] - ); - } + <e->strtab[lte->symtab[i].st_name]); } /* diff --git a/execute_program.c b/execute_program.c index 0306678..6efc03c 100644 --- a/execute_program.c +++ b/execute_program.c @@ -13,40 +13,9 @@ #include "ltrace.h" #include "options.h" -#include "output.h" +#include "debug.h" #include "sysdep.h" -static void change_uid(struct process * proc); - -void -execute_program(struct process * sp, char **argv) { - pid_t pid; - - if (opt_d) { - output_line(0, "Executing `%s'...", sp->filename); - } - - pid = fork(); - if (pid<0) { - perror("ltrace: fork"); - exit(1); - } else if (!pid) { /* child */ - change_uid(sp); - 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; -} - static void change_uid(struct process * proc) { uid_t run_uid, run_euid; @@ -97,3 +66,28 @@ change_uid(struct process * proc) { } } } + +void +execute_program(struct process * sp, char **argv) { + pid_t pid; + + debug(1, "Executing `%s'...", sp->filename); + + pid = fork(); + if (pid<0) { + perror("ltrace: fork"); + exit(1); + } else if (!pid) { /* child */ + change_uid(sp); + trace_me(); + execvp(sp->filename, argv); + fprintf(stderr, "Can't execute `%s': %s\n", sp->filename, strerror(errno)); + exit(1); + } + + debug(1, "PID=%d", pid); + + sp->pid = pid; + + return; +} @@ -15,6 +15,7 @@ #include "output.h" #include "read_config_file.h" #include "options.h" +#include "debug.h" #ifndef SYSCONFDIR #define SYSCONFDIR "/etc" @@ -42,9 +43,7 @@ signal_alarm(int sig) { } tmp2 = tmp2->next; } - if (opt_d>1) { - output_line(0,"Sending SIGSTOP to process %u\n",tmp->pid); - } + debug(2,"Sending SIGSTOP to process %u\n",tmp->pid); kill(tmp->pid, SIGSTOP); tmp = tmp->next; } @@ -53,18 +52,14 @@ signal_alarm(int sig) { static void signal_exit(int sig) { exiting=1; - if (opt_d) { - output_line(0,"Received interrupt signal; exiting..."); - } + debug(1,"Received interrupt signal; exiting..."); signal(SIGINT,SIG_IGN); signal(SIGTERM,SIG_IGN); signal(SIGALRM,signal_alarm); if (opt_p) { struct opt_p_t * tmp = opt_p; while(tmp) { - if (opt_d>1) { - output_line(0,"Sending SIGSTOP to process %u\n",tmp->pid); - } + debug(2,"Sending SIGSTOP to process %u\n",tmp->pid); kill(tmp->pid, SIGSTOP); tmp = tmp->next; } @@ -99,10 +94,10 @@ main(int argc, char **argv) { strcat(path, "/.ltrace.conf"); read_config_file(path); } - if (opt_d && opt_e) { + if (opt_e) { struct opt_e_t * tmp = opt_e; while(tmp) { - printf("Option -e: %s\n", tmp->name); + debug(1,"Option -e: %s\n", tmp->name); tmp = tmp->next; } } @@ -5,6 +5,7 @@ #include <stdio.h> #include "defs.h" +#include "dict.h" /* BREAKPOINT_LENGTH is defined in "sysdep.h" */ #include "sysdep.h" @@ -76,6 +77,7 @@ struct callstack_element { struct process { char * filename; pid_t pid; + struct dict * breakpoints; int breakpoints_enabled; /* -1:not enabled yet, 0:disabled, 1:enabled */ int callstack_depth; @@ -3,7 +3,7 @@ #endif #ifndef VERSION -# define VERSION "0.3.26" +# define VERSION "0.3.27" #endif #include <string.h> @@ -23,6 +23,7 @@ open_program(char * filename) { } proc->filename = filename; proc->pid = 0; + proc->breakpoints = NULL; proc->breakpoints_enabled = -1; proc->callstack_depth = 0; proc->breakpoint_being_enabled = NULL; diff --git a/process_event.c b/process_event.c index 53012f4..e314c25 100644 --- a/process_event.c +++ b/process_event.c @@ -13,6 +13,7 @@ #include "output.h" #include "options.h" #include "elf.h" +#include "debug.h" #ifdef __powerpc__ #include <sys/ptrace.h> @@ -34,44 +35,30 @@ void process_event(struct event * event) { switch (event->thing) { case LT_EV_NONE: - if (opt_d>0) { - output_line(0, "event: none"); - } + debug(1, "event: none"); return; case LT_EV_SIGNAL: - if (opt_d>0) { - output_line(0, "event: signal (%d)", event->e_un.signum); - } + debug(1, "event: signal (%d)", event->e_un.signum); process_signal(event); return; case LT_EV_EXIT: - if (opt_d>0) { - output_line(0, "event: exit (%d)", event->e_un.ret_val); - } + debug(1, "event: exit (%d)", event->e_un.ret_val); process_exit(event); return; case LT_EV_EXIT_SIGNAL: - if (opt_d>0) { - output_line(0, "event: exit signal (%d)", event->e_un.signum); - } + debug(1, "event: exit signal (%d)", event->e_un.signum); process_exit_signal(event); return; case LT_EV_SYSCALL: - if (opt_d>0) { - output_line(0, "event: syscall (%d)", event->e_un.sysnum); - } + debug(1, "event: syscall (%d)", event->e_un.sysnum); process_syscall(event); return; case LT_EV_SYSRET: - if (opt_d>0) { - output_line(0, "event: sysret (%d)", event->e_un.sysnum); - } + debug(1, "event: sysret (%d)", event->e_un.sysnum); process_sysret(event); return; case LT_EV_BREAKPOINT: - if (opt_d>0) { - output_line(0, "event: breakpoint"); - } + debug(1, "event: breakpoint"); process_breakpoint(event); return; default: @@ -144,9 +131,7 @@ static void remove_proc(struct process * proc) { struct process *tmp, *tmp2; - if (opt_d) { - output_line(0,"Removing pid %u\n", proc->pid); - } + debug(1, "Removing pid %u\n", proc->pid); if (list_of_processes == proc) { tmp = list_of_processes; @@ -215,9 +200,7 @@ process_breakpoint(struct event * event) { struct library_symbol * tmp; int i,j; - if (opt_d>1) { - output_line(0,"event: breakpoint (0x%08x)", event->e_un.brk_addr); - } + debug(2, "event: breakpoint (0x%08x)", event->e_un.brk_addr); if (event->proc->breakpoint_being_enabled) { /* Reinsert breakpoint */ continue_enabling_breakpoint(event->proc->pid, event->proc->breakpoint_being_enabled); @@ -230,7 +213,7 @@ process_breakpoint(struct event * event) { #ifdef __powerpc__ unsigned long a; unsigned long addr = event->proc->callstack[i].c_un.libfunc->enter_addr; - struct breakpoint *sbp = dict_find_entry(event->proc, addr); + struct breakpoint *sbp = address2bpstruct(event->proc, addr); unsigned char break_insn[] = BREAKPOINT_VALUE; /* diff --git a/read_config_file.c b/read_config_file.c index 931d9cf..2ba9099 100644 --- a/read_config_file.c +++ b/read_config_file.c @@ -8,8 +8,8 @@ #include "ltrace.h" #include "read_config_file.h" -#include "options.h" #include "output.h" +#include "debug.h" /* * "void" ARGTYPE_VOID @@ -104,20 +104,14 @@ process_line (char * buf) { int i; line_no++; - if (opt_d>2) { - output_line(0, "Reading line %d of `%s'", line_no, filename); - } + debug(3, "Reading line %d of `%s'", line_no, filename); eat_spaces(&str); fun.return_type = str2type(&str); if (fun.return_type==ARGTYPE_UNKNOWN) { - if (opt_d>2) { - output_line(0, " Skipping line %d", line_no); - } + debug(3, " Skipping line %d", line_no); return NULL; } - if (opt_d>3) { - output_line(0, " return_type = %d", fun.return_type); - } + debug(4, " return_type = %d", fun.return_type); eat_spaces(&str); tmp = start_of_arg_sig(str); if (!tmp) { @@ -127,9 +121,7 @@ process_line (char * buf) { *tmp = '\0'; fun.name = strdup(str); str = tmp+1; - if (opt_d>2) { - output_line(0, " name = %s", fun.name); - } + debug(3, " name = %s", fun.name); fun.params_right = 0; for(i=0; i<MAX_ARGS; i++) { eat_spaces(&str); @@ -171,9 +163,7 @@ read_config_file(char * file) { filename = file; - if (opt_d) { - output_line(0, "Reading config file `%s'...", filename); - } + debug(1, "Reading config file `%s'...", filename); stream = fopen(filename, "r"); if (!stream) { @@ -184,9 +174,7 @@ read_config_file(char * file) { struct function * tmp = process_line(buf); if (tmp) { - if (opt_d > 1) { - output_line(0, "New function: `%s'", tmp->name); - } + debug(2, "New function: `%s'", tmp->name); tmp->next = list_of_functions; list_of_functions = tmp; } diff --git a/wait_for_something.c b/wait_for_something.c index 8a471b2..aa1372f 100644 --- a/wait_for_something.c +++ b/wait_for_something.c @@ -12,7 +12,7 @@ #include "ltrace.h" #include "options.h" -#include "output.h" +#include "debug.h" static struct event event; @@ -27,22 +27,16 @@ wait_for_something(void) { int tmp; if (!list_of_processes) { - if (opt_d) { - output_line(0, "No more children"); - } + debug(1, "No more children"); exit(0); } pid = wait(&status); if (pid==-1) { if (errno==ECHILD) { - if (opt_d) { - output_line(0, "No more children"); - } + debug(1, "No more children"); exit(0); } else if (errno==EINTR) { - if (opt_d) { - output_line(0, "wait received EINTR ?"); - } + debug(1, "wait received EINTR ?"); event.thing = LT_EV_NONE; return &event; } @@ -55,9 +49,7 @@ wait_for_something(void) { exit(1); } event.proc->instruction_pointer = NULL; - if (opt_d>2) { - output_line(0,"signal from pid %u", pid); - } + debug(3, "signal from pid %u", pid); if (event.proc->breakpoints_enabled == -1) { enable_all_breakpoints(event.proc); event.thing = LT_EV_NONE; |