From 59749d048d9e452f049f9151735b5256756919c3 Mon Sep 17 00:00:00 2001 From: Anas Nashif Date: Tue, 13 Nov 2012 07:28:12 -0800 Subject: [PATCH 1/1] Imported Upstream version 0.5.3 --- BUGS | 6 + COPYING | 340 +++++ ChangeLog | 539 ++++++++ INSTALL | 19 + Makefile.in | 74 ++ README | 92 ++ TODO | 36 + VERSION | 1 + aclocal.m4 | 833 +++++++++++++ breakpoints.c | 230 ++++ common.h | 253 ++++ configure | 157 +++ debian/changelog | 652 ++++++++++ debian/compat | 1 + debian/control.in | 23 + debian/copyright | 39 + debian/rules | 7 + debug.c | 112 ++ debug.h | 17 + defs.h | 18 + demangle.c | 44 + demangle.h | 12 + dict.c | 215 ++++ dict.h | 20 + display_args.c | 460 +++++++ elf.c | 619 ++++++++++ elf.h | 49 + etc/ltrace.conf | 604 +++++++++ execute_program.c | 91 ++ handle_event.c | 696 +++++++++++ libltrace.c | 154 +++ ltrace.1 | 206 ++++ ltrace.h | 38 + ltrace.spec | 164 +++ main.c | 37 + mkdist | 19 + options.c | 431 +++++++ options.h | 55 + output.c | 303 +++++ output.h | 3 + proc.c | 65 + read_config_file.c | 680 ++++++++++ read_config_file.h | 1 + summary.c | 86 ++ sysdeps/README | 32 + sysdeps/linux-gnu/Makefile | 60 + sysdeps/linux-gnu/README | 13 + sysdeps/linux-gnu/alpha/Makefile | 10 + sysdeps/linux-gnu/alpha/arch.h | 8 + sysdeps/linux-gnu/alpha/plt.c | 12 + sysdeps/linux-gnu/alpha/ptrace.h | 1 + sysdeps/linux-gnu/alpha/regs.c | 40 + sysdeps/linux-gnu/alpha/signalent.h | 32 + sysdeps/linux-gnu/alpha/syscallent.h | 439 +++++++ sysdeps/linux-gnu/alpha/trace.c | 75 ++ sysdeps/linux-gnu/arch_mksyscallent | 42 + sysdeps/linux-gnu/arm/Makefile | 10 + sysdeps/linux-gnu/arm/arch.h | 11 + sysdeps/linux-gnu/arm/arch_syscallent.h | 6 + sysdeps/linux-gnu/arm/breakpoint.c | 77 ++ sysdeps/linux-gnu/arm/plt.c | 12 + sysdeps/linux-gnu/arm/ptrace.h | 9 + sysdeps/linux-gnu/arm/regs.c | 51 + sysdeps/linux-gnu/arm/signalent.h | 33 + sysdeps/linux-gnu/arm/syscallent.h | 322 +++++ sysdeps/linux-gnu/arm/trace.c | 131 ++ sysdeps/linux-gnu/breakpoint.c | 86 ++ sysdeps/linux-gnu/events.c | 161 +++ sysdeps/linux-gnu/i386/Makefile | 10 + sysdeps/linux-gnu/i386/arch.h | 6 + sysdeps/linux-gnu/i386/plt.c | 12 + sysdeps/linux-gnu/i386/ptrace.h | 1 + sysdeps/linux-gnu/i386/regs.c | 40 + sysdeps/linux-gnu/i386/signalent.h | 32 + sysdeps/linux-gnu/i386/syscallent.h | 317 +++++ sysdeps/linux-gnu/i386/trace.c | 85 ++ sysdeps/linux-gnu/ia64/Makefile | 10 + sysdeps/linux-gnu/ia64/arch.h | 13 + sysdeps/linux-gnu/ia64/breakpoint.c | 212 ++++ sysdeps/linux-gnu/ia64/plt.c | 46 + sysdeps/linux-gnu/ia64/ptrace.h | 1 + sysdeps/linux-gnu/ia64/regs.c | 51 + sysdeps/linux-gnu/ia64/signalent.h | 32 + sysdeps/linux-gnu/ia64/syscallent.h | 1303 ++++++++++++++++++++ sysdeps/linux-gnu/ia64/trace.c | 268 ++++ sysdeps/linux-gnu/m68k/Makefile | 10 + sysdeps/linux-gnu/m68k/arch.h | 6 + sysdeps/linux-gnu/m68k/plt.c | 13 + sysdeps/linux-gnu/m68k/ptrace.h | 1 + sysdeps/linux-gnu/m68k/regs.c | 40 + sysdeps/linux-gnu/m68k/signalent.h | 32 + sysdeps/linux-gnu/m68k/syscallent.h | 282 +++++ sysdeps/linux-gnu/m68k/trace.c | 89 ++ sysdeps/linux-gnu/mipsel/Doxyfile | 275 +++++ sysdeps/linux-gnu/mipsel/Makefile | 22 + sysdeps/linux-gnu/mipsel/arch.h | 9 + sysdeps/linux-gnu/mipsel/mipsel.h | 11 + sysdeps/linux-gnu/mipsel/plt.c | 72 ++ sysdeps/linux-gnu/mipsel/ptrace.h | 1 + sysdeps/linux-gnu/mipsel/regs.c | 76 ++ sysdeps/linux-gnu/mipsel/signalent.h | 32 + sysdeps/linux-gnu/mipsel/syscallent.h | 241 ++++ sysdeps/linux-gnu/mipsel/trace.c | 167 +++ sysdeps/linux-gnu/mksignalent | 33 + sysdeps/linux-gnu/mksyscallent | 45 + sysdeps/linux-gnu/mksyscallent_s390 | 38 + sysdeps/linux-gnu/ppc/Makefile | 10 + sysdeps/linux-gnu/ppc/arch.h | 24 + sysdeps/linux-gnu/ppc/plt.c | 54 + sysdeps/linux-gnu/ppc/ptrace.h | 1 + sysdeps/linux-gnu/ppc/regs.c | 47 + sysdeps/linux-gnu/ppc/signalent.h | 32 + sysdeps/linux-gnu/ppc/syscallent.h | 272 ++++ sysdeps/linux-gnu/ppc/trace.c | 155 +++ sysdeps/linux-gnu/proc.c | 36 + sysdeps/linux-gnu/s390/Makefile | 13 + sysdeps/linux-gnu/s390/arch.h | 18 + sysdeps/linux-gnu/s390/plt.c | 12 + sysdeps/linux-gnu/s390/ptrace.h | 1 + sysdeps/linux-gnu/s390/regs.c | 75 ++ sysdeps/linux-gnu/s390/signalent.h | 33 + sysdeps/linux-gnu/s390/signalent1.h | 1 + sysdeps/linux-gnu/s390/syscallent.h | 5 + sysdeps/linux-gnu/s390/syscallent1.h | 1 + sysdeps/linux-gnu/s390/syscalls31.h | 310 +++++ sysdeps/linux-gnu/s390/syscalls64.h | 310 +++++ sysdeps/linux-gnu/s390/trace.c | 198 +++ sysdeps/linux-gnu/sparc/Makefile | 9 + sysdeps/linux-gnu/sparc/arch.h | 8 + sysdeps/linux-gnu/sparc/plt.c | 12 + sysdeps/linux-gnu/sparc/ptrace.h | 21 + sysdeps/linux-gnu/sparc/regs.c | 49 + sysdeps/linux-gnu/sparc/signalent.h | 32 + sysdeps/linux-gnu/sparc/syscallent.h | 284 +++++ sysdeps/linux-gnu/sparc/trace.c | 81 ++ sysdeps/linux-gnu/trace.c | 193 +++ sysdeps/linux-gnu/x86_64/Makefile | 9 + sysdeps/linux-gnu/x86_64/arch.h | 12 + sysdeps/linux-gnu/x86_64/ffcheck.c | 0 sysdeps/linux-gnu/x86_64/plt.c | 12 + sysdeps/linux-gnu/x86_64/ptrace.h | 1 + sysdeps/linux-gnu/x86_64/regs.c | 54 + sysdeps/linux-gnu/x86_64/signalent.h | 32 + sysdeps/linux-gnu/x86_64/signalent1.h | 1 + sysdeps/linux-gnu/x86_64/syscallent.h | 256 ++++ sysdeps/linux-gnu/x86_64/syscallent1.h | 1 + sysdeps/linux-gnu/x86_64/trace.c | 144 +++ testsuite/Makefile | 71 ++ testsuite/README | 244 ++++ testsuite/config/unix.exp | 1 + testsuite/lib/compiler.c | 58 + testsuite/lib/compiler.cc | 45 + testsuite/lib/ltrace.exp | 279 +++++ testsuite/ltrace.main/Makefile | 33 + testsuite/ltrace.main/main-internal-1.c | 8 + testsuite/ltrace.main/main-internal.c | 19 + testsuite/ltrace.main/main-internal.exp | 33 + testsuite/ltrace.main/main-lib.c | 7 + testsuite/ltrace.main/main.c | 21 + testsuite/ltrace.main/main.exp | 39 + testsuite/ltrace.main/parameters-lib.c | 117 ++ testsuite/ltrace.main/parameters.c | 120 ++ testsuite/ltrace.main/parameters.conf | 15 + testsuite/ltrace.main/parameters.exp | 72 ++ testsuite/ltrace.main/signals.c | 48 + testsuite/ltrace.main/signals.exp | 39 + testsuite/ltrace.main/system_calls.c | 68 + testsuite/ltrace.main/system_calls.exp | 67 + testsuite/ltrace.minor/Makefile | 36 + testsuite/ltrace.minor/attach-process.c | 16 + testsuite/ltrace.minor/attach-process.exp | 38 + testsuite/ltrace.minor/count-record.c | 51 + testsuite/ltrace.minor/count-record.exp | 77 ++ testsuite/ltrace.minor/demangle-lib.cpp | 97 ++ testsuite/ltrace.minor/demangle.cpp | 121 ++ testsuite/ltrace.minor/demangle.exp | 63 + testsuite/ltrace.minor/demangle.h | 36 + testsuite/ltrace.minor/print-instruction-pointer.c | 11 + .../ltrace.minor/print-instruction-pointer.exp | 42 + testsuite/ltrace.minor/time-record-T.exp | 84 ++ testsuite/ltrace.minor/time-record-tt.exp | 107 ++ testsuite/ltrace.minor/time-record-ttt.exp | 112 ++ testsuite/ltrace.minor/time-record.c | 23 + testsuite/ltrace.minor/trace-clone.c | 38 + testsuite/ltrace.minor/trace-clone.exp | 44 + testsuite/ltrace.minor/trace-exec.c | 8 + testsuite/ltrace.minor/trace-exec.exp | 45 + testsuite/ltrace.minor/trace-exec1.c | 6 + testsuite/ltrace.minor/trace-fork.c | 33 + testsuite/ltrace.minor/trace-fork.exp | 40 + testsuite/ltrace.torture/Makefile | 33 + testsuite/ltrace.torture/ia64-sigill.exp | 33 + testsuite/ltrace.torture/ia64-sigill.s | 43 + testsuite/ltrace.torture/signals.c | 44 + testsuite/ltrace.torture/signals.exp | 37 + testsuite/run-my-tests.sh | 43 + 196 files changed, 19692 insertions(+) create mode 100644 BUGS create mode 100644 COPYING create mode 100644 ChangeLog create mode 100644 INSTALL create mode 100644 Makefile.in create mode 100644 README create mode 100644 TODO create mode 100644 VERSION create mode 100644 aclocal.m4 create mode 100644 breakpoints.c create mode 100644 common.h create mode 100755 configure create mode 100644 debian/changelog create mode 100644 debian/compat create mode 100644 debian/control.in create mode 100644 debian/copyright create mode 100755 debian/rules create mode 100644 debug.c create mode 100644 debug.h create mode 100644 defs.h create mode 100644 demangle.c create mode 100644 demangle.h create mode 100644 dict.c create mode 100644 dict.h create mode 100644 display_args.c create mode 100644 elf.c create mode 100644 elf.h create mode 100644 etc/ltrace.conf create mode 100644 execute_program.c create mode 100644 handle_event.c create mode 100644 libltrace.c create mode 100644 ltrace.1 create mode 100644 ltrace.h create mode 100644 ltrace.spec create mode 100644 main.c create mode 100755 mkdist create mode 100644 options.c create mode 100644 options.h create mode 100644 output.c create mode 100644 output.h create mode 100644 proc.c create mode 100644 read_config_file.c create mode 100644 read_config_file.h create mode 100644 summary.c create mode 100644 sysdeps/README create mode 100644 sysdeps/linux-gnu/Makefile create mode 100644 sysdeps/linux-gnu/README create mode 100644 sysdeps/linux-gnu/alpha/Makefile create mode 100644 sysdeps/linux-gnu/alpha/arch.h create mode 100644 sysdeps/linux-gnu/alpha/plt.c create mode 100644 sysdeps/linux-gnu/alpha/ptrace.h create mode 100644 sysdeps/linux-gnu/alpha/regs.c create mode 100644 sysdeps/linux-gnu/alpha/signalent.h create mode 100644 sysdeps/linux-gnu/alpha/syscallent.h create mode 100644 sysdeps/linux-gnu/alpha/trace.c create mode 100644 sysdeps/linux-gnu/arch_mksyscallent create mode 100644 sysdeps/linux-gnu/arm/Makefile create mode 100644 sysdeps/linux-gnu/arm/arch.h create mode 100644 sysdeps/linux-gnu/arm/arch_syscallent.h create mode 100644 sysdeps/linux-gnu/arm/breakpoint.c create mode 100644 sysdeps/linux-gnu/arm/plt.c create mode 100644 sysdeps/linux-gnu/arm/ptrace.h create mode 100644 sysdeps/linux-gnu/arm/regs.c create mode 100644 sysdeps/linux-gnu/arm/signalent.h create mode 100644 sysdeps/linux-gnu/arm/syscallent.h create mode 100644 sysdeps/linux-gnu/arm/trace.c create mode 100644 sysdeps/linux-gnu/breakpoint.c create mode 100644 sysdeps/linux-gnu/events.c create mode 100644 sysdeps/linux-gnu/i386/Makefile create mode 100644 sysdeps/linux-gnu/i386/arch.h create mode 100644 sysdeps/linux-gnu/i386/plt.c create mode 100644 sysdeps/linux-gnu/i386/ptrace.h create mode 100644 sysdeps/linux-gnu/i386/regs.c create mode 100644 sysdeps/linux-gnu/i386/signalent.h create mode 100644 sysdeps/linux-gnu/i386/syscallent.h create mode 100644 sysdeps/linux-gnu/i386/trace.c create mode 100644 sysdeps/linux-gnu/ia64/Makefile create mode 100644 sysdeps/linux-gnu/ia64/arch.h create mode 100644 sysdeps/linux-gnu/ia64/breakpoint.c create mode 100644 sysdeps/linux-gnu/ia64/plt.c create mode 100644 sysdeps/linux-gnu/ia64/ptrace.h create mode 100644 sysdeps/linux-gnu/ia64/regs.c create mode 100644 sysdeps/linux-gnu/ia64/signalent.h create mode 100644 sysdeps/linux-gnu/ia64/syscallent.h create mode 100644 sysdeps/linux-gnu/ia64/trace.c create mode 100644 sysdeps/linux-gnu/m68k/Makefile create mode 100644 sysdeps/linux-gnu/m68k/arch.h create mode 100644 sysdeps/linux-gnu/m68k/plt.c create mode 100644 sysdeps/linux-gnu/m68k/ptrace.h create mode 100644 sysdeps/linux-gnu/m68k/regs.c create mode 100644 sysdeps/linux-gnu/m68k/signalent.h create mode 100644 sysdeps/linux-gnu/m68k/syscallent.h create mode 100644 sysdeps/linux-gnu/m68k/trace.c create mode 100644 sysdeps/linux-gnu/mipsel/Doxyfile create mode 100644 sysdeps/linux-gnu/mipsel/Makefile create mode 100644 sysdeps/linux-gnu/mipsel/arch.h create mode 100644 sysdeps/linux-gnu/mipsel/mipsel.h create mode 100644 sysdeps/linux-gnu/mipsel/plt.c create mode 100644 sysdeps/linux-gnu/mipsel/ptrace.h create mode 100644 sysdeps/linux-gnu/mipsel/regs.c create mode 100644 sysdeps/linux-gnu/mipsel/signalent.h create mode 100644 sysdeps/linux-gnu/mipsel/syscallent.h create mode 100644 sysdeps/linux-gnu/mipsel/trace.c create mode 100755 sysdeps/linux-gnu/mksignalent create mode 100755 sysdeps/linux-gnu/mksyscallent create mode 100644 sysdeps/linux-gnu/mksyscallent_s390 create mode 100644 sysdeps/linux-gnu/ppc/Makefile create mode 100644 sysdeps/linux-gnu/ppc/arch.h create mode 100644 sysdeps/linux-gnu/ppc/plt.c create mode 100644 sysdeps/linux-gnu/ppc/ptrace.h create mode 100644 sysdeps/linux-gnu/ppc/regs.c create mode 100644 sysdeps/linux-gnu/ppc/signalent.h create mode 100644 sysdeps/linux-gnu/ppc/syscallent.h create mode 100644 sysdeps/linux-gnu/ppc/trace.c create mode 100644 sysdeps/linux-gnu/proc.c create mode 100644 sysdeps/linux-gnu/s390/Makefile create mode 100644 sysdeps/linux-gnu/s390/arch.h create mode 100644 sysdeps/linux-gnu/s390/plt.c create mode 100644 sysdeps/linux-gnu/s390/ptrace.h create mode 100644 sysdeps/linux-gnu/s390/regs.c create mode 100644 sysdeps/linux-gnu/s390/signalent.h create mode 100644 sysdeps/linux-gnu/s390/signalent1.h create mode 100644 sysdeps/linux-gnu/s390/syscallent.h create mode 100644 sysdeps/linux-gnu/s390/syscallent1.h create mode 100644 sysdeps/linux-gnu/s390/syscalls31.h create mode 100644 sysdeps/linux-gnu/s390/syscalls64.h create mode 100644 sysdeps/linux-gnu/s390/trace.c create mode 100644 sysdeps/linux-gnu/sparc/Makefile create mode 100644 sysdeps/linux-gnu/sparc/arch.h create mode 100644 sysdeps/linux-gnu/sparc/plt.c create mode 100644 sysdeps/linux-gnu/sparc/ptrace.h create mode 100644 sysdeps/linux-gnu/sparc/regs.c create mode 100644 sysdeps/linux-gnu/sparc/signalent.h create mode 100644 sysdeps/linux-gnu/sparc/syscallent.h create mode 100644 sysdeps/linux-gnu/sparc/trace.c create mode 100644 sysdeps/linux-gnu/trace.c create mode 100644 sysdeps/linux-gnu/x86_64/Makefile create mode 100644 sysdeps/linux-gnu/x86_64/arch.h create mode 100644 sysdeps/linux-gnu/x86_64/ffcheck.c create mode 100644 sysdeps/linux-gnu/x86_64/plt.c create mode 100644 sysdeps/linux-gnu/x86_64/ptrace.h create mode 100644 sysdeps/linux-gnu/x86_64/regs.c create mode 100644 sysdeps/linux-gnu/x86_64/signalent.h create mode 100644 sysdeps/linux-gnu/x86_64/signalent1.h create mode 100644 sysdeps/linux-gnu/x86_64/syscallent.h create mode 100644 sysdeps/linux-gnu/x86_64/syscallent1.h create mode 100644 sysdeps/linux-gnu/x86_64/trace.c create mode 100644 testsuite/Makefile create mode 100644 testsuite/README create mode 100644 testsuite/config/unix.exp create mode 100644 testsuite/lib/compiler.c create mode 100644 testsuite/lib/compiler.cc create mode 100644 testsuite/lib/ltrace.exp create mode 100644 testsuite/ltrace.main/Makefile create mode 100644 testsuite/ltrace.main/main-internal-1.c create mode 100644 testsuite/ltrace.main/main-internal.c create mode 100644 testsuite/ltrace.main/main-internal.exp create mode 100644 testsuite/ltrace.main/main-lib.c create mode 100644 testsuite/ltrace.main/main.c create mode 100644 testsuite/ltrace.main/main.exp create mode 100644 testsuite/ltrace.main/parameters-lib.c create mode 100644 testsuite/ltrace.main/parameters.c create mode 100644 testsuite/ltrace.main/parameters.conf create mode 100644 testsuite/ltrace.main/parameters.exp create mode 100644 testsuite/ltrace.main/signals.c create mode 100644 testsuite/ltrace.main/signals.exp create mode 100644 testsuite/ltrace.main/system_calls.c create mode 100644 testsuite/ltrace.main/system_calls.exp create mode 100644 testsuite/ltrace.minor/Makefile create mode 100644 testsuite/ltrace.minor/attach-process.c create mode 100644 testsuite/ltrace.minor/attach-process.exp create mode 100644 testsuite/ltrace.minor/count-record.c create mode 100644 testsuite/ltrace.minor/count-record.exp create mode 100644 testsuite/ltrace.minor/demangle-lib.cpp create mode 100644 testsuite/ltrace.minor/demangle.cpp create mode 100644 testsuite/ltrace.minor/demangle.exp create mode 100644 testsuite/ltrace.minor/demangle.h create mode 100644 testsuite/ltrace.minor/print-instruction-pointer.c create mode 100644 testsuite/ltrace.minor/print-instruction-pointer.exp create mode 100644 testsuite/ltrace.minor/time-record-T.exp create mode 100644 testsuite/ltrace.minor/time-record-tt.exp create mode 100644 testsuite/ltrace.minor/time-record-ttt.exp create mode 100644 testsuite/ltrace.minor/time-record.c create mode 100644 testsuite/ltrace.minor/trace-clone.c create mode 100644 testsuite/ltrace.minor/trace-clone.exp create mode 100644 testsuite/ltrace.minor/trace-exec.c create mode 100644 testsuite/ltrace.minor/trace-exec.exp create mode 100644 testsuite/ltrace.minor/trace-exec1.c create mode 100644 testsuite/ltrace.minor/trace-fork.c create mode 100644 testsuite/ltrace.minor/trace-fork.exp create mode 100644 testsuite/ltrace.torture/Makefile create mode 100644 testsuite/ltrace.torture/ia64-sigill.exp create mode 100644 testsuite/ltrace.torture/ia64-sigill.s create mode 100644 testsuite/ltrace.torture/signals.c create mode 100644 testsuite/ltrace.torture/signals.exp create mode 100755 testsuite/run-my-tests.sh diff --git a/BUGS b/BUGS new file mode 100644 index 0000000..fd44ac0 --- /dev/null +++ b/BUGS @@ -0,0 +1,6 @@ +* Manual page is not accurate (config files...) +* Doesn't do inter-library calls (BP is in the executable's PLT) +* It lacks support for several Linux archs, and many operating systems +* 2008-12-29: this line in config file does not work (2nd argument not used): + string setlocale(enum(LC_ALL=6), string); +* 2009-04-07 doesn't work with threads (processes sharing memory) diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..3912109 --- /dev/null +++ b/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..49b785f --- /dev/null +++ b/ChangeLog @@ -0,0 +1,539 @@ +2009-07-25 Juan Cespedes + + * New release 0.5.3 + * Created "libltrace.a" and a simple main program that calls it + * Added support for callbacks to libltrace + * Got rid of GNU's Autoconf stuff + * Make it work again in sparc with new kernel headers + +2009-05-21 Juan Cespedes + + * Release version 0.5.2 + * new fork() and clone() approach: + + used PTRACE_O_TRACE{FORK,VFORK,CLONE} to trace newly created + processes instead of figuring it out whether a given syscall + would create another process or not + That way, new processes are always traced from the very beginning + * Use PTRACE_O_TRACEEXEC to check if a process has called exec() + +2009-05-07 Juan Cespedes + + * clean-up of structs Process, Breakpoint, Function and Event + +2009-04-07 Juan Cespedes + + * Improved documentation + * Cleaning up of "struct options" + * wait_for_something -> sysdeps/linux/events.c:next_event() + * wait for new children to stop instead of assuming they have stopped + +2009-02-11 Juan Cespedes + + * Fixed bug present since the first version (!) of ltrace, + which caused many programs to segfault when a signal is received: + + When a breakpoint is hit, and we need to continue with it, we: + 1) remove the breakpoint + 2) order a SINGLESTEP + 3) when control comes back, set the breakpoint again + 4) let the process continue + + The problem came when a signal is received in the middle + of all this (specifically, between 2) and 3)). + If this is so, we treat the signal "in the usual way", + it is, at the end we issue a "CONTINUE" instead of the + needed SINGLESTEP. + +2008-12-10 Juan Cespedes + + * summary.c: Fix "ltrace -o -c" + * mkdist: rm -rf autom4te.cache + * debian/control.ini: re-added armel and armeb + +2008-12-10 Juan Cespedes + + * Release version 0.5.1 + +2008-12-10 Juan Cespedes + + * Patches from Anderson Lizardo and Riku Voipio: + + Add generic support for arm targets + + Save funtion arguments on arm + + Add thumb instruction support + + Add basic arm/eabi support + + fix exec() testcase cleanup + + fix memory corruption in clone() test + + fix tracing child with "-p" option + +2008-02-27 Luis Machado + + * sysdeps/linux-gnu/ppc/trace.c (arch_umovelong): New function. + * sysdeps/linux-gnu/ppc/regs.c (get_instruction): New function. + (get_count_register): New function. + * sysdeps/linux-gnu/ppc/arch.h (ARCH_HAVE_UMOVELONG): New define. + * sysdeps/linux-gnu/trace.c (umovelong): Create arch-specific + variant. + * ltrace.h (umovelong): Change prototype. + * process_event.c (process_breakpoint): Handle specifics of ppc32 PLT. + * display_args.c: Call umovelong with info parameter. + +2007-09-04 Juan Cespedes + + * ltrace.h: Take arg_num out of arg_type_info + * linux-gnu/*/trace.c: gimme_arg(): Add arg_num as argument + * ltrace.c: check for existence of $HOME before using it + * General: Small fixes (indentation) + +2007-08-31 Juan Cespedes + + * General: Small fixes (indentation, typos, clean-up of code) + * ltrace.c: Close output file on exit + * ltrace.c: use getenv("HOME") instead of getpwuid(geteuid())->pw_dir + * read_config_file.c, display_args.c: remove "ignore" argtype; + that's what "void" is for + * packaging/debian/: misc fixes, sync with version 0.5-2 + * etc/ltrace.conf: added more system calls + * testsuite/ltrace.minor/trace-clone.c: sleep(1) to avoid earlier + termination of process + * sysdeps/linux-gnu/trace.c: trace_pid(): reverted Petr's patch + to wait for child to stop, as it stopped following clone() + * process_event.c: Disable breakpoints before doing fork() (again!), + to make children work as expected + +2007-05-10 Petr Machata + + * Based on work of Supriya Kannery + * wait_for_something.c, process_event.c: Tracing across exec. + * sysdeps/linux-gnu/trace.c, ltrace.h: New interface was_exec. + * testsuite/ltrace.minor/trace-exec.c, + testsuite/ltrace.minor/trace-exec.exp, + testsuite/ltrace.minor/trace-exec1.c: Testcase for same. + +2007-05-09 Petr Machata + + * wait_for_something.c (wait_for_something): Interpret SIGILL, + SIGEMT and SIGSEGV as valid breakpoint signals, if instruction + pointer referes to breakpoint. + * testsuite/ltrace.torture/ia64-sigill.s, + * testsuite/ltrace.torture/ia64-sigill.exp: Testcase for same. + IA64-centric, because the only reproducer is there. + +2007-01-19 Petr Machata + + * sysdeps/linux-gnu/trace.c (trace_pid): wait for child to stop, + as indicated by ptrace documentation. + * proc.c (open_pid): start the traced child again, it will have + been stopped after trace_pid. Fixes tracing with -p. + * breakpoints.c: initialize proc->breakpoints always, don't wait + untill it might be needed. This renders a check in insert_breakpoint + superfluous. Fixes a sigsegvs experienced with -L. + +2006-12-28 Eric Vaitl + + * sysdeps/linux-gnu/mipsel/* Added mipsel support + * debug.h Added printf format attribute to debug_ + * elf.h Added mips relocation data to struct ltelf + * elf.c (do_init_elf) Read mips relocation data + * elf.c (read_elf) On the mips loop through mips_gotsym + instead of relplt_count. + * process_event.c (process_breakpoint) For the mips, + conditionally add a new breakpoint if the address of the + function changes because of lazy relocation. + * breakpoints.c (enable_all_breakpoints) For the mips, + reinsert breakpoints after the child has been started. + + +2006-11-30 Petr Machata + + * elf.c (elf_gnu_hash): renamed to private_elf_gnu_hash to avoid + conflicts with non-static version from libelf. + +2006-11-30 Petr Machata + + * elf.c (in_load_libraries): removed unused variables + bitmask_idxbits and shift. + * elf.c (do_init_elf, opd2addr): use ARCH_SUPPORTS_OPD to + determine whether to load/use .opd section + * sysdeps/linux-gnu/*/arch.h: define ARCH_SUPPORTS_OPD accordingly + * breakpoints.c (insert_breakpoint): rewrite loop to canonical for + +2006-10-13 Olaf Hering + + * options.c: fix up typo for config file + +2006-09-25 Olaf Hering + + * elf.c, elf.h : remove confilict with glibc SHT_GNU_HASH, include + elf_gnu_hash() directly, remove special casing and fix up output + specifier. + +2006-09-18 Steve Fink + + * display_args.c: store arg_num in arg_type_info + * display_args.c: support 'double' parameters + * display_args.c: fix implementation of float,double params for ia64 + * output.c, process_event.c: store arg_num in arg_type_info + * read_config_file.c: support 'double' parameters + * read_config_file.c: store arg_num in arg_type_info, and as a result, + stop using singleton objects for any of the arg_type_info's. + * read_config_file.c: improve support for struct field alignments + * read_config_file.c: count floating-point parameters to support ia64 + float parameter passing + * sysdeps/README, sysdeps/linux-gnu/*/trace.c: pass in the full + arg_type_info to gimme_arg rather than just the arg_num (necessary + for float params on some architectures) + * sysdeps/linux-gnu/ia64/trace.c: accommodate register renaming when + fetching the parameters of a function after it has returned + * sysdeps/linux-gnu/ia64/trace.c: support floating point parameters + +2006-09-15 Olaf Hering + + * Makefile.in : allow installation as non-root user, print out + some debugging information before running test suite. + * summary.c : allow compilation without USE_DEMANGLE + * sysdeps/linux-gnu/ppc/plt.c : fix warning in sym2addr + * sysdeps/linux-gnu/ia64/regs.c : fix warning when finding + instruction slot + * elf.c : fix up error created in 2006-07-26 refactor + +2006-08-14 Steve Fink + + * demangle.c: remove my_demagle_dict_clear(), remove atexit() call + for same. Avoid potential segfault as demangling uses the + dictionary. + +2006-08-07 Steve Fink + + * display_args.c, etc/ltrace.conf, ltrace.h, read_config_file.c, + testsuite/ltrace.main/parameters-lib.c, + testsuite/ltrace.main/parameters.c, + testsuite/ltrace.main/parameters.conf, + testsuite/ltrace.main/parameters.exp: Allow parameters to be + pointers to structs, which themselves can contain + (nearly) any other type, including other structs or pointers to + structs. + + +2006-08-07 Steve Fink + + * defs.h, display_args.c, etc/ltrace.conf, ltrace.1, ltrace.h, + options.c, options.h, read_config_file.c, + testsuite/ltrace.main/parameters-lib.c, + testsuite/ltrace.main/parameters.c, + testsuite/ltrace.main/parameters.conf, + testsuite/ltrace.main/parameters.exp: array arguments + +2006-08-07 Steve Fink + + * etc/ltrace.conf, read_config_file.c, + testsuite/ltrace.main/parameters-lib.c, + testsuite/ltrace.main/parameters.c, + testsuite/ltrace.main/parameters.conf, + testsuite/ltrace.main/parameters.exp: add ability to typedef + +2006-08-07 Steve Fink + + * display_args.c, etc/ltrace.conf, ltrace.h, read_config_file.c, + testsuite/ltrace.main/parameters-lib.c, + testsuite/ltrace.main/parameters.c, + testsuite/ltrace.main/parameters.conf, + testsuite/ltrace.main/parameters.exp: short, ushort and float types + +2006-08-07 Steve Fink + + * display_args.c, etc/ltrace.conf, ltrace.h, read_config_file.c, + testsuite/ltrace.main/parameters-lib.c, + testsuite/ltrace.main/parameters.c, + testsuite/ltrace.main/parameters.conf, + testsuite/ltrace.main/parameters.exp: implement enumerated parameters + +2006-08-07 Steve Fink + + * testsuite/ltrace.main/Makefile.in : update testsuite for + new parameters + * testsuite/ltrace.main/parameters-lib.c : added + * testsuite/ltrace.main/parameters.c : added + * testsuite/ltrace.main/parameters.conf : added + * testsuite/ltrace.main/parameters.exp : added + +2006-08-07 Steve Fink + + * display_args.c, etc/ltrace.conf, ltrace.h, read_config_file.c, + sysdeps/README, sysdeps/linux-gnu-trace.c : switch to passing + around values rather than argument numbers that need to be fetched + (needed for pointer params) + +2006-08-07 Steve Fink + + * display_args.c, etc/ltrace.conf, ltrace.h, read_config_file.c: + implement ignored arguments + +2006-08-07 Steve Fink + + * display_args.c, etc/ltrace.conf, ltrace.h, read_config_file.c: + implement string[argN] and string[N] parameter descriptors + +2006-08-07 Steve Fink + + * ltrace.h, output.c, read_config_file.c : use arg_type_info in + place of arg_type in order to eventually be able to record + properties along with types. + +2006-07-20 Steve Fink + + * testsuite/lib/ltrace.exp: better quoting and error detection for + ltrace_verify_output's call to grep + +2006-08-07 Steve Fink + + * ltrace.1: update bug email addr + +2006-07-26 Ian Wienand + + * elf.c: refactor opd2addr to not pass void* (fix warnings) + +2006-07-18 Petr Machata + + * elf.c: replace nonexistant elf_plt2addr with opd2addr, fix + typo, and fix WEAK symbol detection + * sysdeps/linux-gnu/ppc/arch.h: define breakpoint instruction, + its length, etc., also on ppc32 + +2006-07-18 Petr Machata + + * elf.c: support .gnu.hash ELF entry + * elf.h: likewise + +2006-07-18 Petr Machata + + * options.c: don't hardcode version number + +2006-07-18 Justin Pryzby + + * ltrace.1: make demagle clearer + +2006-07-16 Steve Fink + + * options.c: implement -F flag for alternate config file(s) + * ltrace.c: load SYSCONFDIR/ltrace.conf and ~/.ltrace.conf by default + +2006-06-19 Ian Wienand + + * sysdeps/linux-gnu/mksyscallent: update, fix for ia64 + * sysdeps/linux-gnu/i386/syscallent.h: regenerate to 2.6.17 + * sysdeps/linux-gnu/i386/signalent.h: likewise + * sysdeps/linux-gnu/arm/syscallent.h: likewise + * sysdeps/linux-gnu/arm/signalent.h: likewise + * sysdeps/linux-gnu/m68k/syscallent.h: likewise + * sysdeps/linux-gnu/m68k/signalent.h: likewise + * sysdeps/linux-gnu/ia64/syscallent.h: likewise + * sysdeps/linux-gnu/ia64/signalent.h: likewise + +2006-06-19 Heiko Carstens + + * sysdeps/linux-gnu/s390/syscalls31.h: update to 2.6.17 + * sysdeps/linux-gnu/s390/syscalls64.h: ditto + +2006-06-16 Justin Pryzby + + * ltrace.1: spelling fix + * TODO: spelling fix + +2006-06-14 Ian Wienand + + * configure.ac: Bump version to 0.5 for Paull Gillam's PPC64 + non-exec PLT patch (as merged below). + * breakpoints.c: merge + * elf.c: merge + * elf.h: merge + * ltrace.h: merge + * output.c: merge + * process_event.c: merge + * sysdeps/linux-gnu/alpha/plt.c: merge + * sysdeps/linux-gnu/arm/plt.c: merge + * sysdeps/linux-gnu/breakpoint.c: merge + * sysdeps/linux-gnu/i386/plt.c: merge + * sysdeps/linux-gnu/ia64/plt.c: merge + * sysdeps/linux-gnu/m68k/plt.c: merge + * sysdeps/linux-gnu/ppc/arch.h: merge + * sysdeps/linux-gnu/ppc/arch.h.rej: merge + * sysdeps/linux-gnu/ppc/plt.c: merge + * sysdeps/linux-gnu/s390/plt.c: merge + * sysdeps/linux-gnu/sparc/plt.c: merge + * sysdeps/linux-gnu/x86_64/plt.c: merge + + +2006-05-11 Heiko Carstens + + * sysdeps/linux-gnu/mksyscallent_s390: add + * sysdeps/linux-gnu/s390/syscalls31.h: update to 2.6.16 + * sysdeps/linux-gnu/s390/syscalls64.h: ditto + +2006-04-24 Paul Gilliam + + * elf.c: Use PLT_REINITALISATION_BP for those architectures that need + to re-initialize breakpoints after the dynamic linker has run. Also, + use value of "e_entry" for address of PLT_REINITALISATION_BP if the + target program has been stripped. + * ltrace.1: Note that fact that "-X" is only available on architectures + that need it. + * options.c: Use PLT_REINITALISATION_BP for those architectures that + need to re-initialize breakpoints after the dynamic linker has run. + * process_event.c: ditto. + * sysdeps/linux-gnu/ppc/arch.h: This is the only such architecture. + * sysdeps/linux-gnu/arm/arch.h: Delete use of PLT_REINITALISATION_BP. + * sysdeps/linux-gnu/m68k/arch.h: ditto. + * sysdeps/linux-gnu/alpha/arch.h: ditto. + * sysdeps/linux-gnu/i386/arch.h: ditto. + * sysdeps/linux-gnu/x86_64/arch.h: ditto. + * sysdeps/linux-gnu/s390/arch.h: ditto. + * sysdeps/linux-gnu/ia64/arch.h: ditto. + * sysdeps/linux-gnu/sparc/arch.h: ditto. + +2006-04-24 Paul Gilliam + + * elf.c: Adds some casts to keep a more picky version of GCC happy. + * sysdeps/linux-gnu/trace.c: ditto. + * sysdeps/linux-gnu/breakpoint.c: ditto. + * ltrace.h: ditto. + +2006-04-24 Paul Gilliam + + * summery.c: Correct a typo prevented the inclusion of "demangle.h". + +2006-03-16 Ian Wienand + + * testsuite/ltrace.minor/trace-clone.c: use __clone2() for IA64 + clone test + +2006-03=13 Paul Gilliam + + * Makefile.in: Add targets to support testsuite, including 'check'. + * confiure.ac: Add testsuite Makefile's to AC_OUTPUT. + * testsuite: Add dejagnu base testsuite. + * testsuite/config/: Add + * testsuite/config/unix.exp: Add + * testsuite/lib/: Add + * testsuite/lib/compiler.c: Add + * testsuite/lib/compiler.cc: Add + * testsuite/lib/ltrace.exp: Add + * testsuite/ltrace.main/: Add + * testsuite/ltrace.main/main.c: Add + * testsuite/ltrace.main/main.exp: Add + * testsuite/ltrace.main/main-internal-1.c: Add + * testsuite/ltrace.main/main-internal.c: Add + * testsuite/ltrace.main/main-internal.exp: Add + * testsuite/ltrace.main/main-lib.c: Add + * testsuite/ltrace.main/Makefile.in: Add + * testsuite/ltrace.main/signals.c: Add + * testsuite/ltrace.main/signals.exp: Add + * testsuite/ltrace.main/system_calls.c: Add + * testsuite/ltrace.main/system_calls.exp: Add + * testsuite/ltrace.minor/: Add + * testsuite/ltrace.minor/attach-process.c: Add + * testsuite/ltrace.minor/attach-process.exp: Add + * testsuite/ltrace.minor/count-record.c: Add + * testsuite/ltrace.minor/count-record.exp: Add + * testsuite/ltrace.minor/demangle.cpp: Add + * testsuite/ltrace.minor/demangle.exp: Add + * testsuite/ltrace.minor/demangle.h: Add + * testsuite/ltrace.minor/demangle-lib.cpp: Add + * testsuite/ltrace.minor/Makefile.in: Add + * testsuite/ltrace.minor/print-instruction-pointer.c: Add + * testsuite/ltrace.minor/print-instruction-pointer.exp: Add + * testsuite/ltrace.minor/time-record.c: Add + * testsuite/ltrace.minor/time-record-T.exp: Add + * testsuite/ltrace.minor/time-record-tt.exp: Add + * testsuite/ltrace.minor/time-record-ttt.exp: Add + * testsuite/ltrace.minor/trace-clone.c: Add + * testsuite/ltrace.minor/trace-clone.exp: Add + * testsuite/ltrace.minor/trace-fork.c: Add + * testsuite/ltrace.minor/trace-fork.exp: Add + * testsuite/ltrace.torture/: Add + * testsuite/ltrace.torture/Makefile.in: Add + * testsuite/ltrace.torture/signals.c: Add + * testsuite/ltrace.torture/signals.exp: Add + * testsuite/Makefile.in: Add + * testsuite/README: Add + * testsuite/run-my-tests.sh: Add + * testsuite/so_test1/: Add + * testsuite/so_test2/: Add + +2006-03-13 Paul Gilliam + + * options.h: New structure for opt_x list elements, now with 'found'. + * options.c: Use new opt_x_t structure, initializing 'found' to 0. + * elf.c: Use new 'found' field for better error checking. + +2006-03-06 Ian Wienand + + * Makefile.in: remove unneeded dirs from make dist; use rm + directly. + +2006-02-22 Ian Wienand + + * COPYING: update from FSF to update address + * Makefile.in: check for SVN checkout with make dist. + +2006-02-21 Ian Wienand + + * README: update to point to Alioth list + +2006-02-21 Ian Wienand + + * lots!: Rebase from RedHat 0.3.36-4.2 package. Forward port most + of the below changes that weren't already there. Bump version to + 0.4 as there are two added architectures and internal API changes. + All changes from this point on should be reflected in this file. + +2006-02-17 Ian Wienand + + * sysdeps/linux-gnu/ia64/arch.h: add ia64 support + * sysdeps/linux-gnu/ia64/breakpoint.c: add + * sysdeps/linux-gnu/ia64/Makefile: add + * sysdeps/linux-gnu/ia64/plt.c: add + * sysdeps/linux-gnu/ia64/ptrace.h: add + * sysdeps/linux-gnu/ia64/regs.c: add + * sysdeps/linux-gnu/ia64/signalent.h: add + * sysdeps/linux-gnu/ia64/syscallent.h: add + * sysdeps/linux-gnu/ia64/trace.c: add + * elf.h: add extra field for PLT size + * elf.c: put in PLT size + * sysdeps/linux-gnu/breakpoint.c: add arch breakpoint override + * sysdeps/linux-gnu/trace.c: don't single step after breakpoint for + ia64 + + * configure.ac: add version to AC_INIT, bump version to 0.3.38 + * options.c: use PACKAGE_VERSION + +2006-02-16 Ian Wienand + + * Makefile.in: install documentation into share/doc, make dist + target from SVN export. + +2006-02-16 Rajeev V. Pillai + + * Makefile.in: pass through CPP and LD FLAGS + +2006-02-16 Ian Wienand + + * read_config_file.c: initialise pt stack argument to stop warning + * summary.c: make show_summary() obey -C for demangaling function names + +2006-02-16 Bernd Zeimetz + + * ltrace.1: reference reportbug + +2006-02-16 Colin S. Miller + + * ltrace.1: fix debug typo + +2006-02-16 Andrew Stribblehill + + * etc/ltrace.conf: fix putenv typo + +2006-02-16 Ian Wienand + + * README: update + * Makefile.in: remove obsolete -I- for -iquote, add TAGS target + * debug.c, debug.h: __PRETTY_FUNCTION__ is const; change specifier + to stop warnings. + * ltrace.1: add a note about not tracing dlopen()ed libraries diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..cdfdee6 --- /dev/null +++ b/INSTALL @@ -0,0 +1,19 @@ +How to build ltrace from source +------------------------------- + +To get the latest version from GIT: + + git clone git://git.debian.org/git/collab-maint/ltrace.git + +To create a distribution (ltrace-.tar.gz): + + ./mkdist + +To compile: + + ./configure + make + +To build debian/control (to create Debian package): + + debian/rules debian/control DEB_AUTO_UPDATE_DEBIAN_CONTROL:=yes diff --git a/Makefile.in b/Makefile.in new file mode 100644 index 0000000..1e8adcd --- /dev/null +++ b/Makefile.in @@ -0,0 +1,74 @@ +# +# ltrace's Makefile.in +# + +#OS := $(shell uname -s) +OS := @HOST_OS@ + +TOPDIR = $(shell pwd) + +prefix = @prefix@ +sysconfdir = @sysconfdir@ +bindir = $(prefix)/bin +mandir = @mandir@ +docdir = $(prefix)/share/doc/ltrace + +CC = @CC@ +CFLAGS = -Wall @CFLAGS@ +CPPFLAGS = -iquote $(TOPDIR) -iquote $(TOPDIR)/sysdeps/$(OS) -DSYSCONFDIR=\"$(sysconfdir)\" @CPPFLAGS@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ + +INSTALL = @INSTALL@ +INSTALL_FILE = $(INSTALL) -p -m 644 +INSTALL_PROGRAM = $(INSTALL) -p -m 755 +INSTALL_SCRIPT = $(INSTALL) -p -m 755 +INSTALL_DIR = $(INSTALL) -p -d -m 755 + +OBJ = libltrace.o options.o elf.o output.o read_config_file.o \ + execute_program.o handle_event.o display_args.o \ + breakpoints.o proc.o demangle.o dict.o debug.o summary.o + +VERSION = @PACKAGE_VERSION@ + +all: ltrace + +ltrace: main.o libltrace.a + $(CC) $(LDFLAGS) $^ $(LIBS) -o $@ + +libltrace.a: sysdeps/sysdep.o $(OBJ) + $(AR) rcv $@ $^ + +sysdeps/sysdep.o: dummy + $(MAKE) -C sysdeps/$(OS) + +clean-deja: + $(RM) testrun.log testrun.sum + cd testsuite; make clean + +clean: clean-deja + $(MAKE) -C sysdeps/$(OS) clean + rm -f ltrace main.o libltrace.a $(OBJ) + rm -f *~ *.bak a.out core + +distclean: clean + rm -f config.h Makefile + +realclean: distclean + +install: ltrace + $(INSTALL_DIR) $(DESTDIR)$(bindir) $(DESTDIR)$(docdir) $(DESTDIR)$(mandir)/man1 + $(INSTALL_DIR) $(DESTDIR)$(sysconfdir) + $(INSTALL_PROGRAM) ltrace $(DESTDIR)$(bindir) + $(INSTALL_FILE) etc/ltrace.conf $(DESTDIR)$(sysconfdir) + $(INSTALL_FILE) COPYING README TODO BUGS ChangeLog $(DESTDIR)$(docdir) + $(INSTALL_FILE) ltrace.1 $(DESTDIR)$(mandir)/man1 + +check: + cd testsuite;cat /proc/version;uptime;free -m;$(MAKE) check + +dummy: + +.PHONY: all clean distclean dist install dummy + +.EXPORT_ALL_VARIABLES: diff --git a/README b/README new file mode 100644 index 0000000..ab1a2e5 --- /dev/null +++ b/README @@ -0,0 +1,92 @@ + ltrace + + A Dynamic Library Tracer + + Copyright 1997-2009 Juan Cespedes + + +Contents +-------- + 0. Authors + 1. Introduction + 2. Where can I find it + 3. How does it work + 4. Where does it work + 5. Bugs + 6. License + + +0. Authors +---------- + +ltrace has been developed mainly by Juan Cespedes , +but he has received many contributions from other people. The following +people have contributed significantly to this project: + +* César Sánchez +* Santiago Romero +* Pat Beirne (ARM port) +* Roman Hodek (m68k port) +* Morten Eriksen (misc fixes) +* Silvio Cesare (ELF hacking) +* Timothy Fesig (S390 port) +* Anton Blanchard (Powerpc port) +* Jakub Jelinek (SPARC port, support for libelf, many fixes) +* Jakub Bogusz (alpha port) +* SuSE (amd64 port) +* Ian Wienand (IA64 port) +* Eric Vaitl (mipsel port) +* Petr Machata (misc fixes) + +1. Introduction +--------------- + +ltrace is a debugging tool, similar to strace, but it traces library +calls instead of system calls. + +2. Where can I find it +---------------------- + +http://www.ltrace.org + +3. How does it work +------------------- + +Using software breakpoints, just like gdb. + +4. Where does it work +--------------------- + +It works with ELF based Linux systems running on i386, m68k, S/390, +ARM, PowerPC, PowerPC64, IA64, AMD64, SPARC and Alpha processors. + +It is part of at least Debian GNU/Linux, RedHat, SuSE, Mandrake... + +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 ltrace-devel@lists.alioth.debian.org. + +This file is very incomplete and out-of-date. + +6. License +---------- + + Copyright (C) 1997-2009 Juan Cespedes + + 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + 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., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + diff --git a/TODO b/TODO new file mode 100644 index 0000000..5063737 --- /dev/null +++ b/TODO @@ -0,0 +1,36 @@ +* BFD: + + New executable formats + + Read list of libraries needed + + Read list of undefined symbols in executables + + Read list of exported symbols in libraries + + Read debugging info from executables/libraries +* Automatically update list of syscalls? +* Improve documentation +* Improve -e/-x options (regexp?) +* Improve -l option +* Improve C++ name demangling +* Display different argument types +* Update /etc/ltrace.conf +* More architectures, cleaner way to port +* More operating systems (solaris?) +* Option -I (inter-library calls) +* Modify ARGTYPE_STRING[0-5] types so that they don't stop displaying chars when '\0' is seen +* Get rid of EVENT_ARCH_SYSCALL and EVENT_ARCH_SYSRET +* Cleaner way to use breakpoints: + + BP is placed in the PLT + + When control hits there: + - write down return address + - change return address with another one (handled by ltrace) + - get arguments... + - change the process' PC to be in the correct place, + without removing breakpoint + + When control hits one of our return addresses: + - get return value... + - change PC to the right place +* To be able to work with processes sharing memory, we must: + + ptrace() every single thread + + place breakpoints only in places where the process control can continue + without having to remove it +* List source dependencies in Makefile +* Create different ltrace processes to trace different children +* After a clone(), syscalls may be seen as sysrets in s390 (see trace.c:syscall_p()) diff --git a/VERSION b/VERSION new file mode 100644 index 0000000..be14282 --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +0.5.3 diff --git a/aclocal.m4 b/aclocal.m4 new file mode 100644 index 0000000..abe07e0 --- /dev/null +++ b/aclocal.m4 @@ -0,0 +1,833 @@ +dnl aclocal.m4t generated automatically by aclocal 1.4-p6 + +dnl Copyright (C) 1994, 1995-8, 1999, 2001 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY, to the extent permitted by law; without +dnl even the implied warranty of MERCHANTABILITY or FITNESS FOR A +dnl PARTICULAR PURPOSE. + +# lib-prefix.m4 serial 3 (gettext-0.13) +dnl Copyright (C) 2001-2003 Free Software Foundation, Inc. +dnl This file is free software, distributed under the terms of the GNU +dnl General Public License. As a special exception to the GNU General +dnl Public License, this file may be distributed as part of a program +dnl that contains a configuration script generated by Autoconf, under +dnl the same distribution terms as the rest of that program. + +dnl From Bruno Haible. + +dnl AC_LIB_ARG_WITH is synonymous to AC_ARG_WITH in autoconf-2.13, and +dnl similar to AC_ARG_WITH in autoconf 2.52...2.57 except that is doesn't +dnl require excessive bracketing. +ifdef([AC_HELP_STRING], +[AC_DEFUN([AC_LIB_ARG_WITH], [AC_ARG_WITH([$1],[[$2]],[$3],[$4])])], +[AC_DEFUN([AC_][LIB_ARG_WITH], [AC_ARG_WITH([$1],[$2],[$3],[$4])])]) + +dnl AC_LIB_PREFIX adds to the CPPFLAGS and LDFLAGS the flags that are needed +dnl to access previously installed libraries. The basic assumption is that +dnl a user will want packages to use other packages he previously installed +dnl with the same --prefix option. +dnl This macro is not needed if only AC_LIB_LINKFLAGS is used to locate +dnl libraries, but is otherwise very convenient. +AC_DEFUN([AC_LIB_PREFIX], +[ + AC_BEFORE([$0], [AC_LIB_LINKFLAGS]) + AC_REQUIRE([AC_PROG_CC]) + AC_REQUIRE([AC_CANONICAL_HOST]) + AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) + dnl By default, look in $includedir and $libdir. + use_additional=yes + AC_LIB_WITH_FINAL_PREFIX([ + eval additional_includedir=\"$includedir\" + eval additional_libdir=\"$libdir\" + ]) + AC_LIB_ARG_WITH([lib-prefix], +[ --with-lib-prefix[=DIR] search for libraries in DIR/include and DIR/lib + --without-lib-prefix don't search for libraries in includedir and libdir], +[ + if test "X$withval" = "Xno"; then + use_additional=no + else + if test "X$withval" = "X"; then + AC_LIB_WITH_FINAL_PREFIX([ + eval additional_includedir=\"$includedir\" + eval additional_libdir=\"$libdir\" + ]) + else + additional_includedir="$withval/include" + additional_libdir="$withval/lib" + fi + fi +]) + if test $use_additional = yes; then + dnl Potentially add $additional_includedir to $CPPFLAGS. + dnl But don't add it + dnl 1. if it's the standard /usr/include, + dnl 2. if it's already present in $CPPFLAGS, + dnl 3. if it's /usr/local/include and we are using GCC on Linux, + dnl 4. if it doesn't exist as a directory. + if test "X$additional_includedir" != "X/usr/include"; then + haveit= + for x in $CPPFLAGS; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + if test "X$x" = "X-I$additional_includedir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test "X$additional_includedir" = "X/usr/local/include"; then + if test -n "$GCC"; then + case $host_os in + linux*) haveit=yes;; + esac + fi + fi + if test -z "$haveit"; then + if test -d "$additional_includedir"; then + dnl Really add $additional_includedir to $CPPFLAGS. + CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }-I$additional_includedir" + fi + fi + fi + fi + dnl Potentially add $additional_libdir to $LDFLAGS. + dnl But don't add it + dnl 1. if it's the standard /usr/lib, + dnl 2. if it's already present in $LDFLAGS, + dnl 3. if it's /usr/local/lib and we are using GCC on Linux, + dnl 4. if it doesn't exist as a directory. + if test "X$additional_libdir" != "X/usr/lib"; then + haveit= + for x in $LDFLAGS; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + if test "X$x" = "X-L$additional_libdir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test "X$additional_libdir" = "X/usr/local/lib"; then + if test -n "$GCC"; then + case $host_os in + linux*) haveit=yes;; + esac + fi + fi + if test -z "$haveit"; then + if test -d "$additional_libdir"; then + dnl Really add $additional_libdir to $LDFLAGS. + LDFLAGS="${LDFLAGS}${LDFLAGS:+ }-L$additional_libdir" + fi + fi + fi + fi + fi +]) + +dnl AC_LIB_PREPARE_PREFIX creates variables acl_final_prefix, +dnl acl_final_exec_prefix, containing the values to which $prefix and +dnl $exec_prefix will expand at the end of the configure script. +AC_DEFUN([AC_LIB_PREPARE_PREFIX], +[ + dnl Unfortunately, prefix and exec_prefix get only finally determined + dnl at the end of configure. + if test "X$prefix" = "XNONE"; then + acl_final_prefix="$ac_default_prefix" + else + acl_final_prefix="$prefix" + fi + if test "X$exec_prefix" = "XNONE"; then + acl_final_exec_prefix='${prefix}' + else + acl_final_exec_prefix="$exec_prefix" + fi + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + eval acl_final_exec_prefix=\"$acl_final_exec_prefix\" + prefix="$acl_save_prefix" +]) + +dnl AC_LIB_WITH_FINAL_PREFIX([statement]) evaluates statement, with the +dnl variables prefix and exec_prefix bound to the values they will have +dnl at the end of the configure script. +AC_DEFUN([AC_LIB_WITH_FINAL_PREFIX], +[ + acl_save_prefix="$prefix" + prefix="$acl_final_prefix" + acl_save_exec_prefix="$exec_prefix" + exec_prefix="$acl_final_exec_prefix" + $1 + exec_prefix="$acl_save_exec_prefix" + prefix="$acl_save_prefix" +]) + +# lib-link.m4 serial 4 (gettext-0.12) +dnl Copyright (C) 2001-2003 Free Software Foundation, Inc. +dnl This file is free software, distributed under the terms of the GNU +dnl General Public License. As a special exception to the GNU General +dnl Public License, this file may be distributed as part of a program +dnl that contains a configuration script generated by Autoconf, under +dnl the same distribution terms as the rest of that program. + +dnl From Bruno Haible. + +dnl AC_LIB_LINKFLAGS(name [, dependencies]) searches for libname and +dnl the libraries corresponding to explicit and implicit dependencies. +dnl Sets and AC_SUBSTs the LIB${NAME} and LTLIB${NAME} variables and +dnl augments the CPPFLAGS variable. +AC_DEFUN([AC_LIB_LINKFLAGS], +[ + AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) + AC_REQUIRE([AC_LIB_RPATH]) + define([Name],[translit([$1],[./-], [___])]) + define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-], + [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])]) + AC_CACHE_CHECK([how to link with lib[]$1], [ac_cv_lib[]Name[]_libs], [ + AC_LIB_LINKFLAGS_BODY([$1], [$2]) + ac_cv_lib[]Name[]_libs="$LIB[]NAME" + ac_cv_lib[]Name[]_ltlibs="$LTLIB[]NAME" + ac_cv_lib[]Name[]_cppflags="$INC[]NAME" + ]) + LIB[]NAME="$ac_cv_lib[]Name[]_libs" + LTLIB[]NAME="$ac_cv_lib[]Name[]_ltlibs" + INC[]NAME="$ac_cv_lib[]Name[]_cppflags" + AC_LIB_APPENDTOVAR([CPPFLAGS], [$INC]NAME) + AC_SUBST([LIB]NAME) + AC_SUBST([LTLIB]NAME) + dnl Also set HAVE_LIB[]NAME so that AC_LIB_HAVE_LINKFLAGS can reuse the + dnl results of this search when this library appears as a dependency. + HAVE_LIB[]NAME=yes + undefine([Name]) + undefine([NAME]) +]) + +dnl AC_LIB_HAVE_LINKFLAGS(name, dependencies, includes, testcode) +dnl searches for libname and the libraries corresponding to explicit and +dnl implicit dependencies, together with the specified include files and +dnl the ability to compile and link the specified testcode. If found, it +dnl sets and AC_SUBSTs HAVE_LIB${NAME}=yes and the LIB${NAME} and +dnl LTLIB${NAME} variables and augments the CPPFLAGS variable, and +dnl #defines HAVE_LIB${NAME} to 1. Otherwise, it sets and AC_SUBSTs +dnl HAVE_LIB${NAME}=no and LIB${NAME} and LTLIB${NAME} to empty. +AC_DEFUN([AC_LIB_HAVE_LINKFLAGS], +[ + AC_REQUIRE([AC_LIB_PREPARE_PREFIX]) + AC_REQUIRE([AC_LIB_RPATH]) + define([Name],[translit([$1],[./-], [___])]) + define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-], + [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])]) + + dnl Search for lib[]Name and define LIB[]NAME, LTLIB[]NAME and INC[]NAME + dnl accordingly. + AC_LIB_LINKFLAGS_BODY([$1], [$2]) + + dnl Add $INC[]NAME to CPPFLAGS before performing the following checks, + dnl because if the user has installed lib[]Name and not disabled its use + dnl via --without-lib[]Name-prefix, he wants to use it. + ac_save_CPPFLAGS="$CPPFLAGS" + AC_LIB_APPENDTOVAR([CPPFLAGS], [$INC]NAME) + + AC_CACHE_CHECK([for lib[]$1], [ac_cv_lib[]Name], [ + ac_save_LIBS="$LIBS" + LIBS="$LIBS $LIB[]NAME" + AC_TRY_LINK([$3], [$4], [ac_cv_lib[]Name=yes], [ac_cv_lib[]Name=no]) + LIBS="$ac_save_LIBS" + ]) + if test "$ac_cv_lib[]Name" = yes; then + HAVE_LIB[]NAME=yes + AC_DEFINE([HAVE_LIB]NAME, 1, [Define if you have the $1 library.]) + AC_MSG_CHECKING([how to link with lib[]$1]) + AC_MSG_RESULT([$LIB[]NAME]) + else + HAVE_LIB[]NAME=no + dnl If $LIB[]NAME didn't lead to a usable library, we don't need + dnl $INC[]NAME either. + CPPFLAGS="$ac_save_CPPFLAGS" + LIB[]NAME= + LTLIB[]NAME= + fi + AC_SUBST([HAVE_LIB]NAME) + AC_SUBST([LIB]NAME) + AC_SUBST([LTLIB]NAME) + undefine([Name]) + undefine([NAME]) +]) + +dnl Determine the platform dependent parameters needed to use rpath: +dnl libext, shlibext, hardcode_libdir_flag_spec, hardcode_libdir_separator, +dnl hardcode_direct, hardcode_minus_L. +AC_DEFUN([AC_LIB_RPATH], +[ + AC_REQUIRE([AC_PROG_CC]) dnl we use $CC, $GCC, $LDFLAGS + AC_REQUIRE([AC_LIB_PROG_LD]) dnl we use $LD, $with_gnu_ld + AC_REQUIRE([AC_CANONICAL_HOST]) dnl we use $host + AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT]) dnl we use $ac_aux_dir + AC_CACHE_CHECK([for shared library run path origin], acl_cv_rpath, [ + CC="$CC" GCC="$GCC" LDFLAGS="$LDFLAGS" LD="$LD" with_gnu_ld="$with_gnu_ld" \ + ${CONFIG_SHELL-/bin/sh} "$ac_aux_dir/config.rpath" "$host" > conftest.sh + . ./conftest.sh + rm -f ./conftest.sh + acl_cv_rpath=done + ]) + wl="$acl_cv_wl" + libext="$acl_cv_libext" + shlibext="$acl_cv_shlibext" + hardcode_libdir_flag_spec="$acl_cv_hardcode_libdir_flag_spec" + hardcode_libdir_separator="$acl_cv_hardcode_libdir_separator" + hardcode_direct="$acl_cv_hardcode_direct" + hardcode_minus_L="$acl_cv_hardcode_minus_L" + dnl Determine whether the user wants rpath handling at all. + AC_ARG_ENABLE(rpath, + [ --disable-rpath do not hardcode runtime library paths], + :, enable_rpath=yes) +]) + +dnl AC_LIB_LINKFLAGS_BODY(name [, dependencies]) searches for libname and +dnl the libraries corresponding to explicit and implicit dependencies. +dnl Sets the LIB${NAME}, LTLIB${NAME} and INC${NAME} variables. +AC_DEFUN([AC_LIB_LINKFLAGS_BODY], +[ + define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-], + [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])]) + dnl By default, look in $includedir and $libdir. + use_additional=yes + AC_LIB_WITH_FINAL_PREFIX([ + eval additional_includedir=\"$includedir\" + eval additional_libdir=\"$libdir\" + ]) + AC_LIB_ARG_WITH([lib$1-prefix], +[ --with-lib$1-prefix[=DIR] search for lib$1 in DIR/include and DIR/lib + --without-lib$1-prefix don't search for lib$1 in includedir and libdir], +[ + if test "X$withval" = "Xno"; then + use_additional=no + else + if test "X$withval" = "X"; then + AC_LIB_WITH_FINAL_PREFIX([ + eval additional_includedir=\"$includedir\" + eval additional_libdir=\"$libdir\" + ]) + else + additional_includedir="$withval/include" + additional_libdir="$withval/lib" + fi + fi +]) + dnl Search the library and its dependencies in $additional_libdir and + dnl $LDFLAGS. Using breadth-first-seach. + LIB[]NAME= + LTLIB[]NAME= + INC[]NAME= + rpathdirs= + ltrpathdirs= + names_already_handled= + names_next_round='$1 $2' + while test -n "$names_next_round"; do + names_this_round="$names_next_round" + names_next_round= + for name in $names_this_round; do + already_handled= + for n in $names_already_handled; do + if test "$n" = "$name"; then + already_handled=yes + break + fi + done + if test -z "$already_handled"; then + names_already_handled="$names_already_handled $name" + dnl See if it was already located by an earlier AC_LIB_LINKFLAGS + dnl or AC_LIB_HAVE_LINKFLAGS call. + uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./-|ABCDEFGHIJKLMNOPQRSTUVWXYZ___|'` + eval value=\"\$HAVE_LIB$uppername\" + if test -n "$value"; then + if test "$value" = yes; then + eval value=\"\$LIB$uppername\" + test -z "$value" || LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$value" + eval value=\"\$LTLIB$uppername\" + test -z "$value" || LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$value" + else + dnl An earlier call to AC_LIB_HAVE_LINKFLAGS has determined + dnl that this library doesn't exist. So just drop it. + : + fi + else + dnl Search the library lib$name in $additional_libdir and $LDFLAGS + dnl and the already constructed $LIBNAME/$LTLIBNAME. + found_dir= + found_la= + found_so= + found_a= + if test $use_additional = yes; then + if test -n "$shlibext" && test -f "$additional_libdir/lib$name.$shlibext"; then + found_dir="$additional_libdir" + found_so="$additional_libdir/lib$name.$shlibext" + if test -f "$additional_libdir/lib$name.la"; then + found_la="$additional_libdir/lib$name.la" + fi + else + if test -f "$additional_libdir/lib$name.$libext"; then + found_dir="$additional_libdir" + found_a="$additional_libdir/lib$name.$libext" + if test -f "$additional_libdir/lib$name.la"; then + found_la="$additional_libdir/lib$name.la" + fi + fi + fi + fi + if test "X$found_dir" = "X"; then + for x in $LDFLAGS $LTLIB[]NAME; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + case "$x" in + -L*) + dir=`echo "X$x" | sed -e 's/^X-L//'` + if test -n "$shlibext" && test -f "$dir/lib$name.$shlibext"; then + found_dir="$dir" + found_so="$dir/lib$name.$shlibext" + if test -f "$dir/lib$name.la"; then + found_la="$dir/lib$name.la" + fi + else + if test -f "$dir/lib$name.$libext"; then + found_dir="$dir" + found_a="$dir/lib$name.$libext" + if test -f "$dir/lib$name.la"; then + found_la="$dir/lib$name.la" + fi + fi + fi + ;; + esac + if test "X$found_dir" != "X"; then + break + fi + done + fi + if test "X$found_dir" != "X"; then + dnl Found the library. + LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$found_dir -l$name" + if test "X$found_so" != "X"; then + dnl Linking with a shared library. We attempt to hardcode its + dnl directory into the executable's runpath, unless it's the + dnl standard /usr/lib. + if test "$enable_rpath" = no || test "X$found_dir" = "X/usr/lib"; then + dnl No hardcoding is needed. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" + else + dnl Use an explicit option to hardcode DIR into the resulting + dnl binary. + dnl Potentially add DIR to ltrpathdirs. + dnl The ltrpathdirs will be appended to $LTLIBNAME at the end. + haveit= + for x in $ltrpathdirs; do + if test "X$x" = "X$found_dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + ltrpathdirs="$ltrpathdirs $found_dir" + fi + dnl The hardcoding into $LIBNAME is system dependent. + if test "$hardcode_direct" = yes; then + dnl Using DIR/libNAME.so during linking hardcodes DIR into the + dnl resulting binary. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" + else + if test -n "$hardcode_libdir_flag_spec" && test "$hardcode_minus_L" = no; then + dnl Use an explicit option to hardcode DIR into the resulting + dnl binary. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" + dnl Potentially add DIR to rpathdirs. + dnl The rpathdirs will be appended to $LIBNAME at the end. + haveit= + for x in $rpathdirs; do + if test "X$x" = "X$found_dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + rpathdirs="$rpathdirs $found_dir" + fi + else + dnl Rely on "-L$found_dir". + dnl But don't add it if it's already contained in the LDFLAGS + dnl or the already constructed $LIBNAME + haveit= + for x in $LDFLAGS $LIB[]NAME; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + if test "X$x" = "X-L$found_dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir" + fi + if test "$hardcode_minus_L" != no; then + dnl FIXME: Not sure whether we should use + dnl "-L$found_dir -l$name" or "-L$found_dir $found_so" + dnl here. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so" + else + dnl We cannot use $hardcode_runpath_var and LD_RUN_PATH + dnl here, because this doesn't fit in flags passed to the + dnl compiler. So give up. No hardcoding. This affects only + dnl very old systems. + dnl FIXME: Not sure whether we should use + dnl "-L$found_dir -l$name" or "-L$found_dir $found_so" + dnl here. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name" + fi + fi + fi + fi + else + if test "X$found_a" != "X"; then + dnl Linking with a static library. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_a" + else + dnl We shouldn't come here, but anyway it's good to have a + dnl fallback. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir -l$name" + fi + fi + dnl Assume the include files are nearby. + additional_includedir= + case "$found_dir" in + */lib | */lib/) + basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e 's,/lib/*$,,'` + additional_includedir="$basedir/include" + ;; + esac + if test "X$additional_includedir" != "X"; then + dnl Potentially add $additional_includedir to $INCNAME. + dnl But don't add it + dnl 1. if it's the standard /usr/include, + dnl 2. if it's /usr/local/include and we are using GCC on Linux, + dnl 3. if it's already present in $CPPFLAGS or the already + dnl constructed $INCNAME, + dnl 4. if it doesn't exist as a directory. + if test "X$additional_includedir" != "X/usr/include"; then + haveit= + if test "X$additional_includedir" = "X/usr/local/include"; then + if test -n "$GCC"; then + case $host_os in + linux*) haveit=yes;; + esac + fi + fi + if test -z "$haveit"; then + for x in $CPPFLAGS $INC[]NAME; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + if test "X$x" = "X-I$additional_includedir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test -d "$additional_includedir"; then + dnl Really add $additional_includedir to $INCNAME. + INC[]NAME="${INC[]NAME}${INC[]NAME:+ }-I$additional_includedir" + fi + fi + fi + fi + fi + dnl Look for dependencies. + if test -n "$found_la"; then + dnl Read the .la file. It defines the variables + dnl dlname, library_names, old_library, dependency_libs, current, + dnl age, revision, installed, dlopen, dlpreopen, libdir. + save_libdir="$libdir" + case "$found_la" in + */* | *\\*) . "$found_la" ;; + *) . "./$found_la" ;; + esac + libdir="$save_libdir" + dnl We use only dependency_libs. + for dep in $dependency_libs; do + case "$dep" in + -L*) + additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'` + dnl Potentially add $additional_libdir to $LIBNAME and $LTLIBNAME. + dnl But don't add it + dnl 1. if it's the standard /usr/lib, + dnl 2. if it's /usr/local/lib and we are using GCC on Linux, + dnl 3. if it's already present in $LDFLAGS or the already + dnl constructed $LIBNAME, + dnl 4. if it doesn't exist as a directory. + if test "X$additional_libdir" != "X/usr/lib"; then + haveit= + if test "X$additional_libdir" = "X/usr/local/lib"; then + if test -n "$GCC"; then + case $host_os in + linux*) haveit=yes;; + esac + fi + fi + if test -z "$haveit"; then + haveit= + for x in $LDFLAGS $LIB[]NAME; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + if test "X$x" = "X-L$additional_libdir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test -d "$additional_libdir"; then + dnl Really add $additional_libdir to $LIBNAME. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$additional_libdir" + fi + fi + haveit= + for x in $LDFLAGS $LTLIB[]NAME; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + if test "X$x" = "X-L$additional_libdir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + if test -d "$additional_libdir"; then + dnl Really add $additional_libdir to $LTLIBNAME. + LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$additional_libdir" + fi + fi + fi + fi + ;; + -R*) + dir=`echo "X$dep" | sed -e 's/^X-R//'` + if test "$enable_rpath" != no; then + dnl Potentially add DIR to rpathdirs. + dnl The rpathdirs will be appended to $LIBNAME at the end. + haveit= + for x in $rpathdirs; do + if test "X$x" = "X$dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + rpathdirs="$rpathdirs $dir" + fi + dnl Potentially add DIR to ltrpathdirs. + dnl The ltrpathdirs will be appended to $LTLIBNAME at the end. + haveit= + for x in $ltrpathdirs; do + if test "X$x" = "X$dir"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + ltrpathdirs="$ltrpathdirs $dir" + fi + fi + ;; + -l*) + dnl Handle this in the next round. + names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'` + ;; + *.la) + dnl Handle this in the next round. Throw away the .la's + dnl directory; it is already contained in a preceding -L + dnl option. + names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'` + ;; + *) + dnl Most likely an immediate library name. + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$dep" + LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$dep" + ;; + esac + done + fi + else + dnl Didn't find the library; assume it is in the system directories + dnl known to the linker and runtime loader. (All the system + dnl directories known to the linker should also be known to the + dnl runtime loader, otherwise the system is severely misconfigured.) + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name" + LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-l$name" + fi + fi + fi + done + done + if test "X$rpathdirs" != "X"; then + if test -n "$hardcode_libdir_separator"; then + dnl Weird platform: only the last -rpath option counts, the user must + dnl pass all path elements in one option. We can arrange that for a + dnl single library, but not when more than one $LIBNAMEs are used. + alldirs= + for found_dir in $rpathdirs; do + alldirs="${alldirs}${alldirs:+$hardcode_libdir_separator}$found_dir" + done + dnl Note: hardcode_libdir_flag_spec uses $libdir and $wl. + acl_save_libdir="$libdir" + libdir="$alldirs" + eval flag=\"$hardcode_libdir_flag_spec\" + libdir="$acl_save_libdir" + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag" + else + dnl The -rpath options are cumulative. + for found_dir in $rpathdirs; do + acl_save_libdir="$libdir" + libdir="$found_dir" + eval flag=\"$hardcode_libdir_flag_spec\" + libdir="$acl_save_libdir" + LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag" + done + fi + fi + if test "X$ltrpathdirs" != "X"; then + dnl When using libtool, the option that works for both libraries and + dnl executables is -R. The -R options are cumulative. + for found_dir in $ltrpathdirs; do + LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-R$found_dir" + done + fi +]) + +dnl AC_LIB_APPENDTOVAR(VAR, CONTENTS) appends the elements of CONTENTS to VAR, +dnl unless already present in VAR. +dnl Works only for CPPFLAGS, not for LIB* variables because that sometimes +dnl contains two or three consecutive elements that belong together. +AC_DEFUN([AC_LIB_APPENDTOVAR], +[ + for element in [$2]; do + haveit= + for x in $[$1]; do + AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"]) + if test "X$x" = "X$element"; then + haveit=yes + break + fi + done + if test -z "$haveit"; then + [$1]="${[$1]}${[$1]:+ }$element" + fi + done +]) + +# lib-ld.m4 serial 3 (gettext-0.13) +dnl Copyright (C) 1996-2003 Free Software Foundation, Inc. +dnl This file is free software, distributed under the terms of the GNU +dnl General Public License. As a special exception to the GNU General +dnl Public License, this file may be distributed as part of a program +dnl that contains a configuration script generated by Autoconf, under +dnl the same distribution terms as the rest of that program. + +dnl Subroutines of libtool.m4, +dnl with replacements s/AC_/AC_LIB/ and s/lt_cv/acl_cv/ to avoid collision +dnl with libtool.m4. + +dnl From libtool-1.4. Sets the variable with_gnu_ld to yes or no. +AC_DEFUN([AC_LIB_PROG_LD_GNU], +[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], acl_cv_prog_gnu_ld, +[# I'd rather use --version here, but apparently some GNU ld's only accept -v. +case `$LD -v 2>&1 conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi +ac_prog=ld +if test "$GCC" = yes; then + # Check if gcc -print-prog-name=ld gives a path. + AC_MSG_CHECKING([for ld used by GCC]) + case $host in + *-*-mingw*) + # gcc leaves a trailing carriage return which upsets mingw + ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; + *) + ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; + esac + case $ac_prog in + # Accept absolute paths. + [[\\/]* | [A-Za-z]:[\\/]*)] + [re_direlt='/[^/][^/]*/\.\./'] + # Canonicalize the path of ld + ac_prog=`echo $ac_prog| sed 's%\\\\%/%g'` + while echo $ac_prog | grep "$re_direlt" > /dev/null 2>&1; do + ac_prog=`echo $ac_prog| sed "s%$re_direlt%/%"` + done + test -z "$LD" && LD="$ac_prog" + ;; + "") + # If it fails, then pretend we aren't using GCC. + ac_prog=ld + ;; + *) + # If it is relative, then search for the first ld in PATH. + with_gnu_ld=unknown + ;; + esac +elif test "$with_gnu_ld" = yes; then + AC_MSG_CHECKING([for GNU ld]) +else + AC_MSG_CHECKING([for non-GNU ld]) +fi +AC_CACHE_VAL(acl_cv_path_LD, +[if test -z "$LD"; then + IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}${PATH_SEPARATOR-:}" + for ac_dir in $PATH; do + test -z "$ac_dir" && ac_dir=. + if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then + acl_cv_path_LD="$ac_dir/$ac_prog" + # Check to see if the program is GNU ld. I'd rather use --version, + # but apparently some GNU ld's only accept -v. + # Break only if it was the GNU/non-GNU ld that we prefer. + case `"$acl_cv_path_LD" -v 2>&1 < /dev/null` in + *GNU* | *'with BFD'*) + test "$with_gnu_ld" != no && break ;; + *) + test "$with_gnu_ld" != yes && break ;; + esac + fi + done + IFS="$ac_save_ifs" +else + acl_cv_path_LD="$LD" # Let the user override the test with a path. +fi]) +LD="$acl_cv_path_LD" +if test -n "$LD"; then + AC_MSG_RESULT($LD) +else + AC_MSG_RESULT(no) +fi +test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH]) +AC_LIB_PROG_LD_GNU +]) + diff --git a/breakpoints.c b/breakpoints.c new file mode 100644 index 0000000..ba3b060 --- /dev/null +++ b/breakpoints.c @@ -0,0 +1,230 @@ +#include "config.h" + +#include +#include +#include + +#ifdef __powerpc__ +#include +#endif + +#include "common.h" + +/*****************************************************************************/ + +Breakpoint * +address2bpstruct(Process *proc, void *addr) { + debug(DEBUG_FUNCTION, "address2bpstruct(pid=%d, addr=%p)", proc->pid, addr); + return dict_find_entry(proc->breakpoints, addr); +} + +void +insert_breakpoint(Process *proc, void *addr, + struct library_symbol *libsym) { + Breakpoint *sbp; + + debug(DEBUG_FUNCTION, "insert_breakpoint(pid=%d, addr=%p, symbol=%s)", proc->pid, addr, libsym ? libsym->name : "NULL"); + debug(1, "symbol=%s, addr=%p", libsym?libsym->name:"(nil)", addr); + + if (!addr) + return; + + if (libsym) + libsym->needs_init = 0; + + sbp = dict_find_entry(proc->breakpoints, addr); + if (!sbp) { + sbp = calloc(1, sizeof(Breakpoint)); + if (!sbp) { + return; /* TODO FIXME XXX: error_mem */ + } + dict_enter(proc->breakpoints, addr, sbp); + sbp->addr = addr; + sbp->libsym = libsym; + } +#ifdef __arm__ + sbp->thumb_mode = proc->thumb_mode; + proc->thumb_mode = 0; +#endif + sbp->enabled++; + if (sbp->enabled == 1 && proc->pid) + enable_breakpoint(proc->pid, sbp); +} + +void +delete_breakpoint(Process *proc, void *addr) { + Breakpoint *sbp; + + debug(DEBUG_FUNCTION, "delete_breakpoint(pid=%d, addr=%p)", proc->pid, addr); + + 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; + + sbp->enabled--; + if (sbp->enabled == 0) + disable_breakpoint(proc->pid, sbp); + assert(sbp->enabled >= 0); +} + +static void +enable_bp_cb(void *addr, void *sbp, void *proc) { + debug(DEBUG_FUNCTION, "enable_bp_cb(pid=%d)", ((Process *)proc)->pid); + if (((Breakpoint *)sbp)->enabled) { + enable_breakpoint(((Process *)proc)->pid, sbp); + } +} + +void +enable_all_breakpoints(Process *proc) { + debug(DEBUG_FUNCTION, "enable_all_breakpoints(pid=%d)", proc->pid); + if (proc->breakpoints_enabled <= 0) { +#ifdef __powerpc__ + unsigned long a; + + /* + * PPC HACK! (XXX FIXME TODO) + * If the dynamic linker hasn't populated the PLT then + * dont enable the breakpoints + */ + if (options.libcalls) { + a = ptrace(PTRACE_PEEKTEXT, proc->pid, + sym2addr(proc, proc->list_of_symbols), + 0); + if (a == 0x0) + return; + } +#endif + + debug(1, "Enabling breakpoints for pid %u...", proc->pid); + if (proc->breakpoints) { + dict_apply_to_all(proc->breakpoints, enable_bp_cb, + proc); + } +#ifdef __mips__ + { + /* + * I'm sure there is a nicer way to do this. We need to + * insert breakpoints _after_ the child has been started. + */ + struct library_symbol *sym; + struct library_symbol *new_sym; + sym=proc->list_of_symbols; + while(sym){ + void *addr= sym2addr(proc,sym); + if(!addr){ + sym=sym->next; + continue; + } + if(dict_find_entry(proc->breakpoints,addr)){ + sym=sym->next; + continue; + } + debug(2,"inserting bp %p %s",addr,sym->name); + new_sym=malloc(sizeof(*new_sym)); + memcpy(new_sym,sym,sizeof(*new_sym)); + new_sym->next=proc->list_of_symbols; + proc->list_of_symbols=new_sym; + insert_breakpoint(proc, addr, new_sym); + sym=sym->next; + } + } +#endif + } + proc->breakpoints_enabled = 1; +} + +static void +disable_bp_cb(void *addr, void *sbp, void *proc) { + debug(DEBUG_FUNCTION, "disable_bp_cb(pid=%d)", ((Process *)proc)->pid); + if (((Breakpoint *)sbp)->enabled) { + disable_breakpoint(((Process *)proc)->pid, sbp); + } +} + +void +disable_all_breakpoints(Process *proc) { + debug(DEBUG_FUNCTION, "disable_all_breakpoints(pid=%d)", proc->pid); + if (proc->breakpoints_enabled) { + debug(1, "Disabling breakpoints for pid %u...", proc->pid); + dict_apply_to_all(proc->breakpoints, disable_bp_cb, proc); + } + proc->breakpoints_enabled = 0; +} + +static void +free_bp_cb(void *addr, void *sbp, void *data) { + debug(DEBUG_FUNCTION, "free_bp_cb(sbp=%p)", sbp); + assert(sbp); + free(sbp); +} + +void +breakpoints_init(Process *proc) { + struct library_symbol *sym; + + debug(DEBUG_FUNCTION, "breakpoints_init(pid=%d)", proc->pid); + if (proc->breakpoints) { /* let's remove that struct */ + dict_apply_to_all(proc->breakpoints, free_bp_cb, NULL); + dict_clear(proc->breakpoints); + proc->breakpoints = NULL; + } + proc->breakpoints = dict_init(dict_key2hash_int, dict_key_cmp_int); + + if (options.libcalls && proc->filename) { + /* FIXME: memory leak when called by exec(): */ + proc->list_of_symbols = read_elf(proc); + if (opt_e) { + struct library_symbol **tmp1 = &(proc->list_of_symbols); + while (*tmp1) { + struct opt_e_t *tmp2 = opt_e; + int keep = !opt_e_enable; + + while (tmp2) { + if (!strcmp((*tmp1)->name, tmp2->name)) { + keep = opt_e_enable; + } + tmp2 = tmp2->next; + } + if (!keep) { + *tmp1 = (*tmp1)->next; + } else { + tmp1 = &((*tmp1)->next); + } + } + } + } else { + proc->list_of_symbols = NULL; + } + for (sym = proc->list_of_symbols; sym; sym = sym->next) { + /* proc->pid==0 delays enabling. */ + insert_breakpoint(proc, sym2addr(proc, sym), sym); + } + proc->callstack_depth = 0; + proc->breakpoints_enabled = -1; +} + +void +reinitialize_breakpoints(Process *proc) { + struct library_symbol *sym; + + debug(DEBUG_FUNCTION, "reinitialize_breakpoints(pid=%d)", proc->pid); + + sym = proc->list_of_symbols; + + while (sym) { + if (sym->needs_init) { + insert_breakpoint(proc, sym2addr(proc, sym), + sym); + if (sym->needs_init && !sym->is_weak) { + fprintf(stderr, + "could not re-initialize breakpoint for \"%s\" in file \"%s\"\n", + sym->name, proc->filename); + exit(1); + } + } + sym = sym->next; + } +} diff --git a/common.h b/common.h new file mode 100644 index 0000000..c672913 --- /dev/null +++ b/common.h @@ -0,0 +1,253 @@ +#include +#include +#include + +#include "ltrace.h" +#include "defs.h" +#include "dict.h" +#include "sysdep.h" +#include "debug.h" +#include "elf.h" +#include "read_config_file.h" + +#if defined HAVE_LIBIBERTY || defined HAVE_LIBSUPC__ +# define USE_DEMANGLE +#endif + +extern char * command; + +extern int exiting; /* =1 if we have to exit ASAP */ + +typedef struct Breakpoint Breakpoint; +struct Breakpoint { + void * addr; + unsigned char orig_value[BREAKPOINT_LENGTH]; + int enabled; + struct library_symbol * libsym; +#ifdef __arm__ + int thumb_mode; +#endif +}; + +enum arg_type { + ARGTYPE_UNKNOWN = -1, + ARGTYPE_VOID, + ARGTYPE_INT, + ARGTYPE_UINT, + ARGTYPE_LONG, + ARGTYPE_ULONG, + ARGTYPE_OCTAL, + ARGTYPE_CHAR, + ARGTYPE_SHORT, + ARGTYPE_USHORT, + ARGTYPE_FLOAT, /* float value, may require index */ + ARGTYPE_DOUBLE, /* double value, may require index */ + ARGTYPE_ADDR, + ARGTYPE_FILE, + ARGTYPE_FORMAT, /* printf-like format */ + ARGTYPE_STRING, /* NUL-terminated string */ + ARGTYPE_STRING_N, /* String of known maxlen */ + ARGTYPE_ARRAY, /* Series of values in memory */ + ARGTYPE_ENUM, /* Enumeration */ + ARGTYPE_STRUCT, /* Structure of values */ + ARGTYPE_POINTER, /* Pointer to some other type */ + ARGTYPE_COUNT /* number of ARGTYPE_* values */ +}; + +typedef struct arg_type_info_t { + enum arg_type type; + union { + /* ARGTYPE_ENUM */ + struct { + size_t entries; + char ** keys; + int * values; + } enum_info; + + /* ARGTYPE_ARRAY */ + struct { + struct arg_type_info_t * elt_type; + size_t elt_size; + int len_spec; + } array_info; + + /* ARGTYPE_STRING_N */ + struct { + int size_spec; + } string_n_info; + + /* ARGTYPE_STRUCT */ + struct { + struct arg_type_info_t ** fields; /* NULL-terminated */ + size_t * offset; + size_t size; + } struct_info; + + /* ARGTYPE_POINTER */ + struct { + struct arg_type_info_t * info; + } ptr_info; + + /* ARGTYPE_FLOAT */ + struct { + size_t float_index; + } float_info; + + /* ARGTYPE_DOUBLE */ + struct { + size_t float_index; + } double_info; + } u; +} arg_type_info; + +enum tof { + LT_TOF_NONE = 0, + LT_TOF_FUNCTION, /* A real library function */ + LT_TOF_FUNCTIONR, /* Return from a real library function */ + LT_TOF_SYSCALL, /* A syscall */ + LT_TOF_SYSCALLR, /* Return from a syscall */ + LT_TOF_STRUCT /* Not a function; read args from struct */ +}; + +typedef struct Function Function; +struct Function { + const char * name; + arg_type_info * return_info; + int num_params; + arg_type_info * arg_info[MAX_ARGS]; + int params_right; + Function * next; +}; + +enum toplt { + LS_TOPLT_NONE = 0, /* PLT not used for this symbol. */ + LS_TOPLT_EXEC, /* PLT for this symbol is executable. */ + LS_TOPLT_POINT /* PLT for this symbol is a non-executable. */ +}; + +extern Function * list_of_functions; +extern char *PLTs_initialized_by_here; + +struct library_symbol { + char * name; + void * enter_addr; + char needs_init; + enum toplt plt_type; + char is_weak; + struct library_symbol * next; +}; + +struct callstack_element { + union { + int syscall; + struct library_symbol * libfunc; + } c_un; + int is_syscall; + void * return_addr; + struct timeval time_spent; +}; + +#define MAX_CALLDEPTH 64 + +typedef enum Process_State Process_State; +enum Process_State { + STATE_ATTACHED = 0, + STATE_BEING_CREATED, + STATE_IGNORED /* ignore this process (it's a fork and no -f was used) */ +}; + +struct Process { + Process_State state; + Process * parent; /* needed by STATE_BEING_CREATED */ + char * filename; + pid_t pid; + Dict * breakpoints; + int breakpoints_enabled; /* -1:not enabled yet, 0:disabled, 1:enabled */ + int mask_32bit; /* 1 if 64-bit ltrace is tracing 32-bit process */ + unsigned int personality; + int tracesysgood; /* signal indicating a PTRACE_SYSCALL trap */ + + int callstack_depth; + struct callstack_element callstack[MAX_CALLDEPTH]; + struct library_symbol * list_of_symbols; + + /* Arch-dependent: */ + void * instruction_pointer; + void * stack_pointer; /* To get return addr, args... */ + void * return_addr; + Breakpoint * breakpoint_being_enabled; + void * arch_ptr; + short e_machine; + short need_to_reinitialize_breakpoints; +#ifdef __arm__ + int thumb_mode; /* ARM execution mode: 0: ARM, 1: Thumb */ +#endif + + /* output: */ + enum tof type_being_displayed; + + Process * next; +}; + +struct opt_c_struct { + int count; + struct timeval tv; +}; + +#include "options.h" +#include "output.h" +#ifdef USE_DEMANGLE +#include "demangle.h" +#endif + +extern Dict * dict_opt_c; + +extern Process * list_of_processes; + +extern Event * next_event(void); +extern Process * pid2proc(pid_t pid); +extern void handle_event(Event * event); +extern void execute_program(Process *, char **); +extern int display_arg(enum tof type, Process * proc, int arg_num, arg_type_info * info); +extern Breakpoint * address2bpstruct(Process * proc, void * addr); +extern void breakpoints_init(Process * proc); +extern void insert_breakpoint(Process * proc, void * addr, struct library_symbol * libsym); +extern void delete_breakpoint(Process * proc, void * addr); +extern void enable_all_breakpoints(Process * proc); +extern void disable_all_breakpoints(Process * proc); +extern void reinitialize_breakpoints(Process *); + +extern Process * open_program(char * filename, pid_t pid); +extern void open_pid(pid_t pid); +extern void show_summary(void); +extern arg_type_info * lookup_prototype(enum arg_type at); + +/* Arch-dependent stuff: */ +extern char * pid2name(pid_t pid); +extern void trace_set_options(Process * proc, pid_t pid); +extern void trace_me(void); +extern int trace_pid(pid_t pid); +extern void untrace_pid(pid_t pid); +extern void get_arch_dep(Process * proc); +extern void * get_instruction_pointer(Process * proc); +extern void set_instruction_pointer(Process * proc, void * addr); +extern void * get_stack_pointer(Process * proc); +extern void * get_return_addr(Process * proc, void * stack_pointer); +extern void set_return_addr(Process * proc, void * addr); +extern void enable_breakpoint(pid_t pid, Breakpoint * sbp); +extern void disable_breakpoint(pid_t pid, const Breakpoint * sbp); +extern int syscall_p(Process * proc, int status, int * sysnum); +extern void continue_process(pid_t pid); +extern void continue_after_signal(pid_t pid, int signum); +extern void continue_after_breakpoint(Process * proc, Breakpoint * sbp); +extern void continue_enabling_breakpoint(pid_t pid, Breakpoint * sbp); +extern long gimme_arg(enum tof type, Process * proc, int arg_num, arg_type_info * info); +extern void save_register_args(enum tof type, Process * proc); +extern int umovestr(Process * proc, void * addr, int len, void * laddr); +extern int umovelong (Process * proc, void * addr, long * result, arg_type_info * info); +extern int ffcheck(void * maddr); +extern void * sym2addr(Process *, struct library_symbol *); + +#if 0 /* not yet */ +extern int umoven(Process * proc, void * addr, int len, void * laddr); +#endif diff --git a/configure b/configure new file mode 100755 index 0000000..d5392a0 --- /dev/null +++ b/configure @@ -0,0 +1,157 @@ +#!/bin/sh + +if [ ! -f libltrace.c ] +then + echo "configure: error: cannot find sources (libltrace.c)" 1>&2 + exit 1 +fi + +echo -n "checking package name... " +PACKAGE_NAME='ltrace' +echo $PACKAGE_NAME + +echo -n "checking $PACKAGE_NAME version... " +PACKAGE_VERSION=$( cat VERSION ) +echo $PACKAGE_VERSION + +echo -n "checking HOST_OS... " +HOST_OS=$( uname -s ) +if [ "$HOST_OS" = "Linux" ] +then + HOST_OS="linux-gnu" +fi +echo $HOST_OS + +# HAVE_LIBIBERTY +echo -n "checking for cplus_demangle in -liberty... " +cat > conftest.c << EOF +char cplus_demangle(); +int main () { + return cplus_demangle(); +} +EOF +if gcc conftest.c -liberty 2>/dev/null +then + HAVE_LIBIBERTY=1 + echo "yes" +else + unset HAVE_LIBIBERTY + echo "no" +fi +rm -f conftest.c a.out + +# HAVE_LIBSUPC__ +echo -n "checking for __cxa_demangle in -lsupc++... " +cat > conftest.c << EOF +char __cxa_demangle(); +int main () { + return __cxa_demangle(); +} +EOF +if gcc conftest.c -lsupc++ 2>/dev/null +then + HAVE_LIBSUPC__=1 + echo "yes" +else + unset HAVE_LIBSUPC__ + echo "no" +fi +rm -f conftest.c a.out + +# HAVE_ELF_C_READ_MMAP +echo -n "checking whether elf_begin accepts ELF_C_READ_MMAP... " +cat > conftest.c << EOF +#include +int main () { + Elf *elf = elf_begin (4, ELF_C_READ_MMAP, 0); + return 0; +} +EOF +if gcc conftest.c 2>/dev/null +then + HAVE_ELF_C_READ_MMAP=1 + echo "yes" +else + unset HAVE_ELF_C_READ_MMAP + echo "no" +fi +rm -f conftest.c a.out + +CC=gcc +CPPFLAGS=' -I /usr/include/libelf' +CFLAGS='-g -O2' +LIBS='-lelf -lsupc++ -liberty ' +INSTALL='/usr/bin/install -c' +iquote='-iquote ' +iquoteend='' + +prefix=/usr/local +sysconfdir='${prefix}/etc' +bindir='${prefix}/bin' +mandir='${prefix}/share/man' +docdir='${prefix}/share/doc/ltrace' +for x_option +do + if test -n "$x_prev"; then + eval $x_prev=\$x_option + x_prev= + continue + fi + case $x_option in + --*=* | *=*) + x_var=`echo $x_option | sed 's/^--//' | sed 's/=.*//'` + x_val=`echo $x_option | sed 's/^.*=//'` + eval $x_var=$x_val + ;; + --*) + x_prev=`echo $x_option | sed 's/^--//'` + ;; + esac +done + +echo "configure: creating Makefile" +# +# Makefile.in -> Makefile +# +x_subst_vars='PACKAGE_VERSION HOST_OS INSTALL CC CPPFLAGS CFLAGS LDFLAGS LIBS iquote iquoteend prefix sysconfdir mandir docdir' + +for i in $x_subst_vars +do + x_val=`eval echo \\"\\$$i\\"` + x_sed="$x_sed +s&@$i@&$x_val&g" +done + +sed "$x_sed" Makefile.in > Makefile + +echo "configure: creating config.h" +# +# config.h +# +exec > config.h + +echo '#define PACKAGE_NAME "ltrace"' +echo '#define PACKAGE_VERSION "'$PACKAGE_VERSION'"' + +if [ "$HAVE_LIBIBERTY" ] +then + echo '#define HAVE_LIBIBERTY 1' +else + echo '#undef HAVE_LIBIBERTY' +fi + +if [ "$HAVE_LIBSUPC__" ] +then + echo '#define HAVE_LIBSUPC__ 1' +else + echo '#undef HAVE_LIBSUPC__' +fi + +if [ "$HAVE_ELF_C_READ_MMAP" ] +then + echo '#define HAVE_ELF_C_READ_MMAP 1' +else + echo '#undef HAVE_ELF_C_READ_MMAP' +fi + +exit 0 diff --git a/debian/changelog b/debian/changelog new file mode 100644 index 0000000..f97cb8f --- /dev/null +++ b/debian/changelog @@ -0,0 +1,652 @@ +ltrace (0.5.3-1) unstable; urgency=low + + * New upstream release + * Make it work again in sparc with new kernel headers (closes: Bug#532195) + + -- Juan Cespedes Sat, 25 Jul 2009 16:24:38 +0200 + +ltrace (0.5.2-2) unstable; urgency=low + + * Make clone() work when child starts after parent finishes + * See syscalls as syscalls and not sysrets when we are a clone + + -- Juan Cespedes Thu, 28 May 2009 16:30:08 +0200 + +ltrace (0.5.2-1) unstable; urgency=low + + * New upstream release (closes: Bug#463023) + * New approach for following forks; it should now attach + every newly created process (closes: Bug#483827) + * Fixed SEGFAULT when killing ltrace with SIGINT or SIGTERM (closes: #458923) + + -- Juan Cespedes Thu, 21 May 2009 19:16:22 +0200 + +ltrace (0.5.1-2) unstable; urgency=low + + * Red-added armel and armeb to debian/control (closes: Bug#463023) + + -- Juan Cespedes Tue, 16 Dec 2008 13:00:50 +0100 + +ltrace (0.5.1-1) unstable; urgency=low + + * New upstream release, fixing many bugs + (thanks to Petr Machata, Luis Machado...) + * Acknowledged NMU (Closes: Bug#463023) + * Update Standards-Version (3.8.0), no changes + + -- Juan Cespedes Wed, 10 Dec 2008 18:41:20 +0100 + +ltrace (0.5-3.1) unstable; urgency=low + + * Non-maintainer upload. + * Big thanks for Anderson Lizardo for providing patches! + * Add generic support for arm targets, Closes: #176413 + * Save funtion arguments on arm, Closes: #462530 + * Add thumb instruction support, Closes: #462531 + * Add basic arm/eabi support, Closes: #450931 + * fix exec() testcase cleanup, Closes: #462532 + * fix memory corruption in clone() test, Closes: #462533 + * fix tracing child with "-p" option, Closes: #462535 + * Update standard, no changes + + -- Riku Voipio Tue, 29 Jan 2008 00:26:50 +0200 + +ltrace (0.5-3) unstable; urgency=low + + * Really fix compilation problems in ppc (!) + + -- Juan Cespedes Fri, 31 Aug 2007 19:04:03 +0200 + +ltrace (0.5-2) unstable; urgency=low + + * Fixed compilation issue in ppc + + -- Juan Cespedes Fri, 31 Aug 2007 13:53:27 +0200 + +ltrace (0.5-1) unstable; urgency=low + + * New upstream version + * Remove some unneeded files in /usr/share/doc (ChangeLog, COPYING...) + * Fix several typos (closes: Bug#372928) + * Added more system calls to ltrace.conf + + -- Juan Cespedes Thu, 30 Aug 2007 14:54:44 +0200 + +ltrace (0.4-2) unstable; urgency=low + + * Use fclose() to close the output file when using option '-o' + (thanks to GuiJianfeng ) + + -- Juan Cespedes Tue, 07 Aug 2007 11:49:27 +0200 + +ltrace (0.4-1) unstable; urgency=low + + * Rebase code from Redhat patches, now everything lives in SVN + * Closes: #297483,#315889,#318009 -- add PowerPC64 support + * Add s390x, ppc64 support + * This removes the patch from #257903 as it seems unnecessary now. + + -- Ian Wienand Tue, 21 Feb 2006 09:23:09 +1100 + +ltrace (0.3.38-1) unstable; urgency=low + + * Closes: 306862 -- Add IA64 support + + -- Ian Wienand Fri, 17 Feb 2006 11:17:46 +1100 + +ltrace (0.3.37-2) unstable; urgency=low + + * Convert to use CDBS + * Use CDBS to build control; you need to run + DEB_AUTO_UPDATE_DEBIAN_CONROL=yes ./debian/rules clean + to make the control file if you checkout from CVS + * Remove autoconf from build-deps, fix up upstream dist target so we don't + need it. + + -- Ian Wienand Thu, 16 Feb 2006 22:56:14 +1100 + +ltrace (0.3.37-1) unstable; urgency=low + + [ Ian Wienand ] + * Non-maintainer upload + * Start a "friendly takeover" from Juan + * Closes: #127503,#280608 -- update man page typos + * Closes: #339348 -- fix putenv typo in ltrace.conf + * Closes: #257903 -- incorporate variable length args patch + * Closes: #282051 -- demange names when -c used with -C + * Closes: #352389 -- pass build flags through to Makefile + * Closes: #155571 -- add note in man page about dlopened libraries + * See "upstream" ChangeLog for other changes (mostly warning fixes) + * Update README to point to Alioth home: http://ltrace.alioth.debian.org + + [ Christoph Berg ] + * Create non-native package. + * Add autoconf to build-deps + + -- Ian Wienand Thu, 16 Feb 2006 11:51:32 +1100 + +ltrace (0.3.36-2) unstable; urgency=low + + * Corrected path for Debian changelog + + -- Juan Cespedes Wed, 10 Nov 2004 00:33:21 +0100 + +ltrace (0.3.36-1) unstable; urgency=low + + * Changed distribution to pristine source + * New Standards-Version (3.6.1) + * Fixed "--indent" option (closes: Bug#265185) + + -- Juan Cespedes Wed, 10 Nov 2004 00:14:19 +0100 + +ltrace (0.3.35.1) unstable; urgency=low + + * Non-maintainer upload + * Applied patch from Jakub Jelinek to fix problems with + binaries built with recent binutils (closes: #274955) + * Applied patch from Jakub Jelinek to add long/ulong types to ltrace.conf + for amd64 + * Applied patch from Jakub Jelinek to fix -C + * Applied patch from Jakub Jelinek to update syscallent.h + * debian/control: build-depend on dpatch and libelfg0-dev + * debian/rules: add dpatch support + * debian/changelog: convert to utf-8 + + -- Andrew Pollock Fri, 22 Oct 2004 21:43:16 +1000 + +ltrace (0.3.35) unstable; urgency=low + + * Fixed include line in m68k, caused build problems + + -- Juan Cespedes Fri, 16 Jul 2004 18:00:10 +0200 + +ltrace (0.3.34) unstable; urgency=low + + * Fixed prototype declaration problem in arm, m68k, powerpc, s390 + * Added "amd64" to list of architectures (closes: Bug#252756) + * Sparc port is hopefully working (closes: Bug#35524) + + -- Juan Cespedes Wed, 07 Jul 2004 10:40:56 +0200 + +ltrace (0.3.33) unstable; urgency=low + + * Fixed two bugs, thanks to Mauro Meneghin : + + Cope correctly with breakpoint values greater than + sizeof(long) bytes + + Fixed small bug in option -r (closes: Bug#212792) + * Show help if no (or few) arguments are given, just like + strace and fenris (thanks, Tomasz Wegrzanowski ) + * Some fixes from Jakub Bogusz : + + Small 64-bit cleanup of code + + support for more than 6 function arguments on amd64 + + Adapted SPARC port from Jakub Jelinek + + Added alpha support + + -- Juan Cespedes Mon, 14 Jun 2004 18:01:12 +0200 + +ltrace (0.3.32) unstable; urgency=low + + * Fixed wrong version number + * Removed unused file "opt_c.c" + * Remove error when tracing no calls and doing fork() + * Clean-up of sysdeps/linux-gnu/s390/trace.c + * Clean-up of sysdeps/linux-gnu/ppc/trace.c + * Make `--library' option really work (closes: Bug#232321) + * Merged several patches from SuSE: + + Added some functions to ltrace.conf + + Handle 64-big ELF files nicely + + AMD64 support + + Updated list of syscalls for S/390 + + Improved some debugging statements + Many thanks to Bernhard Kaindl for his great work + + -- Juan Cespedes Sun, 04 Apr 2004 01:31:37 +0200 + +ltrace (0.3.31) unstable; urgency=low + + * Added a lot of functions to ltrace.conf, + thanks to Jakub Jelinek (closes: Bug#144518) + * Fixed off-by-one problem in checking syscall number + * Removed some warnings + + -- Juan Cespedes Tue, 04 Feb 2003 23:22:46 +0100 + +ltrace (0.3.30) unstable; urgency=low + + * Implemented -T option (show time spent inside each call) + * Alphabetically sort options in help and manual page + * Added -c option (summary of calls on program exit) + + -- Juan Cespedes Mon, 03 Feb 2003 00:22:28 +0100 + +ltrace (0.3.29) unstable; urgency=low + + * Align return values depending on screen width + * Updated list of syscalls and signals to Linux 2.4.20 + * Fixed bug introduced in 0.3.27 which caused -L option to segfault + + -- Juan Cespedes Sat, 01 Feb 2003 19:01:39 +0100 + +ltrace (0.3.28) unstable; urgency=medium + + * Fixed memory corruption when using execve() in a traced program + (closes: Bug#160341, Bug#165626) + + -- Juan Cespedes Fri, 31 Jan 2003 19:51:28 +0100 + +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 Fri, 31 Jan 2003 18:58:55 +0100 + +ltrace (0.3.26) unstable; urgency=low + + * Fixed `ltrace -L' in powerpc + + -- Juan Cespedes Sun, 31 Mar 2002 20:53:49 +0200 + +ltrace (0.3.25) unstable; urgency=low + + * Finally added powerpc support (Anton Blanchard ) + + -- Juan Cespedes Sun, 31 Mar 2002 19:58:25 +0200 + +ltrace (0.3.24) unstable; urgency=low + + * Fixed 2 minor buffer overflows (closes: Bug#130746) + * Obey --prefix, --sysconfdir, --mandir options in configure + * Adding powerpc support (doesn't work yet) + (Anton Blanchard ) + + -- Juan Cespedes Wed, 27 Mar 2002 00:20:57 +0100 + +ltrace (0.3.23) unstable; urgency=low + + * Fixed missing include in trace.c + * One arch-dependent function less (continue_after_breakpoint) + * Fixed S/390 port (it didn't compile yet...) + + -- Juan Cespedes Sun, 3 Mar 2002 18:58:36 +0100 + +ltrace (0.3.22) unstable; urgency=low + + * S/390: Removed extra target in sysdeps/linux-gnu/s390 which avoided + compiling... + + -- Juan Cespedes Sun, 3 Mar 2002 14:04:38 +0100 + +ltrace (0.3.21) unstable; urgency=low + + * Get rid of arch/breakpoint.c; we can do it arch-independent + + -- Juan Cespedes Sun, 3 Mar 2002 02:37:46 +0100 + +ltrace (0.3.20) unstable; urgency=low + + * Added s390 port (Timothy R. Fesig ) + * Modified configure process to use ltrace.spec.in to generate + ltrace.spec (Timothy R. Fesig ) + * Fixed some problems using ltrace.spec on Intel platform. + (Timothy R. Fesig ) + + -- Juan Cespedes Sat, 2 Mar 2002 23:33:00 +0100 + +ltrace (0.3.19) unstable; urgency=low + + * Fixed small bug: "" lines were sometimes incorrectly + displayed + * Added new functions to /etc/ltrace.conf (thanks to James R. Van Zandt + ) (closes: Bug#91349) + + -- Juan Cespedes Fri, 1 Mar 2002 21:05:37 +0100 + +ltrace (0.3.18) unstable; urgency=low + + * Simplified arch-dependent stuff + * Updated list of syscalls and signals to Linux 2.4.18 + * Unified coding-style of all function declarations + * Do not indent lines indicating signals, exit codes, etc + * Updated description + * fix off-by-one problem in checking syscall number (Tim Waugh + fixed this problem in RedHat two years ago; + thank you for NOT noticing me...) + + -- Juan Cespedes Fri, 1 Mar 2002 19:52:43 +0100 + +ltrace (0.3.17) unstable; urgency=low + + * Added a bit more debugging + * Fixed display of return address in nested functions + * Added posibility to exit from a function different from the last called + one (this fixes "ltrace gnome-terminal", for example) + + -- Juan Cespedes Mon, 25 Feb 2002 00:19:19 +0100 + +ltrace (0.3.16) unstable; urgency=low + + * ltrace works again after an execve is received (closes: Bug#108835) + * Added prototypes for fnmatch() and bsearch() (closes: Bug#106862) + * Re-wrote short description so it does not exceed 60 chars + (closes: Bug#114682) + + -- Juan Cespedes Mon, 10 Dec 2001 04:11:26 +0100 + +ltrace (0.3.15) unstable; urgency=low + + * Fixed `-n' option so that it displays correct output even when + tracing several processes + + -- Juan Cespedes Mon, 9 Jul 2001 01:02:46 +0200 + +ltrace (0.3.14) unstable; urgency=low + + * Assume a syscall is always immediatly followed by a sysret + in i386 (fixes bug which prevented ltrace to work properly + in any program using signals); I will have to rethink all + this and fix it correctly or port it to non-i386 archs + * Fixed -n option: now it is done in output.c (this still has + problems when tracing more than one process at a time) + + -- Juan Cespedes Sat, 7 Jul 2001 20:56:42 +0200 + +ltrace (0.3.13) unstable; urgency=low + + * Fixed "ltrace -i", broken since version 0.3.11 + + -- Juan Cespedes Tue, 3 Jul 2001 18:36:15 +0200 + +ltrace (0.3.12) unstable; urgency=low + + * Re-wrote of "elf.c" (Silvio Cesare ) + * Added "--library" option (Silvio) + * Updated list of syscalls and signals to Linux 2.4.5 + * Compile cleanly with gcc-3.0 (thanks to Frédéric L. W. Meunier) + + -- Juan Cespedes Tue, 3 Jul 2001 00:43:25 +0200 + +ltrace (0.3.11) unstable; urgency=low + + * Clean up lintian bugs + * Fixed small bug reading start of arguments in config file + * Keep a stack of nested calls (Morten Eriksen, 1999-07-04) + * Add "--indent" option (Morten Eriksen, 1999-07-04) + * cleans up connection between a breakpoint address and + a call instance (Morten Eriksen, 1999-07-04) + * New Standards-Version (3.5.5) + + -- Juan Cespedes Mon, 2 Jul 2001 00:24:11 +0200 + +ltrace (0.3.10) unstable; urgency=low + + * Added C++ demangle (again) + * Added correct Build-Depends + + -- Juan Cespedes Thu, 23 Dec 1999 00:22:33 +0100 + +ltrace (0.3.9) unstable; urgency=low + + * New Standards-Version (3.1.1) + * Fixed Lintian bugs + + -- Juan Cespedes Sun, 19 Dec 1999 17:49:40 +0100 + +ltrace (0.3.8) unstable; urgency=low + + * glibc-2.1 does no longer need `_GNU_SOURCE' defined to use + * Changed description of package; adopted Red Hat's one + (thanks to whoever wrote it) + * Close all the file descriptors used before executing program (close-on-exec) + * Updated copyright file for new location /usr/share/common-licenses/GPL. + * Used GNU autoconf instead of "uname" to guess host system type + * Install man page in /usr/share/man instead of /usr/man + * Added a few functions to /etc/ltrace.conf + * Updated list of syscalls and signals to linux-2.2.12 + * Fixed bugs in C++ demangle (Morten Eriksen ) + * New Standards-Version: 3.0.1 (but keeping docs in /usr/doc) + + -- Juan Cespedes Mon, 30 Aug 1999 19:34:47 +0200 + +ltrace (0.3.7) unstable; urgency=low + + * Minor fixes + * Added minor patch from Alex Buell + to be able to compile under glibc 2.1 + * Additions to config file from David Dyck + * Clean-up Makefile a bit + * Changed `LT_PT_*' with `ARGTYPE_*' + * Display '\\' instead of '\' + * Updated list of syscalls and signals to linux-2.2.5 + * Compiled against glibc-2.1 + + -- Juan Cespedes Sat, 3 Apr 1999 03:21:50 +0200 + +ltrace (0.3.6) unstable; urgency=low + + * Added m68k port (Roman Hodek ) (Bug#27075) + * Changed "int pid" with "pid_t pid" everywhere + * Fixed return type of some functions from "int" to "void *" (thanks, Roman) + + -- Juan Cespedes Fri, 25 Sep 1998 14:48:37 +0200 + +ltrace (0.3.5) unstable; urgency=low + + * Added ARMLinux port (Pat Beirne ) (Bug#27040) + * Fixed minor things in options.c + + -- Juan Cespedes Thu, 24 Sep 1998 13:18:01 +0200 + +ltrace (0.3.4) unstable; urgency=low + + * Added "ltrace.spec" to build a .rpm binary file. + * Added "-r" option + + -- Juan Cespedes Sun, 20 Sep 1998 21:22:05 +0200 + +ltrace (0.3.3) unstable; urgency=low + + * Fixed a little bug in display_string + * A few more functions added to /etc/ltrace.conf + + -- Juan Cespedes Sun, 6 Sep 1998 14:03:10 +0200 + +ltrace (0.3.2) unstable; urgency=low + + * Make the output line-buffered (Bug#22874) + * New Standards-Version (2.4.1) + * Make it compile cleanly with glibc 2.0.7 + + -- Juan Cespedes Tue, 14 Jul 1998 13:45:24 +0200 + +ltrace (0.3.1) frozen unstable; urgency=low + + * setgid programs had their uid and gid swapped! Fixed. + + -- Juan Cespedes Wed, 29 Apr 1998 19:25:11 +0200 + +ltrace (0.3.0) unstable; urgency=low + + * Preliminary autoconf support + * Switched to getopt() + * New option: -C (demangle C++ names) + * New options: --help, --version + * Display "format" (printf-like) argument types + * Updated manual page + * New option: -e + + -- Juan Cespedes Sat, 25 Apr 1998 14:21:59 +0200 + +ltrace (0.2.9) frozen unstable; urgency=low + + * Bug#20616 wasn't completely fixed; it didn't work with some programs (Fixed) + * Stopping ltrace with ^C DIDN'T WORK if -p option is not used!! (Fixed) + * Option -f caused program to segfault; fixed + * Fixed nasty bug about executing set[ug]id binaries: + When executing a program fails, don't left the program STOPPED. + * Make ltrace work with all setuid and setgid binaries when invoked as root + + -- Juan Cespedes Sat, 11 Apr 1998 22:50:38 +0200 + +ltrace (0.2.8) frozen unstable; urgency=low + + * Fix important bug regarding -p: disable all breakpoints on exit (Bug#20616) + * Compile cleanly on libc5 + * Added `-t' option (Bug#20615) + + -- Juan Cespedes Sat, 4 Apr 1998 08:34:03 +0200 + +ltrace (0.2.7) unstable; urgency=low + + * Some minor fixes + + -- Juan Cespedes Sun, 15 Mar 1998 14:01:40 +0100 + +ltrace (0.2.6) unstable; urgency=low + + * Option `-f' now works (but it fails to attach some processes...) + * Output is now more similar to strace's + + -- Juan Cespedes Sat, 14 Mar 1998 20:50:16 +0100 + +ltrace (0.2.5) unstable; urgency=low + + * After a successful execve(), library calls are now logged + * Enhanced displaying of non-printable chars + * Added some functions to /etc/ltrace.conf + + -- Juan Cespedes Fri, 13 Mar 1998 19:16:47 +0100 + +ltrace (0.2.4) unstable; urgency=low + + * Option `-p' now works (but programs fail when ltrace is interrupted) + + -- Juan Cespedes Fri, 13 Mar 1998 00:29:10 +0100 + +ltrace (0.2.3) unstable; urgency=low + + * Don't display `...' in strings when limit of bytes is reached + * Added some functions to /etc/ltrace.conf + + -- Juan Cespedes Wed, 11 Mar 1998 23:33:14 +0100 + +ltrace (0.2.2) unstable; urgency=low + + * After a successful execve(), syscalls are now logged correctly + + -- Juan Cespedes Wed, 11 Mar 1998 00:02:35 +0100 + +ltrace (0.2.1) unstable; urgency=low + + * Added -u option (run command as other username) + * Updated manual page a bit + + -- Juan Cespedes Tue, 10 Mar 1998 00:08:38 +0100 + +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 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... + + -- Juan Cespedes Sun, 26 Oct 1997 19:53:20 +0100 + +ltrace (0.1.6) experimental; urgency=low + + * New maintainer address + * New Standards-Version + + -- Juan Cespedes Thu, 11 Sep 1997 23:22:32 +0200 + +ltrace (0.1.5) experimental; urgency=low + + * `command' is now searched in the PATH + + -- Juan Cespedes Wed, 27 Aug 1997 22:27:33 +0200 + +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 Mon, 25 Aug 1997 16:08:36 +0200 + +ltrace (0.1.3) experimental; urgency=low + + * Added options `-i', `-S' + * Added syscall names + * Added signal names + * Added `output.c', `signal.c' + + -- Juan Cespedes Sun, 24 Aug 1997 01:45:49 +0200 + +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 Sat, 23 Aug 1997 15:00:23 +0200 + +ltrace (0.1.1) experimental; urgency=low + + * Added ``TODO'' + * Added symbols.c:disable_all_breakpoints + * Added ``process.[ch]'': init_sighandler, pid2proc + * Removed ``trace.c'' + * Added rudimentary support for multiple processes + * Now tracing syscalls (fork() needs a special treatment (TODO)) + * Added process.c:detach_process + * Added i386.c:trace_me,untrace_pid + + -- Juan Cespedes Sat, 23 Aug 1997 02:09:14 +0200 + +ltrace (0.1.0) experimental; urgency=low + + * Some clean-ups + * Added simple manual page + + -- Juan Cespedes Thu, 21 Aug 1997 17:01:36 +0200 + +ltrace (0.0.1997.08.14) experimental; urgency=low + + * Still re-structuring code... new file: symbols.c + + -- Juan Cespedes Thu, 14 Aug 1997 22:22:43 +0200 + +ltrace (0.0.1997.08.09) experimental; urgency=low + + * Added Debian files + * Re-structured most of the code; new files: elf.c, i386.c, trace.c + + -- Juan Cespedes Sat, 9 Aug 1997 20:55:24 +0200 diff --git a/debian/compat b/debian/compat new file mode 100644 index 0000000..7ed6ff8 --- /dev/null +++ b/debian/compat @@ -0,0 +1 @@ +5 diff --git a/debian/control.in b/debian/control.in new file mode 100644 index 0000000..aff5316 --- /dev/null +++ b/debian/control.in @@ -0,0 +1,23 @@ +Source: ltrace +Section: utils +Priority: optional +Maintainer: Juan Cespedes +Standards-Version: 3.8.2 +Build-Depends: @cdbs@, binutils-dev, libelfg0-dev + +Package: ltrace +Architecture: i386 arm armeb armel m68k s390 powerpc sparc alpha amd64 ia64 ppc64 +Depends: ${shlibs:Depends}, ${misc:Depends} +Description: Tracks runtime library calls in dynamically linked programs + ltrace is a debugging program which runs a specified command until it + exits. While the command is executing, ltrace intercepts and records + the dynamic library calls which are called by + the executed process and the signals received by that process. + It can also intercept and print the system calls executed by the program. + . + The program to be traced need not be recompiled for this, so you can + use it on binaries for which you don't have the source handy. + . + You should install ltrace if you need a sysadmin tool for tracking the + execution of processes. + diff --git a/debian/copyright b/debian/copyright new file mode 100644 index 0000000..facd682 --- /dev/null +++ b/debian/copyright @@ -0,0 +1,39 @@ +This is the Debian GNU/Linux's prepackaged version of the +Dynamic Library Tracer ``ltrace''. + +It was downloaded from http://www.ltrace.org/ + + +Copyrights +---------- +Copyright (C) 1997-2009 Juan Cespedes + +ARMLinux port: Copyright (C) 1998 Pat Beirne +m68k port: Copyright (C) 1998 Roman Hodek +Misc fixes: Copyright (C) 1999 Morten Eriksen +s390 port: Copyright (C) 2001 IBM Poughkeepsie, IBM Cororation +ELF hacking: Copyright (C) 1999 Silvio Cesare +PowerPC port: Copyright (C) 2001-2002 Anton Blanchard +SPARC port: Copyright (C) 1999 Jakub Jelinek + + +C++ demangle: Copyright 1989-1997 Free Software Foundation, Inc. + + +License +------- +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 +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +A copy of the GNU General Public License is available as +`/usr/share/common-licenses/GPL' 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA diff --git a/debian/rules b/debian/rules new file mode 100755 index 0000000..4105eb7 --- /dev/null +++ b/debian/rules @@ -0,0 +1,7 @@ +#!/usr/bin/make -f + +include /usr/share/cdbs/1/rules/debhelper.mk +include /usr/share/cdbs/1/class/autotools.mk + +install/ltrace:: + rm -f debian/ltrace/usr/share/doc/ltrace/* diff --git a/debug.c b/debug.c new file mode 100644 index 0000000..1be873b --- /dev/null +++ b/debug.c @@ -0,0 +1,112 @@ +#include +#include + +#include "common.h" + +void +debug_(int level, const char *file, int line, const char *fmt, ...) { + char buf[1024]; + va_list args; + + if (!(options.debug & level)) { + return; + } + va_start(args, fmt); + vsnprintf(buf, 1024, fmt, args); + va_end(args); + + output_line(NULL, "DEBUG: %s:%d: %s", file, line, buf); +} + +/* + * The following section provides a way to print things, like hex dumps, + * with out using buffered output. This was written by Steve Munroe of IBM. + */ + +#include +#include +#include +#include +#include + +static int +xwritehexl(long i) { + int rc = 0; + char text[17]; + int j; + unsigned long temp = (unsigned long)i; + + for (j = 15; j >= 0; j--) { + char c; + c = (char)((temp & 0x0f) + '0'); + if (c > '9') { + c = (char)(c + ('a' - '9' - 1)); + } + text[j] = c; + temp = temp >> 4; + } + + rc = write(1, text, 16); + return rc; +} + +static int +xwritec(char c) { + char temp = c; + char *text = &temp; + int rc = 0; + rc = write(1, text, 1); + return rc; +} + +static int +xwritecr(void) { + return xwritec('\n'); +} + +static int +xwritedump(void *ptr, long addr, int len) { + int rc = 0; + long *tprt = (long *)ptr; + int i; + + for (i = 0; i < len; i += 8) { + xwritehexl(addr); + xwritec('-'); + xwritec('>'); + xwritehexl(*tprt++); + xwritecr(); + addr += sizeof(long); + } + + return rc; +} + +int +xinfdump(long pid, void *ptr, int len) { + int rc; + int i; + long wrdcnt; + long *infwords; + long addr; + + wrdcnt = len / sizeof(long) + 1; + infwords = malloc(wrdcnt * sizeof(long)); + if (!infwords) { + perror("ltrace: malloc"); + exit(1); + } + addr = (long)ptr; + + addr = ((addr + sizeof(long) - 1) / sizeof(long)) * sizeof(long); + + for (i = 0; i < wrdcnt; ++i) { + infwords[i] = ptrace(PTRACE_PEEKTEXT, pid, addr); + addr += sizeof(long); + } + + rc = xwritedump(infwords, (long)ptr, len); + + free(infwords); + return rc; +} diff --git a/debug.h b/debug.h new file mode 100644 index 0000000..653da84 --- /dev/null +++ b/debug.h @@ -0,0 +1,17 @@ +#include + +/* debug levels: + */ +enum { + DEBUG_EVENT = 010, + DEBUG_PROCESS = 020, + DEBUG_FUNCTION = 040 +}; + +void debug_(int level, const char *file, int line, + const char *fmt, ...) __attribute__((format(printf,4,5))); + +int xinfdump(long, void *, int); + +# define debug(level, expr...) debug_(level, __FILE__, __LINE__, expr) + diff --git a/defs.h b/defs.h new file mode 100644 index 0000000..b694099 --- /dev/null +++ b/defs.h @@ -0,0 +1,18 @@ + +#ifndef DEFAULT_ALIGN +#define DEFAULT_ALIGN 50 /* default alignment column for results */ +#endif /* (-a switch) */ + +#ifndef MAX_ARGS +#define MAX_ARGS 32 /* maximum number of args for a function */ +#endif + +#ifndef DEFAULT_STRLEN +#define DEFAULT_STRLEN 32 /* default maximum # of bytes printed in */ +#endif /* strings (-s switch) */ + +#ifndef DEFAULT_ARRAYLEN +#define DEFAULT_ARRAYLEN 4 /* default maximum # array elements */ +#endif /* (-A switch) */ + +#define MAX_LIBRARIES 30 diff --git a/demangle.c b/demangle.c new file mode 100644 index 0000000..5825e28 --- /dev/null +++ b/demangle.c @@ -0,0 +1,44 @@ +#include "config.h" + +#include +#include +#include + +#include "common.h" + +#ifdef USE_DEMANGLE + +/*****************************************************************************/ + +static Dict *d = NULL; + +const char * +my_demangle(const char *function_name) { + const char *tmp, *fn_copy; +#if !defined HAVE_LIBIBERTY && defined HAVE_LIBSUPC__ + extern char *__cxa_demangle(const char *, char *, size_t *, int *); + int status = 0; +#endif + + debug(DEBUG_FUNCTION, "my_demangle(name=%s)", function_name); + + if (!d) + d = dict_init(dict_key2hash_string, dict_key_cmp_string); + + tmp = dict_find_entry(d, (void *)function_name); + if (!tmp) { + fn_copy = strdup(function_name); +#ifdef HAVE_LIBIBERTY + tmp = cplus_demangle(function_name, DMGL_ANSI | DMGL_PARAMS); +#elif defined HAVE_LIBSUPC__ + tmp = __cxa_demangle(function_name, NULL, NULL, &status); +#endif + if (!tmp) + tmp = fn_copy; + if (tmp) + dict_enter(d, (void *)fn_copy, (void *)tmp); + } + return tmp; +} + +#endif diff --git a/demangle.h b/demangle.h new file mode 100644 index 0000000..beac791 --- /dev/null +++ b/demangle.h @@ -0,0 +1,12 @@ +#include "config.h" + +extern char *cplus_demangle(const char *mangled, int options); + +const char *my_demangle(const char *function_name); + +/* Options passed to cplus_demangle (in 2nd parameter). */ + +#define DMGL_NO_OPTS 0 /* For readability... */ +#define DMGL_PARAMS (1 << 0) /* Include function args */ +#define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */ +#define DMGL_JAVA (1 << 2) /* Demangle as Java rather than C++. */ diff --git a/dict.c b/dict.c new file mode 100644 index 0000000..486a461 --- /dev/null +++ b/dict.c @@ -0,0 +1,215 @@ +#include +#include +#include +#include + +#include "common.h" + +/* + Dictionary based on code by Morten Eriksen . +*/ + +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 *); +}; + +Dict * +dict_init(unsigned int (*key2hash) (void *), + int (*key_cmp) (void *, void *)) { + Dict *d; + int i; + + debug(DEBUG_FUNCTION, "dict_init()"); + + d = malloc(sizeof(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(Dict *d) { + int i; + struct dict_entry *entry, *nextentry; + + debug(DEBUG_FUNCTION, "dict_clear()"); + assert(d); + 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(Dict *d, void *key, void *value) { + struct dict_entry *entry, *newentry; + unsigned int hash; + unsigned int bucketpos; + + debug(DEBUG_FUNCTION, "dict_enter()"); + + hash = d->key2hash(key); + bucketpos = hash % DICTTABLESIZE; + + assert(d); + 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)", d, bucketpos, key, value); + return 0; +} + +void * +dict_find_entry(Dict *d, void *key) { + unsigned int hash; + unsigned int bucketpos; + struct dict_entry *entry; + + debug(DEBUG_FUNCTION, "dict_find_entry()"); + + hash = d->key2hash(key); + bucketpos = hash % DICTTABLESIZE; + + assert(d); + 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(Dict *d, + void (*func) (void *key, void *value, void *data), void *data) { + int i; + + debug(DEBUG_FUNCTION, "dict_apply_to_all()"); + + if (!d) { + return; + } + 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; + + assert(key); + 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) { + assert(key1); + assert(key2); + return strcmp((const char *)key1, (const char *)key2); +} + +unsigned int +dict_key2hash_int(void *key) { + return (unsigned long)key; +} + +int +dict_key_cmp_int(void *key1, void *key2) { + return key1 - key2; +} + +Dict * +dict_clone(Dict *old, void * (*key_clone)(void*), void * (*value_clone)(void*)) { + Dict *d; + int i; + + debug(DEBUG_FUNCTION, "dict_clone()"); + + d = malloc(sizeof(Dict)); + if (!d) { + perror("malloc()"); + exit(1); + } + memcpy(d, old, sizeof(Dict)); + for (i = 0; i < DICTTABLESIZE; i++) { /* better use memset()? */ + struct dict_entry *de_old; + struct dict_entry **de_new; + + de_old = old->buckets[i]; + de_new = &d->buckets[i]; + while (de_old) { + *de_new = malloc(sizeof(struct dict_entry)); + if (!*de_new) { + perror("malloc()"); + exit(1); + } + memcpy(*de_new, de_old, sizeof(struct dict_entry)); + (*de_new)->key = key_clone(de_old->key); + (*de_new)->value = value_clone(de_old->value); + de_new = &(*de_new)->next; + de_old = de_old->next; + } + } + return d; +} diff --git a/dict.h b/dict.h new file mode 100644 index 0000000..a70c3d5 --- /dev/null +++ b/dict.h @@ -0,0 +1,20 @@ +/* + Dictionary based on code by Morten Eriksen . +*/ + +typedef struct dict Dict; + +extern Dict *dict_init(unsigned int (*key2hash) (void *), + int (*key_cmp) (void *, void *)); +extern void dict_clear(Dict *d); +extern int dict_enter(Dict *d, void *key, void *value); +extern void *dict_find_entry(Dict *d, void *key); +extern void dict_apply_to_all(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); +extern Dict * dict_clone(Dict *old, void * (*key_clone)(void*), void * (*value_clone)(void*)); diff --git a/display_args.c b/display_args.c new file mode 100644 index 0000000..993a808 --- /dev/null +++ b/display_args.c @@ -0,0 +1,460 @@ +#include +#include +#include +#include +#include + +#include "common.h" + +static int display_char(int what); +static int display_string(enum tof type, Process *proc, + void* addr, size_t maxlen); +static int display_value(enum tof type, Process *proc, + long value, arg_type_info *info, + void *st, arg_type_info* st_info); +static int display_unknown(enum tof type, Process *proc, long value); +static int display_format(enum tof type, Process *proc, int arg_num); + +static int string_maxlength = INT_MAX; +static int array_maxlength = INT_MAX; + +static long +get_length(enum tof type, Process *proc, int len_spec, + void *st, arg_type_info* st_info) { + long len; + arg_type_info info; + + if (len_spec > 0) + return len_spec; + if (type == LT_TOF_STRUCT) { + umovelong (proc, st + st_info->u.struct_info.offset[-len_spec-1], + &len, st_info->u.struct_info.fields[-len_spec-1]); + return len; + } + + info.type = ARGTYPE_INT; + return gimme_arg(type, proc, -len_spec-1, &info); +} + +static int +display_ptrto(enum tof type, Process *proc, long item, + arg_type_info * info, + void *st, arg_type_info* st_info) { + arg_type_info temp; + temp.type = ARGTYPE_POINTER; + temp.u.ptr_info.info = info; + return display_value(type, proc, item, &temp, st, st_info); +} + +/* + * addr - A pointer to the first element of the array + * + * The function name is used to indicate that we're not actually + * looking at an 'array', which is a contiguous region of memory + * containing a sequence of elements of some type; instead, we have a + * pointer to that region of memory. + */ +static int +display_arrayptr(enum tof type, Process *proc, + void *addr, arg_type_info * info, + void *st, arg_type_info* st_info) { + int len = 0; + int i; + int array_len; + + if (addr == NULL) + return fprintf(options.output, "NULL"); + + array_len = get_length(type, proc, info->u.array_info.len_spec, + st, st_info); + len += fprintf(options.output, "[ "); + for (i = 0; i < options.arraylen && i < array_maxlength && i < array_len; i++) { + arg_type_info *elt_type = info->u.array_info.elt_type; + size_t elt_size = info->u.array_info.elt_size; + if (i != 0) + len += fprintf(options.output, ", "); + if (options.debug) + len += fprintf(options.output, "%p=", addr); + len += + display_ptrto(type, proc, (long) addr, elt_type, st, st_info); + addr += elt_size; + } + if (i < array_len) + len += fprintf(options.output, "..."); + len += fprintf(options.output, " ]"); + return len; +} + +/* addr - A pointer to the beginning of the memory region occupied by + * the struct (aka a pointer to the struct) + */ +static int +display_structptr(enum tof type, Process *proc, + void *addr, arg_type_info * info) { + int i; + arg_type_info *field; + int len = 0; + + if (addr == NULL) + return fprintf(options.output, "NULL"); + + len += fprintf(options.output, "{ "); + for (i = 0; (field = info->u.struct_info.fields[i]) != NULL; i++) { + if (i != 0) + len += fprintf(options.output, ", "); + if (options.debug) + len += + fprintf(options.output, "%p=", + addr + info->u.struct_info.offset[i]); + len += + display_ptrto(LT_TOF_STRUCT, proc, + (long) addr + info->u.struct_info.offset[i], + field, addr, info); + } + len += fprintf(options.output, " }"); + + return len; +} + +static int +display_pointer(enum tof type, Process *proc, long value, + arg_type_info * info, + void *st, arg_type_info* st_info) { + long pointed_to; + arg_type_info *inner = info->u.ptr_info.info; + + if (inner->type == ARGTYPE_ARRAY) { + return display_arrayptr(type, proc, (void*) value, inner, + st, st_info); + } else if (inner->type == ARGTYPE_STRUCT) { + return display_structptr(type, proc, (void *) value, inner); + } else { + if (value == 0) + return fprintf(options.output, "NULL"); + else if (umovelong (proc, (void *) value, &pointed_to, + info->u.ptr_info.info) < 0) + return fprintf(options.output, "?"); + else + return display_value(type, proc, pointed_to, inner, + st, st_info); + } +} + +static int +display_enum(enum tof type, Process *proc, + arg_type_info* info, long value) { + int ii; + for (ii = 0; ii < info->u.enum_info.entries; ++ii) { + if (info->u.enum_info.values[ii] == value) + return fprintf(options.output, "%s", info->u.enum_info.keys[ii]); + } + + return display_unknown(type, proc, value); +} + +/* Args: + type - syscall or shared library function or memory + proc - information about the traced process + value - the value to display + info - the description of the type to display + st - if the current value is a struct member, the address of the struct + st_info - type of the above struct + + Those last two parameters are used for structs containing arrays or + strings whose length is given by another structure element. +*/ +int +display_value(enum tof type, Process *proc, + long value, arg_type_info *info, + void *st, arg_type_info* st_info) { + int tmp; + + switch (info->type) { + case ARGTYPE_VOID: + return 0; + case ARGTYPE_INT: + return fprintf(options.output, "%d", (int) value); + case ARGTYPE_UINT: + return fprintf(options.output, "%u", (unsigned) value); + case ARGTYPE_LONG: + if (proc->mask_32bit) + return fprintf(options.output, "%d", (int) value); + else + return fprintf(options.output, "%ld", value); + case ARGTYPE_ULONG: + if (proc->mask_32bit) + return fprintf(options.output, "%u", (unsigned) value); + else + return fprintf(options.output, "%lu", (unsigned long) value); + case ARGTYPE_OCTAL: + return fprintf(options.output, "0%o", (unsigned) value); + case ARGTYPE_CHAR: + tmp = fprintf(options.output, "'"); + tmp += display_char(value == -1 ? value : (char) value); + tmp += fprintf(options.output, "'"); + return tmp; + case ARGTYPE_SHORT: + return fprintf(options.output, "%hd", (short) value); + case ARGTYPE_USHORT: + return fprintf(options.output, "%hu", (unsigned short) value); + case ARGTYPE_FLOAT: { + union { long l; float f; double d; } cvt; + cvt.l = value; + return fprintf(options.output, "%f", cvt.f); + } + case ARGTYPE_DOUBLE: { + union { long l; float f; double d; } cvt; + cvt.l = value; + return fprintf(options.output, "%lf", cvt.d); + } + case ARGTYPE_ADDR: + if (!value) + return fprintf(options.output, "NULL"); + else + return fprintf(options.output, "0x%08lx", value); + case ARGTYPE_FORMAT: + fprintf(stderr, "Should never encounter a format anywhere but at the top level (for now?)\n"); + exit(1); + case ARGTYPE_STRING: + return display_string(type, proc, (void*) value, + string_maxlength); + case ARGTYPE_STRING_N: + return display_string(type, proc, (void*) value, + get_length(type, proc, + info->u.string_n_info.size_spec, st, st_info)); + case ARGTYPE_ARRAY: + return fprintf(options.output, ""); + case ARGTYPE_ENUM: + return display_enum(type, proc, info, value); + case ARGTYPE_STRUCT: + return fprintf(options.output, ""); + case ARGTYPE_POINTER: + return display_pointer(type, proc, value, info, + st, st_info); + case ARGTYPE_UNKNOWN: + default: + return display_unknown(type, proc, value); + } +} + +int +display_arg(enum tof type, Process *proc, int arg_num, arg_type_info * info) { + long arg; + + if (info->type == ARGTYPE_VOID) { + return 0; + } else if (info->type == ARGTYPE_FORMAT) { + return display_format(type, proc, arg_num); + } else { + arg = gimme_arg(type, proc, arg_num, info); + return display_value(type, proc, arg, info, NULL, NULL); + } +} + +static int +display_char(int what) { + switch (what) { + case -1: + return fprintf(options.output, "EOF"); + case '\r': + return fprintf(options.output, "\\r"); + case '\n': + return fprintf(options.output, "\\n"); + case '\t': + return fprintf(options.output, "\\t"); + case '\b': + return fprintf(options.output, "\\b"); + case '\\': + return fprintf(options.output, "\\\\"); + default: + if (isprint(what)) { + return fprintf(options.output, "%c", what); + } else { + return fprintf(options.output, "\\%03o", (unsigned char)what); + } + } +} + +#define MIN(a,b) (((a)<(b)) ? (a) : (b)) + +static int +display_string(enum tof type, Process *proc, void *addr, + size_t maxlength) { + unsigned char *str1; + int i; + int len = 0; + + if (!addr) { + return fprintf(options.output, "NULL"); + } + + str1 = malloc(MIN(options.strlen, maxlength) + 3); + if (!str1) { + return fprintf(options.output, "???"); + } + umovestr(proc, addr, MIN(options.strlen, maxlength) + 1, str1); + len = fprintf(options.output, "\""); + for (i = 0; i < MIN(options.strlen, maxlength); i++) { + if (str1[i]) { + len += display_char(str1[i]); + } else { + break; + } + } + len += fprintf(options.output, "\""); + if (str1[i] && (options.strlen <= maxlength)) { + len += fprintf(options.output, "..."); + } + free(str1); + return len; +} + +static int +display_unknown(enum tof type, Process *proc, long value) { + if (proc->mask_32bit) { + if ((int)value < 1000000 && (int)value > -1000000) + return fprintf(options.output, "%d", (int)value); + else + return fprintf(options.output, "%p", (void *)value); + } else if (value < 1000000 && value > -1000000) { + return fprintf(options.output, "%ld", value); + } else { + return fprintf(options.output, "%p", (void *)value); + } +} + +static int +display_format(enum tof type, Process *proc, int arg_num) { + void *addr; + unsigned char *str1; + int i; + int len = 0; + arg_type_info info; + + info.type = ARGTYPE_POINTER; + addr = (void *)gimme_arg(type, proc, arg_num, &info); + if (!addr) { + return fprintf(options.output, "NULL"); + } + + str1 = malloc(MIN(options.strlen, string_maxlength) + 3); + if (!str1) { + return fprintf(options.output, "???"); + } + umovestr(proc, addr, MIN(options.strlen, string_maxlength) + 1, str1); + len = fprintf(options.output, "\""); + for (i = 0; len < MIN(options.strlen, string_maxlength) + 1; i++) { + if (str1[i]) { + len += display_char(str1[i]); + } else { + break; + } + } + len += fprintf(options.output, "\""); + if (str1[i] && (options.strlen <= string_maxlength)) { + len += fprintf(options.output, "..."); + } + for (i = 0; str1[i]; i++) { + if (str1[i] == '%') { + int is_long = 0; + while (1) { + unsigned char c = str1[++i]; + if (c == '%') { + break; + } else if (!c) { + break; + } else if (strchr("lzZtj", c)) { + is_long++; + if (c == 'j') + is_long++; + if (is_long > 1 + && (sizeof(long) < sizeof(long long) + || proc->mask_32bit)) { + len += fprintf(options.output, ", ..."); + str1[i + 1] = '\0'; + break; + } + } else if (c == 'd' || c == 'i') { + info.type = ARGTYPE_LONG; + if (!is_long || proc->mask_32bit) + len += + fprintf(options.output, ", %d", + (int)gimme_arg(type, proc, ++arg_num, &info)); + else + len += + fprintf(options.output, ", %ld", + gimme_arg(type, proc, ++arg_num, &info)); + break; + } else if (c == 'u') { + info.type = ARGTYPE_LONG; + if (!is_long || proc->mask_32bit) + len += + fprintf(options.output, ", %u", + (int)gimme_arg(type, proc, ++arg_num, &info)); + else + len += + fprintf(options.output, ", %lu", + gimme_arg(type, proc, ++arg_num, &info)); + break; + } else if (c == 'o') { + info.type = ARGTYPE_LONG; + if (!is_long || proc->mask_32bit) + len += + fprintf(options.output, ", 0%o", + (int)gimme_arg(type, proc, ++arg_num, &info)); + else + len += + fprintf(options.output, ", 0%lo", + gimme_arg(type, proc, ++arg_num, &info)); + break; + } else if (c == 'x' || c == 'X') { + info.type = ARGTYPE_LONG; + if (!is_long || proc->mask_32bit) + len += + fprintf(options.output, ", %#x", + (int)gimme_arg(type, proc, ++arg_num, &info)); + else + len += + fprintf(options.output, ", %#lx", + gimme_arg(type, proc, ++arg_num, &info)); + break; + } else if (strchr("eEfFgGaACS", c) + || (is_long + && (c == 'c' || c == 's'))) { + len += fprintf(options.output, ", ..."); + str1[i + 1] = '\0'; + break; + } else if (c == 'c') { + info.type = ARGTYPE_LONG; + len += fprintf(options.output, ", '"); + len += + display_char((int) + gimme_arg(type, proc, ++arg_num, &info)); + len += fprintf(options.output, "'"); + break; + } else if (c == 's') { + info.type = ARGTYPE_POINTER; + len += fprintf(options.output, ", "); + len += + display_string(type, proc, + (void *)gimme_arg(type, proc, ++arg_num, &info), + string_maxlength); + break; + } else if (c == 'p' || c == 'n') { + info.type = ARGTYPE_POINTER; + len += + fprintf(options.output, ", %p", + (void *)gimme_arg(type, proc, ++arg_num, &info)); + break; + } else if (c == '*') { + info.type = ARGTYPE_LONG; + len += + fprintf(options.output, ", %d", + (int)gimme_arg(type, proc, ++arg_num, &info)); + } + } + } + } + free(str1); + return len; +} diff --git a/elf.c b/elf.c new file mode 100644 index 0000000..aeff211 --- /dev/null +++ b/elf.c @@ -0,0 +1,619 @@ +# include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" + +static void do_init_elf(struct ltelf *lte, const char *filename); +static void do_close_elf(struct ltelf *lte); +static void add_library_symbol(GElf_Addr addr, const char *name, + struct library_symbol **library_symbolspp, + enum toplt type_of_plt, int is_weak); +static int in_load_libraries(const char *name, struct ltelf *lte); +static GElf_Addr opd2addr(struct ltelf *ltc, GElf_Addr addr); + +#ifdef PLT_REINITALISATION_BP +extern char *PLTs_initialized_by_here; +#endif + +static void +do_init_elf(struct ltelf *lte, const char *filename) { + int i; + GElf_Addr relplt_addr = 0; + size_t relplt_size = 0; + + debug(DEBUG_FUNCTION, "do_init_elf(filename=%s)", filename); + debug(1, "Reading ELF from %s...", filename); + + memset(lte, 0, sizeof(*lte)); + lte->fd = open(filename, O_RDONLY); + if (lte->fd == -1) + error(EXIT_FAILURE, errno, "Can't open \"%s\"", filename); + +#ifdef HAVE_ELF_C_READ_MMAP + lte->elf = elf_begin(lte->fd, ELF_C_READ_MMAP, NULL); +#else + lte->elf = elf_begin(lte->fd, ELF_C_READ, NULL); +#endif + + if (lte->elf == NULL || elf_kind(lte->elf) != ELF_K_ELF) + error(EXIT_FAILURE, 0, "Can't open ELF file \"%s\"", filename); + + if (gelf_getehdr(lte->elf, <e->ehdr) == NULL) + error(EXIT_FAILURE, 0, "Can't read ELF header of \"%s\"", + filename); + + if (lte->ehdr.e_type != ET_EXEC && lte->ehdr.e_type != ET_DYN) + error(EXIT_FAILURE, 0, + "\"%s\" is not an ELF executable nor shared library", + filename); + + if ((lte->ehdr.e_ident[EI_CLASS] != LT_ELFCLASS + || lte->ehdr.e_machine != LT_ELF_MACHINE) +#ifdef LT_ELF_MACHINE2 + && (lte->ehdr.e_ident[EI_CLASS] != LT_ELFCLASS2 + || lte->ehdr.e_machine != LT_ELF_MACHINE2) +#endif +#ifdef LT_ELF_MACHINE3 + && (lte->ehdr.e_ident[EI_CLASS] != LT_ELFCLASS3 + || lte->ehdr.e_machine != LT_ELF_MACHINE3) +#endif + ) + error(EXIT_FAILURE, 0, + "\"%s\" is ELF from incompatible architecture", filename); + + for (i = 1; i < lte->ehdr.e_shnum; ++i) { + Elf_Scn *scn; + GElf_Shdr shdr; + const char *name; + + scn = elf_getscn(lte->elf, i); + if (scn == NULL || gelf_getshdr(scn, &shdr) == NULL) + error(EXIT_FAILURE, 0, + "Couldn't get section header from \"%s\"", + filename); + + name = elf_strptr(lte->elf, lte->ehdr.e_shstrndx, shdr.sh_name); + if (name == NULL) + error(EXIT_FAILURE, 0, + "Couldn't get section header from \"%s\"", + filename); + + if (shdr.sh_type == SHT_SYMTAB) { + Elf_Data *data; + + lte->symtab = elf_getdata(scn, NULL); + lte->symtab_count = shdr.sh_size / shdr.sh_entsize; + if ((lte->symtab == NULL + || elf_getdata(scn, lte->symtab) != NULL) + && opt_x != NULL) + error(EXIT_FAILURE, 0, + "Couldn't get .symtab data from \"%s\"", + filename); + + scn = elf_getscn(lte->elf, shdr.sh_link); + if (scn == NULL || gelf_getshdr(scn, &shdr) == NULL) + error(EXIT_FAILURE, 0, + "Couldn't get section header from \"%s\"", + filename); + + data = elf_getdata(scn, NULL); + if (data == NULL || elf_getdata(scn, data) != NULL + || shdr.sh_size != data->d_size || data->d_off) + error(EXIT_FAILURE, 0, + "Couldn't get .strtab data from \"%s\"", + filename); + + lte->strtab = data->d_buf; + } else if (shdr.sh_type == SHT_DYNSYM) { + Elf_Data *data; + + lte->dynsym = elf_getdata(scn, NULL); + lte->dynsym_count = shdr.sh_size / shdr.sh_entsize; + if (lte->dynsym == NULL + || elf_getdata(scn, lte->dynsym) != NULL) + error(EXIT_FAILURE, 0, + "Couldn't get .dynsym data from \"%s\"", + filename); + + scn = elf_getscn(lte->elf, shdr.sh_link); + if (scn == NULL || gelf_getshdr(scn, &shdr) == NULL) + error(EXIT_FAILURE, 0, + "Couldn't get section header from \"%s\"", + filename); + + data = elf_getdata(scn, NULL); + if (data == NULL || elf_getdata(scn, data) != NULL + || shdr.sh_size != data->d_size || data->d_off) + error(EXIT_FAILURE, 0, + "Couldn't get .dynstr data from \"%s\"", + filename); + + lte->dynstr = data->d_buf; + } else if (shdr.sh_type == SHT_DYNAMIC) { + Elf_Data *data; + size_t j; + + data = elf_getdata(scn, NULL); + if (data == NULL || elf_getdata(scn, data) != NULL) + error(EXIT_FAILURE, 0, + "Couldn't get .dynamic data from \"%s\"", + filename); + + for (j = 0; j < shdr.sh_size / shdr.sh_entsize; ++j) { + GElf_Dyn dyn; + + if (gelf_getdyn(data, j, &dyn) == NULL) + error(EXIT_FAILURE, 0, + "Couldn't get .dynamic data from \"%s\"", + filename); +#ifdef __mips__ +/** + MIPS ABI Supplement: + + DT_PLTGOT This member holds the address of the .got section. + + DT_MIPS_SYMTABNO This member holds the number of entries in the + .dynsym section. + + DT_MIPS_LOCAL_GOTNO This member holds the number of local global + offset table entries. + + DT_MIPS_GOTSYM This member holds the index of the first dyamic + symbol table entry that corresponds to an entry in the gobal offset + table. + + */ + if(dyn.d_tag==DT_PLTGOT){ + lte->pltgot_addr=dyn.d_un.d_ptr; + } + if(dyn.d_tag==DT_MIPS_LOCAL_GOTNO){ + lte->mips_local_gotno=dyn.d_un.d_val; + } + if(dyn.d_tag==DT_MIPS_GOTSYM){ + lte->mips_gotsym=dyn.d_un.d_val; + } +#endif // __mips__ + if (dyn.d_tag == DT_JMPREL) + relplt_addr = dyn.d_un.d_ptr; + else if (dyn.d_tag == DT_PLTRELSZ) + relplt_size = dyn.d_un.d_val; + } + } else if (shdr.sh_type == SHT_HASH) { + Elf_Data *data; + size_t j; + + lte->hash_type = SHT_HASH; + + data = elf_getdata(scn, NULL); + if (data == NULL || elf_getdata(scn, data) != NULL + || data->d_off || data->d_size != shdr.sh_size) + error(EXIT_FAILURE, 0, + "Couldn't get .hash data from \"%s\"", + filename); + + if (shdr.sh_entsize == 4) { + /* Standard conforming ELF. */ + if (data->d_type != ELF_T_WORD) + error(EXIT_FAILURE, 0, + "Couldn't get .hash data from \"%s\"", + filename); + lte->hash = (Elf32_Word *) data->d_buf; + } else if (shdr.sh_entsize == 8) { + /* Alpha or s390x. */ + Elf32_Word *dst, *src; + size_t hash_count = data->d_size / 8; + + lte->hash = (Elf32_Word *) + malloc(hash_count * sizeof(Elf32_Word)); + if (lte->hash == NULL) + error(EXIT_FAILURE, 0, + "Couldn't convert .hash section from \"%s\"", + filename); + lte->lte_flags |= LTE_HASH_MALLOCED; + dst = lte->hash; + src = (Elf32_Word *) data->d_buf; + if ((data->d_type == ELF_T_WORD + && __BYTE_ORDER == __BIG_ENDIAN) + || (data->d_type == ELF_T_XWORD + && lte->ehdr.e_ident[EI_DATA] == + ELFDATA2MSB)) + ++src; + for (j = 0; j < hash_count; ++j, src += 2) + *dst++ = *src; + } else + error(EXIT_FAILURE, 0, + "Unknown .hash sh_entsize in \"%s\"", + filename); + } else if (shdr.sh_type == SHT_GNU_HASH + && lte->hash == NULL) { + Elf_Data *data; + + lte->hash_type = SHT_GNU_HASH; + + if (shdr.sh_entsize != 0 + && shdr.sh_entsize != 4) { + error(EXIT_FAILURE, 0, + ".gnu.hash sh_entsize in \"%s\" should be 4, but is %llu", + filename, shdr.sh_entsize); + } + + data = elf_getdata(scn, NULL); + if (data == NULL || elf_getdata(scn, data) != NULL + || data->d_off || data->d_size != shdr.sh_size) + error(EXIT_FAILURE, 0, + "Couldn't get .gnu.hash data from \"%s\"", + filename); + + lte->hash = (Elf32_Word *) data->d_buf; + } else if (shdr.sh_type == SHT_PROGBITS + || shdr.sh_type == SHT_NOBITS) { + if (strcmp(name, ".plt") == 0) { + lte->plt_addr = shdr.sh_addr; + lte->plt_size = shdr.sh_size; + if (shdr.sh_flags & SHF_EXECINSTR) { + lte->lte_flags |= LTE_PLT_EXECUTABLE; + } + } +#ifdef ARCH_SUPPORTS_OPD + else if (strcmp(name, ".opd") == 0) { + lte->opd_addr = (GElf_Addr *) (long) shdr.sh_addr; + lte->opd_size = shdr.sh_size; + lte->opd = elf_rawdata(scn, NULL); + } +#endif + } + } + + if (lte->dynsym == NULL || lte->dynstr == NULL) + error(EXIT_FAILURE, 0, + "Couldn't find .dynsym or .dynstr in \"%s\"", filename); + + if (!relplt_addr || !lte->plt_addr) { + debug(1, "%s has no PLT relocations", filename); + lte->relplt = NULL; + lte->relplt_count = 0; + } else { + for (i = 1; i < lte->ehdr.e_shnum; ++i) { + Elf_Scn *scn; + GElf_Shdr shdr; + + scn = elf_getscn(lte->elf, i); + if (scn == NULL || gelf_getshdr(scn, &shdr) == NULL) + error(EXIT_FAILURE, 0, + "Couldn't get section header from \"%s\"", + filename); + if (shdr.sh_addr == relplt_addr + && shdr.sh_size == relplt_size) { + lte->relplt = elf_getdata(scn, NULL); + lte->relplt_count = + shdr.sh_size / shdr.sh_entsize; + if (lte->relplt == NULL + || elf_getdata(scn, lte->relplt) != NULL) + error(EXIT_FAILURE, 0, + "Couldn't get .rel*.plt data from \"%s\"", + filename); + break; + } + } + + if (i == lte->ehdr.e_shnum) + error(EXIT_FAILURE, 0, + "Couldn't find .rel*.plt section in \"%s\"", + filename); + + debug(1, "%s %zd PLT relocations", filename, lte->relplt_count); + } +} + +static void +do_close_elf(struct ltelf *lte) { + debug(DEBUG_FUNCTION, "do_close_elf()"); + if (lte->lte_flags & LTE_HASH_MALLOCED) + free((char *)lte->hash); + elf_end(lte->elf); + close(lte->fd); +} + +static void +add_library_symbol(GElf_Addr addr, const char *name, + struct library_symbol **library_symbolspp, + enum toplt type_of_plt, int is_weak) { + struct library_symbol *s; + + debug(DEBUG_FUNCTION, "add_library_symbol()"); + + s = malloc(sizeof(struct library_symbol) + strlen(name) + 1); + if (s == NULL) + error(EXIT_FAILURE, errno, "add_library_symbol failed"); + + s->needs_init = 1; + s->is_weak = is_weak; + s->plt_type = type_of_plt; + s->next = *library_symbolspp; + s->enter_addr = (void *)(uintptr_t) addr; + s->name = (char *)(s + 1); + strcpy(s->name, name); + *library_symbolspp = s; + + debug(2, "addr: %p, symbol: \"%s\"", (void *)(uintptr_t) addr, name); +} + +/* stolen from elfutils-0.123 */ +static unsigned long +private_elf_gnu_hash(const char *name) { + unsigned long h = 5381; + const unsigned char *string = (const unsigned char *)name; + unsigned char c; + for (c = *string; c; c = *++string) + h = h * 33 + c; + return h & 0xffffffff; +} + +static int +in_load_libraries(const char *name, struct ltelf *lte) { + size_t i; + unsigned long hash; + unsigned long gnu_hash; + + if (!library_num) + return 1; + + hash = elf_hash((const unsigned char *)name); + gnu_hash = private_elf_gnu_hash(name); + for (i = 1; i <= library_num; ++i) { + if (lte[i].hash == NULL) + continue; + + if (lte[i].hash_type == SHT_GNU_HASH) { + Elf32_Word * hashbase = lte[i].hash; + Elf32_Word nbuckets = *hashbase++; + Elf32_Word symbias = *hashbase++; + Elf32_Word bitmask_nwords = *hashbase++; + Elf32_Word * buckets; + Elf32_Word * chain_zero; + Elf32_Word bucket; + + // +1 for skipped `shift' + hashbase += lte[i].ehdr.e_ident[EI_CLASS] * bitmask_nwords + 1; + buckets = hashbase; + hashbase += nbuckets; + chain_zero = hashbase - symbias; + bucket = buckets[gnu_hash % nbuckets]; + + if (bucket != 0) { + const Elf32_Word *hasharr = &chain_zero[bucket]; + do + if ((*hasharr & ~1u) == (gnu_hash & ~1u)) { + int symidx = hasharr - chain_zero; + GElf_Sym sym; + + if (gelf_getsym(lte[i].dynsym, symidx, &sym) == NULL) + error(EXIT_FAILURE, 0, + "Couldn't get symbol from .dynsym"); + + if (sym.st_value != 0 + && sym.st_shndx != SHN_UNDEF + && strcmp(name, lte[i].dynstr + sym.st_name) == 0) + return 1; + } + while ((*hasharr++ & 1u) == 0); + } + } else { + Elf32_Word nbuckets, symndx; + Elf32_Word *buckets, *chain; + nbuckets = lte[i].hash[0]; + buckets = <e[i].hash[2]; + chain = <e[i].hash[2 + nbuckets]; + + for (symndx = buckets[hash % nbuckets]; + symndx != STN_UNDEF; symndx = chain[symndx]) { + GElf_Sym sym; + + if (gelf_getsym(lte[i].dynsym, symndx, &sym) == NULL) + error(EXIT_FAILURE, 0, + "Couldn't get symbol from .dynsym"); + + if (sym.st_value != 0 + && sym.st_shndx != SHN_UNDEF + && strcmp(name, lte[i].dynstr + sym.st_name) == 0) + return 1; + } + } + } + return 0; +} + +static GElf_Addr +opd2addr(struct ltelf *lte, GElf_Addr addr) { +#ifdef ARCH_SUPPORTS_OPD + unsigned long base, offset; + + if (!lte->opd) + return addr; + + base = (unsigned long)lte->opd->d_buf; + offset = (unsigned long)addr - (unsigned long)lte->opd_addr; + if (offset > lte->opd_size) + error(EXIT_FAILURE, 0, "static plt not in .opd"); + + return *(GElf_Addr*)(base + offset); +#else //!ARCH_SUPPORTS_OPD + return addr; +#endif +} + +struct library_symbol * +read_elf(Process *proc) { + struct library_symbol *library_symbols = NULL; + struct ltelf lte[MAX_LIBRARIES + 1]; + size_t i; + struct opt_x_t *xptr; + struct library_symbol **lib_tail = NULL; + int exit_out = 0; + + debug(DEBUG_FUNCTION, "read_elf(file=%s)", proc->filename); + + elf_version(EV_CURRENT); + + do_init_elf(lte, proc->filename); + proc->e_machine = lte->ehdr.e_machine; + for (i = 0; i < library_num; ++i) + do_init_elf(<e[i + 1], library[i]); +#ifdef __mips__ + // MIPS doesn't use the PLT and the GOT entries get changed + // on startup. + proc->need_to_reinitialize_breakpoints = 1; + for(i=lte->mips_gotsym; idynsym_count;i++){ + GElf_Sym sym; + const char *name; + GElf_Addr addr = arch_plt_sym_val(lte, i, 0); + if (gelf_getsym(lte->dynsym, i, &sym) == NULL){ + error(EXIT_FAILURE, 0, + "Couldn't get relocation from \"%s\"", + proc->filename); + } + name=lte->dynstr+sym.st_name; + if(ELF64_ST_TYPE(sym.st_info) != STT_FUNC){ + debug(2,"sym %s not a function",name); + continue; + } + add_library_symbol(addr, name, &library_symbols, 0, + ELF64_ST_BIND(sym.st_info) != 0); + if (!lib_tail) + lib_tail = &(library_symbols->next); + } +#else + for (i = 0; i < lte->relplt_count; ++i) { + GElf_Rel rel; + GElf_Rela rela; + GElf_Sym sym; + GElf_Addr addr; + void *ret; + const char *name; + + if (lte->relplt->d_type == ELF_T_REL) { + ret = gelf_getrel(lte->relplt, i, &rel); + rela.r_offset = rel.r_offset; + rela.r_info = rel.r_info; + rela.r_addend = 0; + } else + ret = gelf_getrela(lte->relplt, i, &rela); + + if (ret == NULL + || ELF64_R_SYM(rela.r_info) >= lte->dynsym_count + || gelf_getsym(lte->dynsym, ELF64_R_SYM(rela.r_info), + &sym) == NULL) + error(EXIT_FAILURE, 0, + "Couldn't get relocation from \"%s\"", + proc->filename); + +#ifdef PLT_REINITALISATION_BP + if (!sym.st_value && PLTs_initialized_by_here) + proc->need_to_reinitialize_breakpoints = 1; +#endif + + name = lte->dynstr + sym.st_name; + if (in_load_libraries(name, lte)) { + addr = arch_plt_sym_val(lte, i, &rela); + add_library_symbol(addr, name, &library_symbols, + (PLTS_ARE_EXECUTABLE(lte) + ? LS_TOPLT_EXEC : LS_TOPLT_POINT), + ELF64_ST_BIND(sym.st_info) == STB_WEAK); + if (!lib_tail) + lib_tail = &(library_symbols->next); + } + } +#endif // !__mips__ +#ifdef PLT_REINITALISATION_BP + struct opt_x_t *main_cheat; + + if (proc->need_to_reinitialize_breakpoints) { + /* Add "PLTs_initialized_by_here" to opt_x list, if not + already there. */ + main_cheat = (struct opt_x_t *)malloc(sizeof(struct opt_x_t)); + if (main_cheat == NULL) + error(EXIT_FAILURE, 0, "Couldn't allocate memory"); + main_cheat->next = opt_x; + main_cheat->found = 0; + main_cheat->name = PLTs_initialized_by_here; + + for (xptr = opt_x; xptr; xptr = xptr->next) + if (strcmp(xptr->name, PLTs_initialized_by_here) == 0 + && main_cheat) { + free(main_cheat); + main_cheat = NULL; + break; + } + if (main_cheat) + opt_x = main_cheat; + } +#endif + + for (i = 0; i < lte->symtab_count; ++i) { + GElf_Sym sym; + GElf_Addr addr; + const char *name; + + if (gelf_getsym(lte->symtab, i, &sym) == NULL) + error(EXIT_FAILURE, 0, + "Couldn't get symbol from \"%s\"", + proc->filename); + + name = lte->strtab + sym.st_name; + addr = sym.st_value; + if (!addr) + continue; + + for (xptr = opt_x; xptr; xptr = xptr->next) + if (xptr->name && strcmp(xptr->name, name) == 0) { + /* FIXME: Should be able to use &library_symbols as above. But + when you do, none of the real library symbols cause breaks. */ + add_library_symbol(opd2addr(lte, addr), + name, lib_tail, LS_TOPLT_NONE, 0); + xptr->found = 1; + break; + } + } + for (xptr = opt_x; xptr; xptr = xptr->next) + if ( ! xptr->found) { + char *badthing = "WARNING"; +#ifdef PLT_REINITALISATION_BP + if (strcmp(xptr->name, PLTs_initialized_by_here) == 0) { + if (lte->ehdr.e_entry) { + add_library_symbol ( + opd2addr (lte, lte->ehdr.e_entry), + PLTs_initialized_by_here, + lib_tail, 1, 0); + fprintf (stderr, "WARNING: Using e_ent" + "ry from elf header (%p) for " + "address of \"%s\"\n", (void*) + (long) lte->ehdr.e_entry, + PLTs_initialized_by_here); + continue; + } + badthing = "ERROR"; + exit_out = 1; + } +#endif + fprintf (stderr, + "%s: Couldn't find symbol \"%s\" in file \"%s" + "\"\n", badthing, xptr->name, proc->filename); + } + if (exit_out) { + exit (1); + } + + for (i = 0; i < library_num + 1; ++i) + do_close_elf(<e[i]); + + return library_symbols; +} diff --git a/elf.h b/elf.h new file mode 100644 index 0000000..426f7b8 --- /dev/null +++ b/elf.h @@ -0,0 +1,49 @@ +#ifndef LTRACE_ELF_H +#define LTRACE_ELF_H + +#include +#include + +struct ltelf { + int fd; + Elf *elf; + GElf_Ehdr ehdr; + Elf_Data *dynsym; + size_t dynsym_count; + const char *dynstr; + GElf_Addr plt_addr; + size_t plt_size; + Elf_Data *relplt; + size_t relplt_count; + Elf_Data *symtab; + const char *strtab; + size_t symtab_count; + Elf_Data *opd; + GElf_Addr *opd_addr; + size_t opd_size; + Elf32_Word *hash; + int hash_type; + int lte_flags; +#ifdef __mips__ + size_t pltgot_addr; + size_t mips_local_gotno; + size_t mips_gotsym; +#endif // __mips__ +}; + +#define LTE_HASH_MALLOCED 1 +#define LTE_PLT_EXECUTABLE 2 + +#define PLTS_ARE_EXECUTABLE(lte) ((lte->lte_flags & LTE_PLT_EXECUTABLE) != 0) + +extern int library_num; +extern char *library[MAX_LIBRARIES]; + +extern struct library_symbol *read_elf(Process *); + +extern GElf_Addr arch_plt_sym_val(struct ltelf *, size_t, GElf_Rela *); + +#ifndef SHT_GNU_HASH +#define SHT_GNU_HASH 0x6ffffff6 /* GNU-style hash table. */ +#endif +#endif diff --git a/etc/ltrace.conf b/etc/ltrace.conf new file mode 100644 index 0000000..ed4fc5a --- /dev/null +++ b/etc/ltrace.conf @@ -0,0 +1,604 @@ +; ltrace.conf +; +; ~/.ltrace.conf will also be read, if it exists. The -F option may be +; used to suppress the automatic inclusion of both this file and +; ~/.ltrace.conf, and load a different config file or config files +; instead. + +; Argument types: +; + == May vary (ie, is a returned value) (prefix) +; void +; int +; uint == (unsigned int) +; long +; ulong == (unsigned long) +; octal == (unsigned) [written in octal] +; char +; short == (short) +; ushort == (unsigned short) +; addr == (void *) [unsigned, written in hexa] +; file == (FILE *) [TODO] +; format == ((const char *), ...) [printf() like] [TODO] +; string == (char *) +; string[argN] == (char *) [N>0] [show only up to (arg N) bytes] +; string[eltN] == (char *) [N>0] [show only up to (elt N) bytes] +; string[retval] == (char *) [show only up to (return val) bytes] +; string[arg0] == (char *) [same as string[retval]] +; string[N] == (char *) [N>0] [show only up to N bytes] +; type* == (type *) [pointer to any other type] +; enum (key=value,key=value,...) [enumeration, see below] +; array(type,argN) +; == (type[SIZE]) [array of (arg N) elements] +; array(type,eltN) +; == (type[SIZE]) [array of (struct element N) elements] +; array(type,N) == (type[N]) [array of N elements] +; struct(type,type,...) +; == (struct {...}) [struct of several types] +; +; Backwards-compatibility: +; string0 == (char *) [same as string[retval]] +; stringN == (char *) [N>0] [same as string[argN]] + + + +; Typedefs +; +; To make it easier to specify argument lists, you can use 'typedef' +; directives to avoid repeating complex parameter descriptors: +; +; typedef color = enum(RED=1,BLUE=2,GREEN=3) +; void draw_line(color,int,int,int,int) +; void draw_square(color,int,int,int,int) +; +; Enumerations +; +; The syntax is a parenthesized list of key=value assignments, like so: +; enum (F_DUPFD=0,F_GETFD=1,F_SETFD=2) +; an example usage might look like +; int fcntl(int,enum (F_DUPFD=0,F_GETFD=1,F_SETFD=2)) +; +; Arrays +; +; NOTE: Uses of array(...) alone are very rare. You almost always +; want array(...)*. The exceptions are when you have a fixed-size +; array. +; +; Structs +; +; NOTE: Uses of struct(...) alone are very rare. You almost always +; want struct(...)* (a pointer to a struct) anyway. Most compilers +; pass structs as pointers anyway, and those that don't are not yet +; supported. The one time when you want to use a non-pointer +; struct(...) type are when you have an array of structs, or a struct +; containing another struct. +; +; For example, if you have +; struct s1 { +; int y_size; +; int * y; +; int z[3]; +; struct { char c; } a; +; struct { char c; } * b; +; } +; and a function +; void f(struct s1*) +; then the corresponding ltrace spec is +; void f(struct(int,array(int,elt0),array(int,3),struct(char),struct(char)*)*) +; which, formatted similarly to the C declaration, looks like +; void f(struct( +; int, +; array(int,elt0), +; array(int,3), +; struct(char), +; struct(char)* +; )* +; ) + + +; arpa/inet.h +int inet_aton(string,addr); +string inet_ntoa(addr); ; It isn't an ADDR but an hexa number... +addr inet_addr(string); + +; bfd.h +void bfd_init(void); +int bfd_set_default_target(string); +addr bfd_scan_vma(string, addr, int); +addr bfd_openr(string,string); +int bfd_check_format(addr,int); + +; ctype.h +char tolower(char); +char toupper(char); +addr __ctype_b_loc(void); +addr __ctype_tolower_loc(void); +addr __ctype_toupper_loc(void); + +; curses.h +int waddch(addr, char); +int mvprintw(int, int, format); +int wmove(addr, int, int); +int waddnstr(addr, string, int); +string tgoto(string, int, int); + +; dirent.h +int closedir(addr); +addr opendir(string); +addr readdir(addr); +addr readdir64(addr); + +; dlfcn.h +addr dlopen(string, int); +string dlerror(void); +addr dlsym(addr, string); +int dlclose(addr); + +; errno.h +addr __errno_location(void); + +; fcntl.h +int open(string,int,octal); ; WARNING: 3rd argument may not be there +int open64(string,int,octal); ; WARNING: 3rd argument may not be there + +; fnmatch.h +int fnmatch(string, string, int); + +; getopt.h +int getopt_long(int,addr,string,addr,int*); +int getopt_long_only(int,addr,string,addr,addr); + +; grp.h +void endgrent(void); +addr getgrnam(string); +void setgrent(void); +addr getgrent(void); + +; libintl.h +string __dcgettext(string,string,int); +string bindtextdomain(string, string); +string textdomain(string); + +; libio.h +char _IO_getc(file); +int _IO_putc(char,file); + +; locale.h +string setlocale(int, string); + +; mcheck.h +void mtrace(void); +void muntrace(void); + +; mntent.h +int endmntent(file); +file setmntent(string,string); +addr getmntent(addr); + +; mqueue.h +int mq_open(string, int, octal, addr); ; WARNING: 3rd and 4th arguments may not be there +int mq_close(int); +int mq_unlink(string); +int mq_getattr(int, addr); +int mq_setattr(int, addr, addr); +int mq_notify(int, addr); +int mq_send(int, string3, ulong, uint); +int mq_timedsend(int, string3, ulong, uint, addr); +long mq_receive(int, +string0, ulong, addr); +long mq_timedreceive(int, +string0, ulong, addr, addr); + +; netdb.h +void endhostent(void); +void endnetent(void); +void endnetgrent(void); +void endprotoent(void); +void endservent(void); +void freeaddrinfo(addr); +string gai_strerror(int); +int getaddrinfo(string, string, addr, addr); +addr gethostbyaddr(string, uint, int); +addr gethostbyname(string); +addr gethostent(void); +int getnameinfo(addr, uint, string, uint, string, uint, uint); +addr getnetbyaddr(uint, int); +addr getnetbyname(string); +addr getnetent(void); +int getnetgrent(addr, addr, addr); +addr getprotobyname(string); +addr getprotobynumber(int); +addr getprotoent(void); +addr getservbyname(string, string); +addr getservbyport(int, string); +addr getservent(void); +void herror(string); +string hstrerror(int); +int rcmd(addr, ushort, string, string, string, addr); +int rcmd_af(addr, ushort, string, string, string, addr, int); +int rexec(addr, int, string, string, string, addr); +int rexec_af(addr, int, string, string, string, addr, int); +int rresvport (addr); +int rresvport_af (addr, int); +int ruserok(string, int, string, string); +int ruserok_af(string, int, string, string, int); +void sethostent(int); +void setnetent(int); +int setnetgrent(string); +void setprotoent(int); +void setservent(int); + +; netinet/in.h +uint ntohs(uint); + +; pcap.h +string pcap_lookupdev(addr); +addr pcap_open_live(string, int, int, int, addr); +int pcap_snapshot(addr); +int pcap_lookupnet(string, addr, addr, addr); +int pcap_compile(addr, addr, string, int, addr); + +; pwd.h +string getpass(string); +void endpwent(void); +addr getpwnam(string); +void setpwent(void); + +; readline/readline.h +string readline(string); + +; signal.h +int kill(int,int); +addr signal(int,addr); +int sigemptyset(addr); +int sigfillset(addr); +int sigaddset(addr, int); +int sigdelset(addr, int); +int sigismember(addr, int); +int sigaction(int, addr, addr); +int sigprocmask(int, addr, addr); +int sigpending(addr); +int sigsuspend(addr); + +; stdio.h +int fclose(file); +int feof(file); +int ferror(file); +int fflush(file); +char fgetc(file); +addr fgets(+string, int, file); +int fileno(file); +file fopen(string,string); +file fopen64(string,string); +int fprintf(file,format); +int fputc(char,file); +int fputs(string,file); +ulong fread(addr,ulong,ulong,file); +ulong fread_unlocked(addr,ulong,ulong,file); +ulong fwrite(string,ulong,ulong,file); +ulong fwrite_unlocked(string,ulong,ulong,file); +int pclose(addr); +void perror(string); +addr popen(string, string); +int printf(format); +int puts(string); +int remove(string); +int snprintf(+string2,ulong,format); +int sprintf(+string,format); +string tempnam(string,string); +int vfprintf(file,string,addr); +int vsnprintf(+string2,ulong,string,addr); +int setvbuf(file,addr,int,ulong); +void setbuf(file,addr); +void setbuffer(file,addr,ulong); +void setlinebuf(file); +int rename(string,string); + +; stdlib.h +long __strtol_internal(string,addr,int); +ulong __strtoul_internal(string,addr,int); +int atexit(addr); +addr bsearch(string, addr, ulong, ulong, addr); +addr calloc(ulong, ulong); +void exit(int); +void free(addr); +string getenv(string); +int putenv(string); +int setenv(string,string,int); +void unsetenv(string); +addr malloc(ulong); +void qsort(addr,ulong,ulong,addr); +int random(void); +addr realloc(addr,ulong); +void srandom(uint); +int system(string); + +; string.h +void bcopy(addr,addr,ulong); +void bzero(addr,ulong); +string basename(string); +string index(string,char); +addr memchr(string,char,ulong); +addr memcpy(addr,string3,ulong); +addr memset(addr,char,long); +string rindex(string,char); +addr stpcpy(addr,string); +int strcasecmp(string, string); +string strcat(string, string); +string strchr(string,char); +int strcoll(string,string); +ulong strlen(string); +int strcmp(string,string); +addr strcpy(addr,string); +addr strdup(string); +string strerror(int); +int strncmp(string,string,ulong); +addr strncpy(addr,string3,ulong); +string strrchr(string,char); +string strsep(addr,string); +ulong strspn(string,string); +ulong strcspn(string,string); +string strstr(string,string); +string strtok(string, string); + +; sys/ioctl.h +int ioctl(int, int, addr); + +; sys/socket.h +int socket(int,int,int); + +; sys/stat.h +int __fxstat(int,int,addr); +int __xstat(int,string,addr); +int __lxstat(int,string,addr); +int __fxstat64(int,int,addr); +int __xstat64(int,string,addr); +int __lxstat64(int,string,addr); +int chmod(string,octal); +int fchmod(int,octal); +int mkfifo(string,octal); +octal umask(octal); + +; sys/utsname.h +int uname(addr); + +; sys/vfs.h +int statfs(string,addr); + +; syslog.h +void closelog(void); +void openlog(string,int,int); +void syslog(int,format); + +; term.h +int tputs(string, int, addr); + +; termios.h +int tcgetattr(int,addr); +int tcsetattr(int,int,addr); + +; time.h +string ctime(addr); +int gettimeofday(addr, addr); +addr gmtime(addr); +addr localtime(addr); +ulong strftime(+string2,ulong,string,addr); +long time(addr); + +; unistd.h +void _exit(int); +int access(string, int); +uint alarm(uint); +int chdir(string); +int chown(string,int,int); +int close(int); +string crypt(string,string); +int dup2(int,int); +int execlp(string,string,addr,addr,addr); +int execv(string,addr); +int fchdir(int); +int fork(void); +int ftruncate(int,ulong); +string2 getcwd(addr,ulong); +int getdomainname(+string2,ulong); +int geteuid(void); +int getegid(void); +int getgid(void); +int gethostname(+string2,ulong); +string getlogin(void); +int getopt(int,addr,string); +int getpid(void); +int getppid(void); +int getuid(void); +int getpgrp(void); +int setpgrp(void); +int getpgid(int); +int isatty(int); +int link(string,string); +int mkdir(string,octal); +long read(int, +string[retval], ulong); +int rmdir(string); +int seteuid(uint); +int setgid(int); +int sethostname(+string2,ulong); +int setpgid(int,int); +int setreuid(uint, uint); +int setuid(int); +uint sleep(uint); +int symlink(string,string); +int sync(void); +int truncate(string,ulong); +string ttyname(int); +int unlink(string); +void usleep(uint); +long write(int, string3, ulong); +addr sbrk(long); +int getpagesize(void); +long lseek(int,long,int); +int pipe(addr); + +; utmp.h +void endutent(void); +addr getutent(void); +void setutent(void); + +; wchar.h +int fwide(addr, int); + +; sys/wait.h +int wait(addr); +int waitpid(int,addr,int); + +; X11/Xlib.h +void XCloseDisplay(addr); +int XMapWindow(addr,addr); +addr XOpenDisplay(string); + +; sys/acl.h +int acl_add_perm(addr,uint); +int acl_calc_mask(addr); +int acl_clear_perms(addr); +int acl_copy_entry(addr,addr); +int acl_copy_ext(addr,addr,int); +addr acl_copy_int(addr); +int acl_create_entry(addr,addr); +int acl_delete_def_file(string); +int acl_delete_entry(addr,addr); +int acl_delete_perm(addr,uint); +addr acl_dup(addr); +int acl_free(addr); +addr acl_from_text(string); +int acl_get_entry(addr,int,addr); +addr acl_get_fd(int); +addr acl_get_file(string,int); +int acl_get_permset(addr,addr); +addr acl_get_qualifier(addr); +int acl_get_tag_type(addr,addr); +addr acl_init(int); +int acl_set_fd(int,addr); +int acl_set_file(string,int,addr); +int acl_set_permset(addr,addr); +int acl_set_qualifier(addr,addr); +int acl_set_tag_type(addr,int); +int acl_size(addr); +string acl_to_text(addr,addr); +itn acl_valid(addr); + +; acl/libacl.h +int acl_check(addr,addr); +int acl_cmp(addr,addr); +int acl_entries(addr); +int acl_equiv_mode(addr,addr); +string acl_error(int); +int acl_extended_fd(int); +int acl_extended_file(string); +addr acl_from_mode(octal); +int acl_get_perm(addr,uint); +string acl_to_any_text(addr,string,char,int); + +; SYSCALLS +addr SYS_brk(addr); +int SYS_close(int); +int SYS_execve(string,addr,addr); +void SYS_exit(int); +void SYS_exit_group(int); +int SYS_fork(void); +int SYS_getcwd(+string2,ulong); +int SYS_getpid(void); +;addr SYS_mmap(addr,ulong,int,int,int,long); +int SYS_munmap(addr,ulong); +int SYS_open(string,int,octal); +int SYS_personality(uint); +long SYS_read(int,+string0,ulong); +int SYS_stat(string,addr); +octal SYS_umask(octal); +int SYS_uname(addr); +long SYS_write(int,string3,ulong); +int SYS_sync(void); +int SYS_setxattr(string,string,addr,uint,int); +int SYS_lsetxattr(string,string,addr,uint,int); +int SYS_fsetxattr(int,string,addr,uint,int); +int SYS_getxattr(string,string,addr,uint); +int SYS_lgetxattr(string,string,addr,uint); +int SYS_fgetxattr(int,string,addr,uint); +int SYS_listxattr(string,addr,uint); +int SYS_llistxattr(string,addr,uint); +int SYS_flistxattr(int,addr,uint); +int SYS_removexattr(string,string); +int SYS_lremovexattr(string,string); +int SYS_fremovexattr(int,string); +int SYS_chdir(string); +int SYS_fchdir(int); +int SYS_chmod(string,octal); +int SYS_fchmod(int,octal); +int SYS_chown(string,int,int); +int SYS_fchown(int,int,int); +int SYS_lchown(string,int,int); +int SYS_chroot(string); +int SYS_dup(int); +int SYS_dup2(int,int); +int SYS_fdatasync(int); +int SYS_fsync(int); +int SYS_getpriority(int,int); +int SYS_setpriority(int,int,int); +int SYS_getrlimit(int,addr); +int SYS_setrlimit(int,addr); +int SYS_gettimeofday(addr,addr); +int SYS_settimeofday(addr,addr); +int SYS_setfsgid(int); +int SYS_setfsuid(int); +int SYS_getuid(void); +int SYS_setuid(int); +int SYS_getgid(void); +int SYS_setgid(int); +int SYS_getsid(int); +int SYS_setsid(int); +int SYS_setreuid(int,int); +int SYS_setregid(int,int); +int SYS_geteuid(void); +int SYS_getegid(void); +int SYS_setpgid(int,int); +int SYS_getresuid(addr,addr,addr); +int SYS_setresuid(int,int,int); +int SYS_getresgid(addr,addr,addr); +int SYS_setresgid(int,int,int); +int SYS_kill(int,int); +int SYS_link(string,string); +int SYS_madvise(addr,ulong,int); +int SYS_mkdir(string,octal); +int SYS_mknod(string,octal,int); +int SYS_msync(addr,ulong,int); +int SYS_nice(int); +int SYS_poll(addr,uint,int); +int SYS_readdir(uint,addr,uint); +int SYS_readlink(string,string,ulong); +int SYS_reboot(int,int,int,addr); +int SYS_rename(string,string); +int SYS_rmdir(string); +int SYS_sigaltstack(addr,addr); +int SYS_statfs(string,addr); +int SYS_fstatfs(int,addr); +int SYS_fstat(int,addr); +int SYS_lstat(string,addr); +int SYS_stime(addr); +int SYS_symlink(string, string); +int SYS_sysinfo(addr); +int SYS_syslog(int,string,int); +int SYS_truncate(string,long); +int SYS_ftruncate(int,long); +int SYS_mount(string,string,string,ulong,addr); +int SYS_umount(string); +int SYS_umount2(string,int); +int SYS_unlink(string); +int SYS_utime(string,addr); +long SYS_lseek(int,long,int); +addr SYS_signal(int,addr); +int SYS_sigaction(int,addr,addr); +int SYS_pause(void); +int SYS_sigpending(addr); +int SYS_sigprocmask(int,addr,addr); +int SYS_sigqueue(int,int,addr); +int SYS_sigsuspend(addr); +int SYS_wait(addr); +int SYS_waitpid(int,addr,int); +ulong SYS_readv(int,addr,int); +ulong SYS_writev(int,addr,int); +int SYS_mprotect(addr,int,int); +int SYS_access(string,octal); diff --git a/execute_program.c b/execute_program.c new file mode 100644 index 0000000..5fd6379 --- /dev/null +++ b/execute_program.c @@ -0,0 +1,91 @@ +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" + +static void +change_uid(Process *proc) { + uid_t run_uid, run_euid; + gid_t run_gid, run_egid; + + if (options.user) { + struct passwd *pent; + + if (getuid() != 0 || geteuid() != 0) { + fprintf(stderr, + "you must be root to use the -u option\n"); + exit(1); + } + if ((pent = getpwnam(options.user)) == NULL) { + fprintf(stderr, "cannot find user `%s'\n", options.user); + exit(1); + } + run_uid = pent->pw_uid; + run_gid = pent->pw_gid; + + if (initgroups(options.user, run_gid) < 0) { + perror("ltrace: initgroups"); + exit(1); + } + } else { + run_uid = getuid(); + run_gid = getgid(); + } + if (options.user || !geteuid()) { + struct stat statbuf; + run_euid = run_uid; + run_egid = run_gid; + + if (!stat(proc->filename, &statbuf)) { + if (statbuf.st_mode & S_ISUID) { + run_euid = statbuf.st_uid; + } + if (statbuf.st_mode & S_ISGID) { + run_egid = statbuf.st_gid; + } + } + if (setregid(run_gid, run_egid) < 0) { + perror("ltrace: setregid"); + exit(1); + } + if (setreuid(run_uid, run_euid) < 0) { + perror("ltrace: setreuid"); + exit(1); + } + } +} + +void +execute_program(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; +} diff --git a/handle_event.c b/handle_event.c new file mode 100644 index 0000000..1dfb82b --- /dev/null +++ b/handle_event.c @@ -0,0 +1,696 @@ +#include "config.h" + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include + +#include "common.h" + +#ifdef __powerpc__ +#include +#endif + +static void handle_signal(Event *event); +static void handle_exit(Event *event); +static void handle_exit_signal(Event *event); +static void handle_syscall(Event *event); +static void handle_arch_syscall(Event *event); +static void handle_sysret(Event *event); +static void handle_arch_sysret(Event *event); +static void handle_clone(Event *event); +static void handle_exec(Event *event); +static void handle_breakpoint(Event *event); +static void handle_new(Event *event); +static void remove_proc(Process *proc); + +static void callstack_push_syscall(Process *proc, int sysnum); +static void callstack_push_symfunc(Process *proc, + struct library_symbol *sym); +static void callstack_pop(Process *proc); + +static char * shortsignal(Process *proc, int signum); +static char * sysname(Process *proc, int sysnum); +static char * arch_sysname(Process *proc, int sysnum); + +void +handle_event(Event *event) { + debug(DEBUG_FUNCTION, "handle_event(pid=%d, type=%d)", event->proc ? event->proc->pid : -1, event->type); + switch (event->type) { + case EVENT_NONE: + debug(1, "event: none"); + return; + case EVENT_SIGNAL: + debug(1, "event: signal (%s [%d])", + shortsignal(event->proc, event->e_un.signum), + event->e_un.signum); + handle_signal(event); + return; + case EVENT_EXIT: + debug(1, "event: exit (%d)", event->e_un.ret_val); + handle_exit(event); + return; + case EVENT_EXIT_SIGNAL: + debug(1, "event: exit signal (%s [%d])", + shortsignal(event->proc, event->e_un.signum), + event->e_un.signum); + handle_exit_signal(event); + return; + case EVENT_SYSCALL: + debug(1, "event: syscall (%s [%d])", + sysname(event->proc, event->e_un.sysnum), + event->e_un.sysnum); + handle_syscall(event); + return; + case EVENT_SYSRET: + debug(1, "event: sysret (%s [%d])", + sysname(event->proc, event->e_un.sysnum), + event->e_un.sysnum); + handle_sysret(event); + return; + case EVENT_ARCH_SYSCALL: + debug(1, "event: arch_syscall (%s [%d])", + arch_sysname(event->proc, event->e_un.sysnum), + event->e_un.sysnum); + handle_arch_syscall(event); + return; + case EVENT_ARCH_SYSRET: + debug(1, "event: arch_sysret (%s [%d])", + arch_sysname(event->proc, event->e_un.sysnum), + event->e_un.sysnum); + handle_arch_sysret(event); + return; + case EVENT_CLONE: + debug(1, "event: clone (%u)", event->e_un.newpid); + handle_clone(event); + return; + case EVENT_EXEC: + debug(1, "event: exec()"); + handle_exec(event); + return; + case EVENT_BREAKPOINT: + debug(1, "event: breakpoint"); + handle_breakpoint(event); + return; + case EVENT_NEW: + debug(1, "event: new process"); + handle_new(event); + return; + default: + fprintf(stderr, "Error! unknown event?\n"); + exit(1); + } +} + +/* TODO */ +static void * +address_clone(void * addr) { + debug(DEBUG_FUNCTION, "address_clone(%p)", addr); + return addr; +} + +static void * +breakpoint_clone(void * bp) { + Breakpoint * b; + debug(DEBUG_FUNCTION, "breakpoint_clone(%p)", bp); + b = malloc(sizeof(Breakpoint)); + if (!b) { + perror("malloc()"); + exit(1); + } + memcpy(b, bp, sizeof(Breakpoint)); + return b; +} + +typedef struct Pending_New Pending_New; +struct Pending_New { + pid_t pid; + Pending_New * next; +}; +static Pending_New * pending_news = NULL; + +static int +pending_new(pid_t pid) { + Pending_New * p; + + debug(DEBUG_FUNCTION, "pending_new(%d)", pid); + + p = pending_news; + while (p) { + if (p->pid == pid) { + return 1; + } + p = p->next; + } + return 0; +} + +static void +pending_new_insert(pid_t pid) { + Pending_New * p; + + debug(DEBUG_FUNCTION, "pending_new_insert(%d)", pid); + + p = malloc(sizeof(Pending_New)); + if (!p) { + perror("malloc()"); + exit(1); + } + p->pid = pid; + p->next = pending_news; + pending_news = p; +} + +static void +pending_new_remove(pid_t pid) { + Pending_New *p, *pred; + + debug(DEBUG_FUNCTION, "pending_new_remove(%d)", pid); + + p = pending_news; + if (p->pid == pid) { + pending_news = p->next; + free(p); + } else { + while (p) { + if (p->pid == pid) { + pred->next = p->next; + free(p); + } + pred = p; + p = p->next; + } + } +} + +static void +handle_clone(Event * event) { + Process *p; + + debug(DEBUG_FUNCTION, "handle_clone(pid=%d)", event->proc->pid); + + p = malloc(sizeof(Process)); + if (!p) { + perror("malloc()"); + exit(1); + } + memcpy(p, event->proc, sizeof(Process)); + p->breakpoints = dict_clone(event->proc->breakpoints, address_clone, breakpoint_clone); + p->pid = event->e_un.newpid; + p->parent = event->proc; + + if (pending_new(p->pid)) { + pending_new_remove(p->pid); + if (p->breakpoint_being_enabled) { + enable_breakpoint(p->pid, p->breakpoint_being_enabled); + p->breakpoint_being_enabled = NULL; + } + if (event->proc->state == STATE_ATTACHED && options.follow) { + p->state = STATE_ATTACHED; + } else { + p->state = STATE_IGNORED; + } + continue_process(p->pid); + p->next = list_of_processes; + list_of_processes = p; + } else { + p->state = STATE_BEING_CREATED; + p->next = list_of_processes; + list_of_processes = p; + } + continue_process(event->proc->pid); +} + +static void +handle_new(Event * event) { + Process * proc; + + debug(DEBUG_FUNCTION, "handle_new(pid=%d)", event->e_un.newpid); + + proc = pid2proc(event->e_un.newpid); + if (!proc) { + pending_new_insert(event->e_un.newpid); + } else { + assert(proc->state == STATE_BEING_CREATED); + if (proc->breakpoint_being_enabled) { + enable_breakpoint(proc->pid, proc->breakpoint_being_enabled); + proc->breakpoint_being_enabled = NULL; + } + if (options.follow) { + proc->state = STATE_ATTACHED; + } else { + proc->state = STATE_IGNORED; + } + continue_process(proc->pid); + } +} + +static char * +shortsignal(Process *proc, int signum) { + static char *signalent0[] = { +#include "signalent.h" + }; + static char *signalent1[] = { +#include "signalent1.h" + }; + static char **signalents[] = { signalent0, signalent1 }; + int nsignals[] = { sizeof signalent0 / sizeof signalent0[0], + sizeof signalent1 / sizeof signalent1[0] + }; + + debug(DEBUG_FUNCTION, "shortsignal(pid=%d, signum=%d)", proc->pid, signum); + + if (proc->personality > sizeof signalents / sizeof signalents[0]) + abort(); + if (signum < 0 || signum >= nsignals[proc->personality]) { + return "UNKNOWN_SIGNAL"; + } else { + return signalents[proc->personality][signum]; + } +} + +static char * +sysname(Process *proc, int sysnum) { + static char result[128]; + static char *syscalent0[] = { +#include "syscallent.h" + }; + static char *syscalent1[] = { +#include "syscallent1.h" + }; + static char **syscalents[] = { syscalent0, syscalent1 }; + int nsyscals[] = { sizeof syscalent0 / sizeof syscalent0[0], + sizeof syscalent1 / sizeof syscalent1[0] + }; + + debug(DEBUG_FUNCTION, "sysname(pid=%d, sysnum=%d)", proc->pid, sysnum); + + if (proc->personality > sizeof syscalents / sizeof syscalents[0]) + abort(); + if (sysnum < 0 || sysnum >= nsyscals[proc->personality]) { + sprintf(result, "SYS_%d", sysnum); + return result; + } else { + sprintf(result, "SYS_%s", + syscalents[proc->personality][sysnum]); + return result; + } +} + +static char * +arch_sysname(Process *proc, int sysnum) { + static char result[128]; + static char *arch_syscalent[] = { +#include "arch_syscallent.h" + }; + int nsyscals = sizeof arch_syscalent / sizeof arch_syscalent[0]; + + debug(DEBUG_FUNCTION, "arch_sysname(pid=%d, sysnum=%d)", proc->pid, sysnum); + + if (sysnum < 0 || sysnum >= nsyscals) { + sprintf(result, "ARCH_%d", sysnum); + return result; + } else { + sprintf(result, "ARCH_%s", + arch_syscalent[sysnum]); + return result; + } +} + +static void +handle_signal(Event *event) { + debug(DEBUG_FUNCTION, "handle_signal(pid=%d, signum=%d)", event->proc->pid, event->e_un.signum); + if (exiting && event->e_un.signum == SIGSTOP) { + pid_t pid = event->proc->pid; + disable_all_breakpoints(event->proc); + untrace_pid(pid); + remove_proc(event->proc); + return; + } + if (event->proc->state != STATE_IGNORED) { + output_line(event->proc, "--- %s (%s) ---", + shortsignal(event->proc, event->e_un.signum), + strsignal(event->e_un.signum)); + } + continue_after_signal(event->proc->pid, event->e_un.signum); +} + +static void +handle_exit(Event *event) { + debug(DEBUG_FUNCTION, "handle_exit(pid=%d, status=%d)", event->proc->pid, event->e_un.ret_val); + if (event->proc->state != STATE_IGNORED) { + output_line(event->proc, "+++ exited (status %d) +++", + event->e_un.ret_val); + } + remove_proc(event->proc); +} + +static void +handle_exit_signal(Event *event) { + debug(DEBUG_FUNCTION, "handle_exit_signal(pid=%d, signum=%d)", event->proc->pid, event->e_un.signum); + if (event->proc->state != STATE_IGNORED) { + output_line(event->proc, "+++ killed by %s +++", + shortsignal(event->proc, event->e_un.signum)); + } + remove_proc(event->proc); +} + +static void +remove_proc(Process *proc) { + Process *tmp, *tmp2; + + debug(DEBUG_FUNCTION, "remove_proc(pid=%d)", proc->pid); + + if (list_of_processes == proc) { + tmp = list_of_processes; + list_of_processes = list_of_processes->next; + free(tmp); + return; + } + tmp = list_of_processes; + while (tmp->next) { + if (tmp->next == proc) { + tmp2 = tmp->next; + tmp->next = tmp->next->next; + free(tmp2); + continue; + } + tmp = tmp->next; + } +} + +static void +handle_syscall(Event *event) { + debug(DEBUG_FUNCTION, "handle_syscall(pid=%d, sysnum=%d)", event->proc->pid, event->e_un.sysnum); + if (event->proc->state != STATE_IGNORED) { + if (options.syscalls) { + output_left(LT_TOF_SYSCALL, event->proc, + sysname(event->proc, event->e_un.sysnum)); + } + if (event->proc->breakpoints_enabled == 0) { + enable_all_breakpoints(event->proc); + } + callstack_push_syscall(event->proc, event->e_un.sysnum); + } + continue_process(event->proc->pid); +} + +static void +handle_exec(Event * event) { + Process * proc = event->proc; + pid_t saved_pid; + + debug(DEBUG_FUNCTION, "handle_exec(pid=%d)", proc->pid); + if (proc->state == STATE_IGNORED) { + untrace_pid(proc->pid); + remove_proc(proc); + return; + } + output_line(proc, "--- Called exec() ---"); + proc->mask_32bit = 0; + proc->personality = 0; + proc->arch_ptr = NULL; + free(proc->filename); + proc->filename = pid2name(proc->pid); + saved_pid = proc->pid; + proc->pid = 0; + breakpoints_init(proc); + proc->pid = saved_pid; + proc->callstack_depth = 0; + continue_process(proc->pid); +} + +static void +handle_arch_syscall(Event *event) { + debug(DEBUG_FUNCTION, "handle_arch_syscall(pid=%d, sysnum=%d)", event->proc->pid, event->e_un.sysnum); + if (event->proc->state != STATE_IGNORED) { + if (options.syscalls) { + output_left(LT_TOF_SYSCALL, event->proc, + arch_sysname(event->proc, event->e_un.sysnum)); + } + if (event->proc->breakpoints_enabled == 0) { + enable_all_breakpoints(event->proc); + } + callstack_push_syscall(event->proc, 0xf0000 + event->e_un.sysnum); + } + continue_process(event->proc->pid); +} + +struct timeval current_time_spent; + +static void +calc_time_spent(Process *proc) { + struct timeval tv; + struct timezone tz; + struct timeval diff; + struct callstack_element *elem; + + debug(DEBUG_FUNCTION, "calc_time_spent(pid=%d)", proc->pid); + elem = &proc->callstack[proc->callstack_depth - 1]; + + gettimeofday(&tv, &tz); + + diff.tv_sec = tv.tv_sec - elem->time_spent.tv_sec; + if (tv.tv_usec >= elem->time_spent.tv_usec) { + diff.tv_usec = tv.tv_usec - elem->time_spent.tv_usec; + } else { + diff.tv_sec++; + diff.tv_usec = 1000000 + tv.tv_usec - elem->time_spent.tv_usec; + } + current_time_spent = diff; +} + +static void +handle_sysret(Event *event) { + debug(DEBUG_FUNCTION, "handle_sysret(pid=%d, sysnum=%d)", event->proc->pid, event->e_un.sysnum); + if (event->proc->state != STATE_IGNORED) { + if (opt_T || options.summary) { + calc_time_spent(event->proc); + } + callstack_pop(event->proc); + if (options.syscalls) { + output_right(LT_TOF_SYSCALLR, event->proc, + sysname(event->proc, event->e_un.sysnum)); + } + } + continue_process(event->proc->pid); +} + +static void +handle_arch_sysret(Event *event) { + debug(DEBUG_FUNCTION, "handle_arch_sysret(pid=%d, sysnum=%d)", event->proc->pid, event->e_un.sysnum); + if (event->proc->state != STATE_IGNORED) { + if (opt_T || options.summary) { + calc_time_spent(event->proc); + } + callstack_pop(event->proc); + if (options.syscalls) { + output_right(LT_TOF_SYSCALLR, event->proc, + arch_sysname(event->proc, event->e_un.sysnum)); + } + } + continue_process(event->proc->pid); +} + +static void +handle_breakpoint(Event *event) { + int i, j; + Breakpoint *sbp; + + debug(DEBUG_FUNCTION, "handle_breakpoint(pid=%d, addr=%p)", event->proc->pid, event->e_un.brk_addr); + debug(2, "event: breakpoint (%p)", event->e_un.brk_addr); + +#ifdef __powerpc__ + /* Need to skip following NOP's to prevent a fake function from being stacked. */ + long stub_addr = (long) get_count_register(event->proc); + Breakpoint *stub_bp = NULL; + char nop_instruction[] = PPC_NOP; + + stub_bp = address2bpstruct (event->proc, event->e_un.brk_addr); + + if (stub_bp) { + unsigned char *bp_instruction = stub_bp->orig_value; + + if (memcmp(bp_instruction, nop_instruction, + PPC_NOP_LENGTH) == 0) { + if (stub_addr != (long) event->e_un.brk_addr) { + set_instruction_pointer (event->proc, event->e_un.brk_addr + 4); + continue_process(event->proc->pid); + return; + } + } + } +#endif + if ((sbp = event->proc->breakpoint_being_enabled) != 0) { + /* Reinsert breakpoint */ + continue_enabling_breakpoint(event->proc->pid, + event->proc-> + breakpoint_being_enabled); + event->proc->breakpoint_being_enabled = NULL; + return; + } + + for (i = event->proc->callstack_depth - 1; i >= 0; i--) { + if (event->e_un.brk_addr == + event->proc->callstack[i].return_addr) { +#ifdef __powerpc__ + /* + * PPC HACK! (XXX FIXME TODO) + * The PLT gets modified during the first call, + * so be sure to re-enable the breakpoint. + */ + unsigned long a; + struct library_symbol *libsym = + event->proc->callstack[i].c_un.libfunc; + void *addr = sym2addr(event->proc, libsym); + + if (libsym->plt_type != LS_TOPLT_POINT) { + unsigned char break_insn[] = BREAKPOINT_VALUE; + + sbp = address2bpstruct(event->proc, addr); + assert(sbp); + a = ptrace(PTRACE_PEEKTEXT, event->proc->pid, + addr); + + if (memcmp(&a, break_insn, BREAKPOINT_LENGTH)) { + sbp->enabled--; + insert_breakpoint(event->proc, addr, + libsym); + } + } else { + sbp = dict_find_entry(event->proc->breakpoints, sym2addr(event->proc, libsym)); + assert(sbp); + if (addr != sbp->addr) { + insert_breakpoint(event->proc, addr, + libsym); + } + } +#elif defined(__mips__) + void *addr; + void *old_addr; + struct library_symbol *sym= event->proc->callstack[i].c_un.libfunc; + assert(sym); + old_addr = dict_find_entry(event->proc->breakpoints, sym2addr(event->proc, sym))->addr; + addr=sym2addr(event->proc,sym); + assert(old_addr !=0 && addr !=0); + if(addr != old_addr){ + struct library_symbol *new_sym; + new_sym=malloc(sizeof(*new_sym)); + memcpy(new_sym,sym,sizeof(*new_sym)); + new_sym->next=event->proc->list_of_symbols; + event->proc->list_of_symbols=new_sym; + insert_breakpoint(event->proc, addr, new_sym); + } +#endif + for (j = event->proc->callstack_depth - 1; j > i; j--) { + callstack_pop(event->proc); + } + if (event->proc->state != STATE_IGNORED) { + if (opt_T || options.summary) { + calc_time_spent(event->proc); + } + } + callstack_pop(event->proc); + event->proc->return_addr = event->e_un.brk_addr; + if (event->proc->state != STATE_IGNORED) { + output_right(LT_TOF_FUNCTIONR, event->proc, + event->proc->callstack[i].c_un.libfunc->name); + } + continue_after_breakpoint(event->proc, + address2bpstruct(event->proc, + event->e_un.brk_addr)); + return; + } + } + + if ((sbp = address2bpstruct(event->proc, event->e_un.brk_addr))) { + if (event->proc->state != STATE_IGNORED) { + event->proc->stack_pointer = get_stack_pointer(event->proc); + event->proc->return_addr = + get_return_addr(event->proc, event->proc->stack_pointer); + output_left(LT_TOF_FUNCTION, event->proc, sbp->libsym->name); + callstack_push_symfunc(event->proc, sbp->libsym); + } +#ifdef PLT_REINITALISATION_BP + if (event->proc->need_to_reinitialize_breakpoints + && (strcmp(sbp->libsym->name, PLTs_initialized_by_here) == + 0)) + reinitialize_breakpoints(event->proc); +#endif + + continue_after_breakpoint(event->proc, sbp); + return; + } + + if (event->proc->state != STATE_IGNORED) { + output_line(event->proc, "unexpected breakpoint at %p", + (void *)event->e_un.brk_addr); + } + continue_process(event->proc->pid); +} + +static void +callstack_push_syscall(Process *proc, int sysnum) { + struct callstack_element *elem; + + debug(DEBUG_FUNCTION, "callstack_push_syscall(pid=%d, sysnum=%d)", proc->pid, sysnum); + /* FIXME: not good -- should use dynamic allocation. 19990703 mortene. */ + if (proc->callstack_depth == MAX_CALLDEPTH - 1) { + fprintf(stderr, "Error: call nesting too deep!\n"); + return; + } + + elem = &proc->callstack[proc->callstack_depth]; + elem->is_syscall = 1; + elem->c_un.syscall = sysnum; + elem->return_addr = NULL; + + proc->callstack_depth++; + if (opt_T || options.summary) { + struct timezone tz; + gettimeofday(&elem->time_spent, &tz); + } +} + +static void +callstack_push_symfunc(Process *proc, struct library_symbol *sym) { + struct callstack_element *elem; + + debug(DEBUG_FUNCTION, "callstack_push_symfunc(pid=%d, symbol=%s)", proc->pid, sym->name); + /* FIXME: not good -- should use dynamic allocation. 19990703 mortene. */ + if (proc->callstack_depth == MAX_CALLDEPTH - 1) { + fprintf(stderr, "Error: call nesting too deep!\n"); + return; + } + + elem = &proc->callstack[proc->callstack_depth]; + elem->is_syscall = 0; + elem->c_un.libfunc = sym; + + elem->return_addr = proc->return_addr; + if (elem->return_addr) { + insert_breakpoint(proc, elem->return_addr, 0); + } + + proc->callstack_depth++; + if (opt_T || options.summary) { + struct timezone tz; + gettimeofday(&elem->time_spent, &tz); + } +} + +static void +callstack_pop(Process *proc) { + struct callstack_element *elem; + assert(proc->callstack_depth > 0); + + debug(DEBUG_FUNCTION, "callstack_pop(pid=%d)", proc->pid); + elem = &proc->callstack[proc->callstack_depth - 1]; + if (!elem->is_syscall && elem->return_addr) { + delete_breakpoint(proc, elem->return_addr); + } + proc->callstack_depth--; +} diff --git a/libltrace.c b/libltrace.c new file mode 100644 index 0000000..0f48d11 --- /dev/null +++ b/libltrace.c @@ -0,0 +1,154 @@ +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" + +char *command = NULL; +Process *list_of_processes = NULL; + +int exiting = 0; /* =1 if a SIGINT or SIGTERM has been received */ + +static void +signal_alarm(int sig) { + Process *tmp = list_of_processes; + + signal(SIGALRM, SIG_DFL); + while (tmp) { + struct opt_p_t *tmp2 = opt_p; + while (tmp2) { + if (tmp->pid == tmp2->pid) { + tmp = tmp->next; + if (!tmp) { + return; + } + tmp2 = opt_p; + continue; + } + tmp2 = tmp2->next; + } + debug(2, "Sending SIGSTOP to process %u\n", tmp->pid); + kill(tmp->pid, SIGSTOP); + tmp = tmp->next; + } +} + +static void +signal_exit(int sig) { + exiting = 1; + 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) { + debug(2, "Sending SIGSTOP to process %u\n", tmp->pid); + kill(tmp->pid, SIGSTOP); + tmp = tmp->next; + } + } + alarm(1); +} + +static void +normal_exit(void) { + output_line(0, 0); + if (options.summary) { + show_summary(); + } + if (options.output) { + fclose(options.output); + options.output = NULL; + } +} + +void +ltrace_init(int argc, char **argv) { + struct opt_p_t *opt_p_tmp; + + atexit(normal_exit); + signal(SIGINT, signal_exit); /* Detach processes when interrupted */ + signal(SIGTERM, signal_exit); /* ... or killed */ + + argv = process_options(argc, argv); + while (opt_F) { + /* If filename begins with ~, expand it to the user's home */ + /* directory. This does not correctly handle ~yoda, but that */ + /* isn't as bad as it seems because the shell will normally */ + /* be doing the expansion for us; only the hardcoded */ + /* ~/.ltrace.conf should ever use this code. */ + if (opt_F->filename[0] == '~') { + char path[PATH_MAX]; + char *home_dir = getenv("HOME"); + if (home_dir) { + strncpy(path, home_dir, PATH_MAX - 1); + path[PATH_MAX - 1] = '\0'; + strncat(path, opt_F->filename + 1, + PATH_MAX - strlen(path) - 1); + read_config_file(path); + } + } else { + read_config_file(opt_F->filename); + } + opt_F = opt_F->next; + } + if (opt_e) { + struct opt_e_t *tmp = opt_e; + while (tmp) { + debug(1, "Option -e: %s\n", tmp->name); + tmp = tmp->next; + } + } + if (command) { + execute_program(open_program(command, 0), argv); + } + opt_p_tmp = opt_p; + while (opt_p_tmp) { + open_pid(opt_p_tmp->pid); + opt_p_tmp = opt_p_tmp->next; + } +} + +static int num_ltrace_callbacks[EVENT_MAX]; +static callback_func * ltrace_callbacks[EVENT_MAX]; + +void +ltrace_add_callback(callback_func func, Event_type type) { + ltrace_callbacks[type] = realloc(ltrace_callbacks[type], (num_ltrace_callbacks[type]+1)*sizeof(callback_func)); + ltrace_callbacks[type][num_ltrace_callbacks[type]++] = func; +} + +static void +dispatch_callbacks(Event * ev) { + int i; + /* Ignoring case 1: signal into a dying tracer */ + if (ev->type==EVENT_SIGNAL && + exiting && ev->e_un.signum == SIGSTOP) { + return; + } + /* Ignoring case 2: process being born before a clone event */ + if (ev->proc && ev->proc->state == STATE_IGNORED) { + return; + } + for (i=0; itype]; i++) { + ltrace_callbacks[ev->type][i](ev); + } +} + +void +ltrace_main(void) { + Event * ev; + while (1) { + ev = next_event(); + dispatch_callbacks(ev); + handle_event(ev); + } +} diff --git a/ltrace.1 b/ltrace.1 new file mode 100644 index 0000000..358d6aa --- /dev/null +++ b/ltrace.1 @@ -0,0 +1,206 @@ +.\" Copyright (c) 1997-2005 Juan Cespedes +.\" This file is covered by the GNU GPL +.TH ltrace 1 +.SH NAME +ltrace \- A library call tracer + +.SH SYNOPSIS +.B ltrace +.I "[-CfhiLrStttV] [-a column] [-A maxelts] [-D level] [-e expr] [-l filename] [-n nr] [-o filename] [-p pid] ... [-s strsize] [-u username] [-X extern] [-x extern] ... [--align=column] [--debug=level] [--demangle] [--help] [--indent=nr] [--library=filename] [--output=filename] [--version] [command [arg ...]]" + +.SH DESCRIPTION +.B ltrace +is a program that simply runs the specified +.I command +until it exits. It intercepts and records the dynamic library calls +which are called by the executed process and the signals which are +received by that process. +It can also intercept and print the system calls executed by the program. +.PP +Its use is very similar to +.BR strace(1) . + +.SH OPTIONS +.TP +.I \-a, \-\-align column +Align return values in a specific column (default column is 5/8 of screen width). +.TP +.I \-A maxelts +Maximum number of array elements to print before suppressing the rest with an ellipsis ("...") +.TP +.I \-c +Count time and calls for each library call and report a summary on program exit. +.TP +.I \-C, \-\-demangle +Decode (demangle) low-level symbol names into user-level names. +Besides removing any initial underscore prefix used by the system, +this makes C++ function names readable. +.TP +.I \-D, \-\-debug level +Show debugging output of +.B ltrace +itself. +.I level +must be a sum of some of the following numbers: +.RS +.TP +.B 01 +DEBUG_GENERAL. Shows helpful progress information +.TP +.B 010 +DEBUG_EVENT. Shows every event received by a traced program +.TP +.B 020 +DEBUG_PROCESS. Shows every action +.B ltrace +carries upon a traced process +.TP +.B 040 +DEBUG_FUNCTION. Shows every entry to internal functions +.RE +.TP +.I \-e expr +A qualifying expression which modifies which events to trace. +The format of the expression is: +.br +[!]value1[,value2]... +.br +where the values are the functions to trace. Using an exclamation +mark negates the set of values. For example +.I \-e printf +means to trace only the printf library call. By contrast, +.I \-e !printf +means to trace every library call except printf. +.IP +Note that some shells use the exclamation point for history +expansion; even inside quoted arguments. If so, you must escape +the exclamation point with a backslash. +.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 immediately. +.TP +.I \-F +Load an alternate config file. Normally, /etc/ltrace.conf and +~/.ltrace.conf will be read (the latter only if it exists). +Use this option to load the given file or files instead of +those two default files. +.TP +.I \-h, \-\-help +Show a summary of the options to ltrace and exit. +.TP +.I \-i +Print the instruction pointer at the time of the library call. +.TP +.I \-l, \-\-library filename +Display only the symbols included in the library +.I filename. +Up to 30 library names can be specified with several instances +of this option. +.TP +.I \-L +DON'T display library calls (use it with the +.I \-S +option). +.TP +.I \-n, \-\-indent nr +Indent trace output by +.I nr +number of spaces for each new nested call. Using this option makes +the program flow visualization easy to follow. +.TP +.I \-o, \-\-output filename +Write the trace output to the file +.I filename +rather than to stderr. +.TP +.I \-p pid +Attach to the process with the process ID +.I pid +and begin tracing. +.TP +.I \-r +Print a relative timestamp with each line of the trace. +This records the time difference between the beginning of +successive lines. +.TP +.I \-s strsize +Specify the maximum string size to print (the default is 32). +.TP +.I \-S +Display system calls as well as library calls +.TP +.I \-t +Prefix each line of the trace with the time of day. +.TP +.I \-tt +If given twice, the time printed will include the microseconds. +.TP +.I \-ttt +If given thrice, the time printed will include the microseconds and +the leading portion will be printed as the number of seconds since the +epoch. +.TP +.I \-T +Show the time spent inside each call. This records the time difference +between the beginning and the end of each call. +.TP +.I \-u username +Run command with the userid, groupid and supplementary groups of +.IR username . +This option is only useful when running as root and enables the +correct execution of setuid and/or setgid binaries. +.TP +.I \-X extern +Some architectures need to know where to set a breakpoint that will be hit +after the dynamic linker has run. If this flag is used, then the breakpoint +is set at +.IR extern , +which must be an external function. By default, '_start' is used. +NOTE: this flag is only available on the architectures that need it. +.TP +.I \-x extern +Trace the external function +.IR extern . +This option may be repeated. +.TP +.I \-V, \-\-version +Show the version number of ltrace and exit. + +.SH BUGS +It has most of the bugs stated in +.BR strace(1) . +.LP +Manual page and documentation are not very up-to-date. +.LP +Option -f sometimes fails to trace some children. +.LP +It only works on Linux and in a small subset of architectures. +.LP +Only ELF32 binaries are supported. +.LP +Calls to dlopen()ed libraries will not be traced. +.PP +If you would like to report a bug, send a message to the mailing list +(ltrace-devel@lists.alioth.debian.org), or use the +.BR reportbug(1) +program if you are under the Debian GNU/Linux distribution. + +.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 + +.SH "SEE ALSO" +.BR strace(1) , +.BR ptrace(2) + diff --git a/ltrace.h b/ltrace.h new file mode 100644 index 0000000..5e43ba5 --- /dev/null +++ b/ltrace.h @@ -0,0 +1,38 @@ +typedef enum Event_type Event_type; +enum Event_type { + EVENT_NONE=0, + EVENT_SIGNAL, + EVENT_EXIT, + EVENT_EXIT_SIGNAL, + EVENT_SYSCALL, + EVENT_SYSRET, + EVENT_ARCH_SYSCALL, + EVENT_ARCH_SYSRET, + EVENT_CLONE, + EVENT_EXEC, + EVENT_BREAKPOINT, + EVENT_LIBCALL, + EVENT_LIBRET, + EVENT_NEW, /* in this case, proc is NULL */ + EVENT_MAX +}; + +typedef struct Process Process; +typedef struct Event Event; +struct Event { + Process * proc; + Event_type type; + union { + int ret_val; /* EVENT_EXIT */ + int signum; /* EVENT_SIGNAL, EVENT_EXIT_SIGNAL */ + int sysnum; /* EVENT_SYSCALL, EVENT_SYSRET */ + void * brk_addr; /* EVENT_BREAKPOINT */ + int newpid; /* EVENT_CLONE, EVENT_NEW */ + } e_un; +}; + +typedef void (*callback_func) (Event *); + +extern void ltrace_init(int argc, char **argv); +extern void ltrace_add_callback(callback_func f, Event_type type); +extern void ltrace_main(void); diff --git a/ltrace.spec b/ltrace.spec new file mode 100644 index 0000000..3740190 --- /dev/null +++ b/ltrace.spec @@ -0,0 +1,164 @@ +Summary: Tracks runtime library calls from dynamically linked executables. +Name: ltrace +Version: 0.3.36 +Release: 4.2 +Source: ftp://ftp.debian.org/debian/pool/main/l/ltrace/ltrace_%{version}.orig.tar.gz +Patch1: ftp://ftp.debian.org/debian/pool/main/l/ltrace/ltrace_0.3.36-2.diff.gz +Patch2: ltrace-ppc64.patch +Patch3: ltrace-ppc64-2.patch +Patch4: ltrace-s390x.patch +Patch5: ltrace-syscallent-update.patch +Patch6: ltrace-fixes.patch +Patch7: ltrace-ia64.patch +License: GPL +Group: Development/Debuggers +ExclusiveArch: i386 x86_64 ia64 ppc ppc64 s390 s390x alpha sparc +Prefix: %{_prefix} +BuildRoot: /var/tmp/%{name}-root +BuildRequires: elfutils-libelf-devel + +%description +Ltrace is a debugging program which runs a specified command until the +command exits. While the command is executing, ltrace intercepts and +records both the dynamic library calls called by the executed process +and the signals received by the executed process. Ltrace can also +intercept and print system calls executed by the process. + +You should install ltrace if you need a sysadmin tool for tracking the +execution of processes. + +%prep +%setup -q +%patch1 -p1 +%patch2 -p1 +%patch3 -p1 +%patch4 -p1 +%patch5 -p1 +%patch6 -p1 +%patch7 -p1 +sed -i -e 's/-o root -g root//' Makefile.in + +%build +export CC="gcc`echo $RPM_OPT_FLAGS | sed -n 's/^.*\(-m[36][124]\).*$/ \1/p'`" +%configure CC="$CC" +make + +%install +make DESTDIR=$RPM_BUILD_ROOT mandir=%{_mandir} install +rm -f ChangeLog; mv -f debian/changelog ChangeLog +rm -rf $RPM_BUILD_ROOT/%{_prefix}/doc + +%clean +rm -rf $RPM_BUILD_ROOT + +%files +%defattr(-,root,root) +%doc COPYING README TODO BUGS ChangeLog +%{_prefix}/bin/ltrace +%{_mandir}/man1/ltrace.1* +%config /etc/ltrace.conf + +%changelog +* Fri Feb 10 2006 Jesse Keating - 0.3.36-4.2 +- bump again for double-long bug on ppc(64) + +* Tue Feb 07 2006 Jesse Keating - 0.3.36-4.1 +- rebuilt for new gcc4.1 snapshot and glibc changes + +* Mon Jan 9 2006 Jakub Jelinek 0.3.36-4 +- added ppc64 and s390x support (IBM) +- added ia64 support (Ian Wienand) + +* Sat Mar 5 2005 Jakub Jelinek 0.3.36-3 +- rebuilt with GCC 4 + +* Tue Dec 14 2004 Jakub Jelinek 0.3.36-2 +- make x86_64 ltrace trace both 32-bit and 64-bit binaries (#141955, + IT#55600) +- fix tracing across execve +- fix printf-style format handling on 64-bit arches + +* Thu Nov 18 2004 Jakub Jelinek 0.3.36-1 +- update to 0.3.36 + +* Mon Oct 11 2004 Jakub Jelinek 0.3.35-1 +- update to 0.3.35 +- update syscall tables from latest kernel source + +* Tue Jun 15 2004 Elliot Lee +- rebuilt + +* Tue Jun 8 2004 Jakub Jelinek 0.3.32-3 +- buildreq elfutils-libelf-devel (#124921) + +* Thu Apr 22 2004 Jakub Jelinek 0.3.32-2 +- fix demangling + +* Thu Apr 22 2004 Jakub Jelinek 0.3.32-1 +- update to 0.3.32 + - fix dict.c assertion (#114359) + - x86_64 support +- rewrite elf.[ch] using libelf +- don't rely on st_value of SHN_UNDEF symbols in binaries, + instead walk .rel{,a}.plt and compute the addresses (#115299) +- fix x86-64 support +- some ltrace.conf additions +- some format string printing fixes + +* Fri Feb 13 2004 Elliot Lee +- rebuilt + +* Mon Feb 3 2003 Jakub Jelinek 0.3.29-1 +- update to 0.3.29 + +* Wed Jan 22 2003 Tim Powers +- rebuilt + +* Sun Sep 1 2002 Jakub Jelinek 0.3.10-12 +- add a bunch of missing functions to ltrace.conf + (like strlen, ugh) + +* Fri Jun 21 2002 Tim Powers +- automated rebuild + +* Tue May 28 2002 Phil Knirsch +- Added the 'official' s390 patch. + +* Thu May 23 2002 Tim Powers +- automated rebuild + +* Wed Jan 09 2002 Tim Powers +- automated rebuild + +* Fri Jul 20 2001 Jakub Jelinek +- fix stale symlink in documentation directory (#47749) + +* Sun Jun 24 2001 Elliot Lee +- Bump release + rebuild. + +* Thu Aug 2 2000 Tim Waugh +- fix off-by-one problem in checking syscall number + +* Wed Jul 12 2000 Prospector +- automatic rebuild + +* Mon Jun 19 2000 Matt Wilson +- rebuilt for next release +- patched Makefile.in to take a hint on mandir (patch2) +- use %%{_mandir} and %%makeinstall + +* Wed Feb 02 2000 Cristian Gafton +- fix description + +* Fri Jan 7 2000 Jeff Johnson +- update to 0.3.10. +- include (but don't apply) sparc patch from Jakub Jellinek. + +* Sun Mar 21 1999 Cristian Gafton +- auto rebuild in the new build environment (release 2) + +* Fri Mar 12 1999 Jeff Johnson +- update to 0.3.6. + +* Mon Sep 21 1998 Preston Brown +- upgraded to 0.3.4 diff --git a/main.c b/main.c new file mode 100644 index 0000000..bd443cf --- /dev/null +++ b/main.c @@ -0,0 +1,37 @@ +#include +#include + +#include "ltrace.h" + +/* +static int count_call =0; +static int count_ret =0; + +static void +callback_call(Event * ev) { + count_call ++; +} +static void +callback_ret(Event * ev) { + count_ret ++; +} + +static void +endcallback(Event *ev) { + printf("%d calls\n%d rets\n",count_call, count_ret); +} +*/ + +int +main(int argc, char *argv[]) { + ltrace_init(argc, argv); + +/* + ltrace_add_callback(callback_call, EVENT_SYSCALL); + ltrace_add_callback(callback_ret, EVENT_SYSRET); + ltrace_add_callback(endcallback, EVENT_EXIT); +*/ + + ltrace_main(); + return 0; +} diff --git a/mkdist b/mkdist new file mode 100755 index 0000000..25182fb --- /dev/null +++ b/mkdist @@ -0,0 +1,19 @@ +#!/bin/sh -e + +# Create ltrace-${version}.tar.gz from a GIT repository + +if [ ! -d .git -o ! -f libltrace.c ] +then + echo "This must be called inside a ltrace GIT repository" 1>&2 + exit 1 +fi + +VERSION=$( cat VERSION ) + +echo Building ltrace-$VERSION.tar.gz ... +rm -rf ltrace-$VERSION +git clone ./ ltrace-$VERSION >/dev/null +GZIP=-9 tar --exclude .git -zcf ltrace-$VERSION.tar.gz ltrace-$VERSION +rm -rf ltrace-$VERSION +echo Done. + diff --git a/options.c b/options.c new file mode 100644 index 0000000..aef73b1 --- /dev/null +++ b/options.c @@ -0,0 +1,431 @@ +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "common.h" + +#ifndef SYSCONFDIR +#define SYSCONFDIR "/etc" +#endif + +#define SYSTEM_CONFIG_FILE SYSCONFDIR "/ltrace.conf" +#define USER_CONFIG_FILE "~/.ltrace.conf" + +struct options_t options = { + .align = DEFAULT_ALIGN, /* alignment column for results */ + .user = NULL, /* username to run command as */ + .syscalls = 0, /* display syscalls */ + .libcalls = 1, /* display library calls */ +#ifdef USE_DEMANGLE + .demangle = 0, /* Demangle low-level symbol names */ +#endif + .indent = 0, /* indent output according to program flow */ + .output = NULL, /* output to a specific file */ + .summary = 0, /* Report a summary on program exit */ + .debug = 0, /* debug */ + .arraylen = DEFAULT_ARRAYLEN, /* maximum # array elements to print */ + .strlen = DEFAULT_STRLEN, /* maximum # of bytes printed in strings */ + .follow = 0, /* trace child processes */ +}; + +char *library[MAX_LIBRARIES]; +int library_num = 0; +static char *progname; /* Program name (`ltrace') */ +int opt_i = 0; /* instruction pointer */ +int opt_r = 0; /* print relative timestamp */ +int opt_t = 0; /* print absolute timestamp */ +int opt_T = 0; /* show the time spent inside each call */ + +/* List of pids given to option -p: */ +struct opt_p_t *opt_p = NULL; /* attach to process with a given pid */ + +/* List of function names given to option -e: */ +struct opt_e_t *opt_e = NULL; +int opt_e_enable = 1; + +/* List of global function names given to -x: */ +struct opt_x_t *opt_x = NULL; + +/* List of filenames give to option -F: */ +struct opt_F_t *opt_F = NULL; /* alternate configuration file(s) */ + +#ifdef PLT_REINITALISATION_BP +/* Set a break on the routine named here in order to re-initialize breakpoints + after all the PLTs have been initialzed */ +char *PLTs_initialized_by_here = PLT_REINITALISATION_BP; +#endif + +static void +err_usage(void) { + fprintf(stderr, "Try `%s --help' for more information\n", progname); + exit(1); +} + +static void +usage(void) { + fprintf(stdout, "Usage: %s [option ...] [command [arg ...]]\n" + "Trace library calls of a given program.\n\n" + " -a, --align=COLUMN align return values in a secific column.\n" + " -A ARRAYLEN maximum number of array elements to print.\n" + " -c count time and calls, and report a summary on exit.\n" +# ifdef USE_DEMANGLE + " -C, --demangle decode low-level symbol names into user-level names.\n" +# endif + " -D, --debug=LEVEL enable debugging (see -Dh or --debug=help).\n" + " -Dh, --debug=help show help on debugging.\n" + " -e expr modify which events to trace.\n" + " -f trace children (fork() and clone()).\n" + " -F, --config=FILE load alternate configuration file (may be repeated).\n" + " -h, --help display this help and exit.\n" + " -i print instruction pointer at time of library call.\n" + " -l, --library=FILE print library calls from this library only.\n" + " -L do NOT display library calls.\n" + " -n, --indent=NR indent output by NR spaces for each call level nesting.\n" + " -o, --output=FILE write the trace output to that file.\n" + " -p PID attach to the process with the process ID pid.\n" + " -r print relative timestamps.\n" + " -s STRLEN specify the maximum string size to print.\n" + " -S display system calls.\n" + " -t, -tt, -ttt print absolute timestamps.\n" + " -T show the time spent inside each call.\n" + " -u USERNAME run command with the userid, groupid of username.\n" + " -V, --version output version information and exit.\n" + " -x NAME treat the global NAME like a library subroutine.\n" +#ifdef PLT_REINITALISATION_BP + " -X NAME same as -x; and PLT's will be initialized by here.\n" +#endif + "\nReport bugs to ltrace-devel@lists.alioth.debian.org\n", + progname); +} + +static void +usage_debug(void) { + fprintf(stdout, "%s debugging option, --debug= or -D:\n", progname); + fprintf(stdout, + "\n" + " number ref. in source description\n" + " 1 general Generally helpful progress information\n" + " 10 event Shows every event received by a traced process\n" + " 20 process Shows actions carried upon a traced processes\n" + " 40 function Shows every entry to internal functions\n" + "\n" + "Debugging options are mixed using bitwise-or.\n" + "Note that the meanings and values are subject to change.\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); + } + if (n + strlen(filename) + 1 >= PATH_MAX) { + fprintf(stderr, "Error: filename too long\n"); + exit(1); + } + strncpy(pathname, path, n); + if (n && pathname[n - 1] != '/') { + pathname[n++] = '/'; + } + strcpy(pathname + n, filename); + if (!access(pathname, X_OK)) { + return pathname; + } + } + return filename; +} + +static void +guess_cols(void) { + struct winsize ws; + char *c; + + options.align = DEFAULT_ALIGN; + c = getenv("COLUMNS"); + if (c && *c) { + char *endptr; + int cols; + cols = strtol(c, &endptr, 0); + if (cols > 0 && !*endptr) { + options.align = cols * 5 / 8; + } + } else if (ioctl(1, TIOCGWINSZ, &ws) != -1 && ws.ws_col > 0) { + options.align = ws.ws_col * 5 / 8; + } else if (ioctl(2, TIOCGWINSZ, &ws) != -1 && ws.ws_col > 0) { + options.align = ws.ws_col * 5 / 8; + } +} + +char ** +process_options(int argc, char **argv) { + progname = argv[0]; + options.output = stderr; + + guess_cols(); + + while (1) { + int c; + char *p; + int option_index = 0; + static struct option long_options[] = { + {"align", 1, 0, 'a'}, + {"config", 1, 0, 'F'}, + {"debug", 1, 0, 'D'}, +# ifdef USE_DEMANGLE + {"demangle", 0, 0, 'C'}, +#endif + {"indent", 1, 0, 'n'}, + {"help", 0, 0, 'h'}, + {"library", 1, 0, 'l'}, + {"output", 1, 0, 'o'}, + {"version", 0, 0, 'V'}, + {0, 0, 0, 0} + }; + c = getopt_long(argc, argv, "+cfhiLrStTV" +# ifdef USE_DEMANGLE + "C" +# endif + "a:A:D:e:F:l:n:o:p:s:u:x:X:", long_options, + &option_index); + if (c == -1) { + break; + } + switch (c) { + case 'a': + options.align = atoi(optarg); + break; + case 'A': + options.arraylen = atoi(optarg); + break; + case 'c': + options.summary++; + break; +#ifdef USE_DEMANGLE + case 'C': + options.demangle++; + break; +#endif + case 'D': + if (optarg[0]=='h') { + usage_debug(); + exit(0); + } + options.debug = strtoul(optarg,&p,8); + if (*p) { + fprintf(stderr, "%s: --debug requires an octal argument\n", progname); + err_usage(); + } + break; + case 'e': + { + char *str_e = strdup(optarg); + if (!str_e) { + perror("ltrace: strdup"); + exit(1); + } + if (str_e[0] == '!') { + opt_e_enable = 0; + str_e++; + } + while (*str_e) { + struct opt_e_t *tmp; + char *str2 = strchr(str_e, ','); + if (str2) { + *str2 = '\0'; + } + tmp = malloc(sizeof(struct opt_e_t)); + if (!tmp) { + perror("ltrace: malloc"); + exit(1); + } + tmp->name = str_e; + tmp->next = opt_e; + opt_e = tmp; + if (str2) { + str_e = str2 + 1; + } else { + break; + } + } + break; + } + case 'f': + options.follow = 1; + break; + case 'F': + { + struct opt_F_t *tmp = malloc(sizeof(struct opt_F_t)); + if (!tmp) { + perror("ltrace: malloc"); + exit(1); + } + tmp->filename = strdup(optarg); + tmp->next = opt_F; + opt_F = tmp; + break; + } + case 'h': + usage(); + exit(0); + case 'i': + opt_i++; + break; + case 'l': + if (library_num == MAX_LIBRARIES) { + fprintf(stderr, + "Too many libraries. Maximum is %i.\n", + MAX_LIBRARIES); + exit(1); + } + library[library_num++] = optarg; + break; + case 'L': + options.libcalls = 0; + break; + case 'n': + options.indent = atoi(optarg); + break; + case 'o': + options.output = fopen(optarg, "w"); + if (!options.output) { + fprintf(stderr, + "Can't open %s for output: %s\n", + optarg, strerror(errno)); + exit(1); + } + setvbuf(options.output, (char *)NULL, _IOLBF, 0); + fcntl(fileno(options.output), F_SETFD, FD_CLOEXEC); + break; + case 'p': + { + struct opt_p_t *tmp = malloc(sizeof(struct opt_p_t)); + if (!tmp) { + perror("ltrace: malloc"); + exit(1); + } + tmp->pid = atoi(optarg); + tmp->next = opt_p; + opt_p = tmp; + break; + } + case 'r': + opt_r++; + break; + case 's': + options.strlen = atoi(optarg); + break; + case 'S': + options.syscalls = 1; + break; + case 't': + opt_t++; + break; + case 'T': + opt_T++; + break; + case 'u': + options.user = optarg; + break; + case 'V': + printf("ltrace version " PACKAGE_VERSION ".\n" + "Copyright (C) 1997-2009 Juan Cespedes .\n" + "This is free software; see the GNU General Public Licence\n" + "version 2 or later for copying conditions. There is NO warranty.\n"); + exit(0); + case 'X': +#ifdef PLT_REINITALISATION_BP + PLTs_initialized_by_here = optarg; +#else + fprintf(stderr, "WARNING: \"-X\" not used for this " + "architecture: assuming you meant \"-x\"\n"); +#endif + /* Fall Thru */ + + case 'x': + { + struct opt_x_t *p = opt_x; + + /* First, check for duplicate. */ + while (p && strcmp(p->name, optarg)) { + p = p->next; + } + if (p) { + break; + } + + /* If not duplicate, add to list. */ + p = malloc(sizeof(struct opt_x_t)); + if (!p) { + perror("ltrace: malloc"); + exit(1); + } + p->name = optarg; + p->found = 0; + p->next = opt_x; + opt_x = p; + break; + } + + default: + err_usage(); + } + } + argc -= optind; + argv += optind; + + if (!opt_F) { + opt_F = malloc(sizeof(struct opt_F_t)); + opt_F->next = malloc(sizeof(struct opt_F_t)); + opt_F->next->next = NULL; + opt_F->filename = USER_CONFIG_FILE; + opt_F->next->filename = SYSTEM_CONFIG_FILE; + } + /* Reverse the config file list since it was built by + * prepending, and it would make more sense to process the + * files in the order they were given. Probably it would make + * more sense to keep a tail pointer instead? */ + { + struct opt_F_t *egg = NULL; + struct opt_F_t *chicken; + while (opt_F) { + chicken = opt_F->next; + opt_F->next = egg; + egg = opt_F; + opt_F = chicken; + } + opt_F = egg; + } + + if (!opt_p && argc < 1) { + fprintf(stderr, "%s: too few arguments\n", progname); + err_usage(); + } + if (opt_r && opt_t) { + fprintf(stderr, "%s: Incompatible options -r and -t\n", + progname); + err_usage(); + } + if (argc > 0) { + command = search_for_command(argv[0]); + } + return &argv[0]; +} diff --git a/options.h b/options.h new file mode 100644 index 0000000..db253c5 --- /dev/null +++ b/options.h @@ -0,0 +1,55 @@ +#include +#include + +struct options_t { + int align; /* -a: default alignment column for results */ + char * user; /* -u: username to run command as */ + int syscalls; /* -S: display system calls */ + int libcalls; /* -L: display library calls */ + int demangle; /* -C: demangle low-level names into user-level names */ + int indent; /* -n: indent trace output according to program flow */ + FILE *output; /* output to a specific file */ + int summary; /* count time, calls, and report a summary on program exit */ + int debug; /* debug */ + int arraylen; /* default maximum # of array elements printed */ + int strlen; /* default maximum # of bytes printed in strings */ + int follow; /* trace child processes */ +}; +extern struct options_t options; + +extern int opt_i; /* instruction pointer */ +extern int opt_r; /* print relative timestamp */ +extern int opt_t; /* print absolute timestamp */ +extern int opt_T; /* show the time spent inside each call */ + +struct opt_p_t { + pid_t pid; + struct opt_p_t *next; +}; + +struct opt_e_t { + char *name; + struct opt_e_t *next; +}; + +struct opt_F_t { + char *filename; + struct opt_F_t *next; +}; + +struct opt_x_t { + char *name; + int found; + struct opt_x_t *next; +}; + +extern struct opt_p_t *opt_p; /* attach to process with a given pid */ + +extern struct opt_e_t *opt_e; /* list of function names to display */ +extern int opt_e_enable; /* 0 if '!' is used, 1 otherwise */ + +extern struct opt_F_t *opt_F; /* alternate configuration file(s) */ + +extern struct opt_x_t *opt_x; /* list of functions to break at */ + +extern char **process_options(int argc, char **argv); diff --git a/output.c b/output.c new file mode 100644 index 0000000..bb07ab1 --- /dev/null +++ b/output.c @@ -0,0 +1,303 @@ +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" + +/* TODO FIXME XXX: include in common.h: */ +extern struct timeval current_time_spent; + +Dict *dict_opt_c = NULL; + +static Process *current_proc = 0; +static int current_depth = 0; +static int current_column = 0; + +static void +output_indent(Process *proc) { + current_column += + fprintf(options.output, "%*s", options.indent * proc->callstack_depth, ""); +} + +static void +begin_of_line(enum tof type, Process *proc) { + current_column = 0; + if (!proc) { + return; + } + if ((options.output != stderr) && (opt_p || options.follow)) { + current_column += fprintf(options.output, "%u ", proc->pid); + } else if (options.follow) { + current_column += fprintf(options.output, "[pid %u] ", proc->pid); + } + if (opt_r) { + struct timeval tv; + struct timezone tz; + static struct timeval old_tv = { 0, 0 }; + struct timeval diff; + + gettimeofday(&tv, &tz); + + if (old_tv.tv_sec == 0 && old_tv.tv_usec == 0) { + old_tv.tv_sec = tv.tv_sec; + old_tv.tv_usec = tv.tv_usec; + } + diff.tv_sec = tv.tv_sec - old_tv.tv_sec; + if (tv.tv_usec >= old_tv.tv_usec) { + diff.tv_usec = tv.tv_usec - old_tv.tv_usec; + } else { + diff.tv_sec--; + diff.tv_usec = 1000000 + tv.tv_usec - old_tv.tv_usec; + } + old_tv.tv_sec = tv.tv_sec; + old_tv.tv_usec = tv.tv_usec; + current_column += fprintf(options.output, "%3lu.%06d ", + diff.tv_sec, (int)diff.tv_usec); + } + if (opt_t) { + struct timeval tv; + struct timezone tz; + + gettimeofday(&tv, &tz); + if (opt_t > 2) { + current_column += fprintf(options.output, "%lu.%06d ", + tv.tv_sec, (int)tv.tv_usec); + } else if (opt_t > 1) { + struct tm *tmp = localtime(&tv.tv_sec); + current_column += + fprintf(options.output, "%02d:%02d:%02d.%06d ", + tmp->tm_hour, tmp->tm_min, tmp->tm_sec, + (int)tv.tv_usec); + } else { + struct tm *tmp = localtime(&tv.tv_sec); + current_column += fprintf(options.output, "%02d:%02d:%02d ", + tmp->tm_hour, tmp->tm_min, + tmp->tm_sec); + } + } + if (opt_i) { + if (type == LT_TOF_FUNCTION || type == LT_TOF_FUNCTIONR) { + current_column += fprintf(options.output, "[%p] ", + proc->return_addr); + } else { + current_column += fprintf(options.output, "[%p] ", + proc->instruction_pointer); + } + } + if (options.indent > 0 && type != LT_TOF_NONE) { + output_indent(proc); + } +} + +static Function * +name2func(char *name) { + Function *tmp; + const char *str1, *str2; + + tmp = list_of_functions; + while (tmp) { +#ifdef USE_DEMANGLE + str1 = options.demangle ? my_demangle(tmp->name) : tmp->name; + str2 = options.demangle ? my_demangle(name) : name; +#else + str1 = tmp->name; + str2 = name; +#endif + if (!strcmp(str1, str2)) { + + return tmp; + } + tmp = tmp->next; + } + return NULL; +} + +void +output_line(Process *proc, char *fmt, ...) { + va_list args; + + if (options.summary) { + return; + } + if (current_proc) { + if (current_proc->callstack[current_depth].return_addr) { + fprintf(options.output, " \n"); + } else { + fprintf(options.output, " \n"); + } + } + current_proc = 0; + if (!fmt) { + return; + } + begin_of_line(LT_TOF_NONE, proc); + + va_start(args, fmt); + vfprintf(options.output, fmt, args); + fprintf(options.output, "\n"); + va_end(args); + current_column = 0; +} + +static void +tabto(int col) { + if (current_column < col) { + fprintf(options.output, "%*s", col - current_column, ""); + } +} + +void +output_left(enum tof type, Process *proc, char *function_name) { + Function *func; + static arg_type_info *arg_unknown = NULL; + if (arg_unknown == NULL) + arg_unknown = lookup_prototype(ARGTYPE_UNKNOWN); + + if (options.summary) { + return; + } + if (current_proc) { + fprintf(options.output, " \n"); + current_proc = 0; + current_column = 0; + } + current_proc = proc; + current_depth = proc->callstack_depth; + proc->type_being_displayed = type; + begin_of_line(type, proc); +#ifdef USE_DEMANGLE + current_column += + fprintf(options.output, "%s(", + options.demangle ? my_demangle(function_name) : function_name); +#else + current_column += fprintf(options.output, "%s(", function_name); +#endif + + func = name2func(function_name); + if (!func) { + int i; + for (i = 0; i < 4; i++) { + current_column += + display_arg(type, proc, i, arg_unknown); + current_column += fprintf(options.output, ", "); + } + current_column += display_arg(type, proc, 4, arg_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->arg_info[i]); + current_column += fprintf(options.output, ", "); + } + if (func->num_params > func->params_right) { + current_column += + display_arg(type, proc, i, func->arg_info[i]); + if (func->params_right) { + current_column += fprintf(options.output, ", "); + } + } + if (func->params_right) { + save_register_args(type, proc); + } + } +} + +void +output_right(enum tof type, Process *proc, char *function_name) { + Function *func = name2func(function_name); + static arg_type_info *arg_unknown = NULL; + if (arg_unknown == NULL) + arg_unknown = lookup_prototype(ARGTYPE_UNKNOWN); + + if (options.summary) { + struct opt_c_struct *st; + if (!dict_opt_c) { + dict_opt_c = + dict_init(dict_key2hash_string, + dict_key_cmp_string); + } + st = dict_find_entry(dict_opt_c, function_name); + if (!st) { + char *na; + st = malloc(sizeof(struct opt_c_struct)); + na = strdup(function_name); + if (!st || !na) { + perror("malloc()"); + exit(1); + } + st->count = 0; + st->tv.tv_sec = st->tv.tv_usec = 0; + dict_enter(dict_opt_c, na, st); + } + if (st->tv.tv_usec + current_time_spent.tv_usec > 1000000) { + st->tv.tv_usec += current_time_spent.tv_usec - 1000000; + st->tv.tv_sec++; + } else { + st->tv.tv_usec += current_time_spent.tv_usec; + } + st->count++; + st->tv.tv_sec += current_time_spent.tv_sec; + +// fprintf(options.output, "%s <%lu.%06d>\n", function_name, +// current_time_spent.tv_sec, (int)current_time_spent.tv_usec); + return; + } + if (current_proc && (current_proc != proc || + current_depth != proc->callstack_depth)) { + fprintf(options.output, " \n"); + current_proc = 0; + } + if (current_proc != proc) { + begin_of_line(type, proc); +#ifdef USE_DEMANGLE + current_column += + fprintf(options.output, "<... %s resumed> ", + options.demangle ? my_demangle(function_name) : function_name); +#else + current_column += + fprintf(options.output, "<... %s resumed> ", function_name); +#endif + } + + if (!func) { + current_column += fprintf(options.output, ") "); + tabto(options.align - 1); + fprintf(options.output, "= "); + display_arg(type, proc, -1, arg_unknown); + } 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->arg_info[i]); + current_column += fprintf(options.output, ", "); + } + if (func->params_right) { + current_column += + display_arg(type, proc, i, func->arg_info[i]); + } + current_column += fprintf(options.output, ") "); + tabto(options.align - 1); + fprintf(options.output, "= "); + if (func->return_info->type == ARGTYPE_VOID) { + fprintf(options.output, ""); + } else { + display_arg(type, proc, -1, func->return_info); + } + } + if (opt_T) { + fprintf(options.output, " <%lu.%06d>", + current_time_spent.tv_sec, + (int)current_time_spent.tv_usec); + } + fprintf(options.output, "\n"); + current_proc = 0; + current_column = 0; +} diff --git a/output.h b/output.h new file mode 100644 index 0000000..c58577a --- /dev/null +++ b/output.h @@ -0,0 +1,3 @@ +void output_line(Process *proc, char *fmt, ...); +void output_left(enum tof type, Process *proc, char *function_name); +void output_right(enum tof type, Process *proc, char *function_name); diff --git a/proc.c b/proc.c new file mode 100644 index 0000000..bfc6e41 --- /dev/null +++ b/proc.c @@ -0,0 +1,65 @@ +#include +#include +#include +#include +#include + +#include "common.h" + +Process * +open_program(char *filename, pid_t pid) { + Process *proc; + proc = calloc(sizeof(Process), 1); + if (!proc) { + perror("malloc"); + exit(1); + } + proc->filename = strdup(filename); + proc->breakpoints_enabled = -1; + if (pid) { + proc->pid = pid; + } + breakpoints_init(proc); + + proc->next = list_of_processes; + list_of_processes = proc; + return proc; +} + +void +open_pid(pid_t pid) { + Process *proc; + char *filename; + + if (trace_pid(pid) < 0) { + fprintf(stderr, "Cannot attach to pid %u: %s\n", pid, + strerror(errno)); + return; + } + + filename = pid2name(pid); + + if (!filename) { + fprintf(stderr, "Cannot trace pid %u: %s\n", pid, + strerror(errno)); + return; + } + + proc = open_program(filename, pid); + continue_process(pid); + proc->breakpoints_enabled = 1; +} + +Process * +pid2proc(pid_t pid) { + Process *tmp; + + tmp = list_of_processes; + while (tmp) { + if (pid == tmp->pid) { + return tmp; + } + tmp = tmp->next; + } + return NULL; +} diff --git a/read_config_file.c b/read_config_file.c new file mode 100644 index 0000000..b4b1b56 --- /dev/null +++ b/read_config_file.c @@ -0,0 +1,680 @@ +#include "config.h" + +#include +#include +#include + +#include "common.h" + +static int line_no; +static char *filename; +static int error_count = 0; + +static arg_type_info *parse_type(char **str); + +Function *list_of_functions = NULL; + +/* Map of strings to type names. These do not need to be in any + * particular order */ +static struct list_of_pt_t { + char *name; + enum arg_type pt; +} list_of_pt[] = { + { + "void", ARGTYPE_VOID}, { + "int", ARGTYPE_INT}, { + "uint", ARGTYPE_UINT}, { + "long", ARGTYPE_LONG}, { + "ulong", ARGTYPE_ULONG}, { + "octal", ARGTYPE_OCTAL}, { + "char", ARGTYPE_CHAR}, { + "short", ARGTYPE_SHORT}, { + "ushort", ARGTYPE_USHORT}, { + "float", ARGTYPE_FLOAT}, { + "double", ARGTYPE_DOUBLE}, { + "addr", ARGTYPE_ADDR}, { + "file", ARGTYPE_FILE}, { + "format", ARGTYPE_FORMAT}, { + "string", ARGTYPE_STRING}, { + "array", ARGTYPE_ARRAY}, { + "struct", ARGTYPE_STRUCT}, { + "enum", ARGTYPE_ENUM}, { + NULL, ARGTYPE_UNKNOWN} /* Must finish with NULL */ +}; + +/* Array of prototype objects for each of the types. The order in this + * array must exactly match the list of enumerated values in + * common.h */ +static arg_type_info arg_type_prototypes[] = { + { ARGTYPE_VOID }, + { ARGTYPE_INT }, + { ARGTYPE_UINT }, + { ARGTYPE_LONG }, + { ARGTYPE_ULONG }, + { ARGTYPE_OCTAL }, + { ARGTYPE_CHAR }, + { ARGTYPE_SHORT }, + { ARGTYPE_USHORT }, + { ARGTYPE_FLOAT }, + { ARGTYPE_DOUBLE }, + { ARGTYPE_ADDR }, + { ARGTYPE_FILE }, + { ARGTYPE_FORMAT }, + { ARGTYPE_STRING }, + { ARGTYPE_STRING_N }, + { ARGTYPE_ARRAY }, + { ARGTYPE_ENUM }, + { ARGTYPE_STRUCT }, + { ARGTYPE_POINTER }, + { ARGTYPE_UNKNOWN } +}; + +arg_type_info * +lookup_prototype(enum arg_type at) { + if (at >= 0 && at <= ARGTYPE_COUNT) + return &arg_type_prototypes[at]; + else + return &arg_type_prototypes[ARGTYPE_COUNT]; /* UNKNOWN */ +} + +static arg_type_info * +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(" ,()#*;012345[", *(*str + strlen(tmp->name)))) { + *str += strlen(tmp->name); + return lookup_prototype(tmp->pt); + } + tmp++; + } + return lookup_prototype(ARGTYPE_UNKNOWN); +} + +static void +eat_spaces(char **str) { + while (**str == ' ') { + (*str)++; + } +} + +static char * +xstrndup(char *str, size_t len) { + char *ret = (char *) malloc(len + 1); + strncpy(ret, str, len); + ret[len] = 0; + return ret; +} + +static char * +parse_ident(char **str) { + char *ident = *str; + + if (!isalnum(**str) && **str != '_') { + output_line(0, "Syntax error in `%s', line %d: Bad identifier", + filename, line_no); + error_count++; + return NULL; + } + + while (**str && (isalnum(**str) || **str == '_')) { + ++(*str); + } + + return xstrndup(ident, *str - ident); +} + +/* + Returns position in string at the left parenthesis which starts the + function's argument signature. Returns NULL on error. +*/ +static char * +start_of_arg_sig(char *str) { + char *pos; + int stacked = 0; + + if (!strlen(str)) + return NULL; + + pos = &str[strlen(str)]; + do { + pos--; + if (pos < str) + return NULL; + while ((pos > str) && (*pos != ')') && (*pos != '(')) + pos--; + + if (*pos == ')') + stacked++; + else if (*pos == '(') + stacked--; + else + return NULL; + + } while (stacked > 0); + + return (stacked == 0) ? pos : NULL; +} + +static int +parse_int(char **str) { + char *end; + long n = strtol(*str, &end, 0); + if (end == *str) { + output_line(0, "Syntax error in `%s', line %d: Bad number (%s)", + filename, line_no, *str); + error_count++; + return 0; + } + + *str = end; + return n; +} + +/* + * Input: + * argN : The value of argument #N, counting from 1 (arg0 = retval) + * eltN : The value of element #N of the containing structure + * retval : The return value + * 0 : Error + * N : The numeric value N, if N > 0 + * + * Output: + * > 0 actual numeric value + * = 0 return value + * < 0 (arg -n), counting from one + */ +static int +parse_argnum(char **str) { + int multiplier = 1; + int n = 0; + + if (strncmp(*str, "arg", 3) == 0) { + (*str) += 3; + multiplier = -1; + } else if (strncmp(*str, "elt", 3) == 0) { + (*str) += 3; + multiplier = -1; + } else if (strncmp(*str, "retval", 6) == 0) { + (*str) += 6; + return 0; + } + + n = parse_int(str); + + return n * multiplier; +} + +struct typedef_node_t { + char *name; + arg_type_info *info; + struct typedef_node_t *next; +} *typedefs = NULL; + +static arg_type_info * +lookup_typedef(char **str) { + struct typedef_node_t *node; + char *end = *str; + while (*end && (isalnum(*end) || *end == '_')) + ++end; + if (end == *str) + return NULL; + + for (node = typedefs; node != NULL; node = node->next) { + if (strncmp(*str, node->name, end - *str) == 0) { + (*str) += strlen(node->name); + return node->info; + } + } + + return NULL; +} + +static void +parse_typedef(char **str) { + char *name; + arg_type_info *info; + struct typedef_node_t *binding; + + (*str) += strlen("typedef"); + eat_spaces(str); + + // Grab out the name of the type + name = parse_ident(str); + + // Skip = sign + eat_spaces(str); + if (**str != '=') { + output_line(0, + "Syntax error in `%s', line %d: expected '=', got '%c'", + filename, line_no, **str); + error_count++; + return; + } + (*str)++; + eat_spaces(str); + + // Parse the type + info = parse_type(str); + + // Insert onto beginning of linked list + binding = malloc(sizeof(*binding)); + binding->name = name; + binding->info = info; + binding->next = typedefs; + typedefs = binding; +} + +static size_t +arg_sizeof(arg_type_info * arg) { + if (arg->type == ARGTYPE_CHAR) { + return sizeof(char); + } else if (arg->type == ARGTYPE_SHORT || arg->type == ARGTYPE_USHORT) { + return sizeof(short); + } else if (arg->type == ARGTYPE_FLOAT) { + return sizeof(float); + } else if (arg->type == ARGTYPE_DOUBLE) { + return sizeof(double); + } else if (arg->type == ARGTYPE_ENUM) { + return sizeof(int); + } else if (arg->type == ARGTYPE_STRUCT) { + return arg->u.struct_info.size; + } else if (arg->type == ARGTYPE_POINTER) { + return sizeof(void*); + } else if (arg->type == ARGTYPE_ARRAY) { + if (arg->u.array_info.len_spec > 0) + return arg->u.array_info.len_spec * arg->u.array_info.elt_size; + else + return sizeof(void *); + } else { + return sizeof(int); + } +} + +#undef alignof +#define alignof(field,st) ((size_t) ((char*) &st.field - (char*) &st)) +static size_t +arg_align(arg_type_info * arg) { + struct { char c; char C; } cC; + struct { char c; short s; } cs; + struct { char c; int i; } ci; + struct { char c; long l; } cl; + struct { char c; void* p; } cp; + struct { char c; float f; } cf; + struct { char c; double d; } cd; + + static size_t char_alignment = alignof(C, cC); + static size_t short_alignment = alignof(s, cs); + static size_t int_alignment = alignof(i, ci); + static size_t long_alignment = alignof(l, cl); + static size_t ptr_alignment = alignof(p, cp); + static size_t float_alignment = alignof(f, cf); + static size_t double_alignment = alignof(d, cd); + + switch (arg->type) { + case ARGTYPE_LONG: + case ARGTYPE_ULONG: + return long_alignment; + case ARGTYPE_CHAR: + return char_alignment; + case ARGTYPE_SHORT: + case ARGTYPE_USHORT: + return short_alignment; + case ARGTYPE_FLOAT: + return float_alignment; + case ARGTYPE_DOUBLE: + return double_alignment; + case ARGTYPE_ADDR: + case ARGTYPE_FILE: + case ARGTYPE_FORMAT: + case ARGTYPE_STRING: + case ARGTYPE_STRING_N: + case ARGTYPE_POINTER: + return ptr_alignment; + + case ARGTYPE_ARRAY: + return arg_align(&arg->u.array_info.elt_type[0]); + + case ARGTYPE_STRUCT: + return arg_align(arg->u.struct_info.fields[0]); + + default: + return int_alignment; + } +} + +static size_t +align_skip(size_t alignment, size_t offset) { + if (offset % alignment) + return alignment - (offset % alignment); + else + return 0; +} + +/* I'm sure this isn't completely correct, but just try to get most of + * them right for now. */ +static void +align_struct(arg_type_info* info) { + size_t offset; + int i; + + if (info->u.struct_info.size != 0) + return; // Already done + + // Compute internal padding due to alignment constraints for + // various types. + offset = 0; + for (i = 0; info->u.struct_info.fields[i] != NULL; i++) { + arg_type_info *field = info->u.struct_info.fields[i]; + offset += align_skip(arg_align(field), offset); + info->u.struct_info.offset[i] = offset; + offset += arg_sizeof(field); + } + + info->u.struct_info.size = offset; +} + +static arg_type_info * +parse_nonpointer_type(char **str) { + arg_type_info *simple; + arg_type_info *info; + + if (strncmp(*str, "typedef", 7) == 0) { + parse_typedef(str); + return lookup_prototype(ARGTYPE_UNKNOWN); + } + + simple = str2type(str); + if (simple->type == ARGTYPE_UNKNOWN) { + info = lookup_typedef(str); + if (info) + return info; + else + return simple; // UNKNOWN + } + + info = malloc(sizeof(*info)); + info->type = simple->type; + + /* Code to parse parameterized types will go into the following + switch statement. */ + + switch (info->type) { + + /* Syntax: array ( type, N|argN ) */ + case ARGTYPE_ARRAY: + (*str)++; // Get past open paren + eat_spaces(str); + if ((info->u.array_info.elt_type = parse_type(str)) == NULL) + return NULL; + info->u.array_info.elt_size = + arg_sizeof(info->u.array_info.elt_type); + (*str)++; // Get past comma + eat_spaces(str); + info->u.array_info.len_spec = parse_argnum(str); + (*str)++; // Get past close paren + return info; + + /* Syntax: enum ( keyname=value,keyname=value,... ) */ + case ARGTYPE_ENUM:{ + struct enum_opt { + char *key; + int value; + struct enum_opt *next; + }; + struct enum_opt *list = NULL; + struct enum_opt *p; + int entries = 0; + int ii; + + eat_spaces(str); + (*str)++; // Get past open paren + eat_spaces(str); + + while (**str && **str != ')') { + p = (struct enum_opt *) malloc(sizeof(*p)); + eat_spaces(str); + p->key = parse_ident(str); + if (error_count) { + free(p); + return NULL; + } + eat_spaces(str); + if (**str != '=') { + free(p->key); + free(p); + output_line(0, + "Syntax error in `%s', line %d: expected '=', got '%c'", + filename, line_no, **str); + error_count++; + return NULL; + } + ++(*str); + eat_spaces(str); + p->value = parse_int(str); + p->next = list; + list = p; + ++entries; + + // Skip comma + eat_spaces(str); + if (**str == ',') { + (*str)++; + eat_spaces(str); + } + } + + info->u.enum_info.entries = entries; + info->u.enum_info.keys = + (char **) malloc(entries * sizeof(char *)); + info->u.enum_info.values = + (int *) malloc(entries * sizeof(int)); + for (ii = 0, p = NULL; list; ++ii, list = list->next) { + if (p) + free(p); + info->u.enum_info.keys[ii] = list->key; + info->u.enum_info.values[ii] = list->value; + p = list; + } + if (p) + free(p); + + return info; + } + + case ARGTYPE_STRING: + if (!isdigit(**str) && **str != '[') { + /* Oops, was just a simple string after all */ + free(info); + return simple; + } + + info->type = ARGTYPE_STRING_N; + + /* Backwards compatibility for string0, string1, ... */ + if (isdigit(**str)) { + info->u.string_n_info.size_spec = -parse_int(str); + return info; + } + + (*str)++; // Skip past opening [ + eat_spaces(str); + info->u.string_n_info.size_spec = parse_argnum(str); + eat_spaces(str); + (*str)++; // Skip past closing ] + return info; + + // Syntax: struct ( type,type,type,... ) + case ARGTYPE_STRUCT:{ + int field_num = 0; + (*str)++; // Get past open paren + info->u.struct_info.fields = + malloc((MAX_ARGS + 1) * sizeof(void *)); + info->u.struct_info.offset = + malloc((MAX_ARGS + 1) * sizeof(size_t)); + info->u.struct_info.size = 0; + eat_spaces(str); // Empty arg list with whitespace inside + while (**str && **str != ')') { + if (field_num == MAX_ARGS) { + output_line(0, + "Error in `%s', line %d: Too many structure elements", + filename, line_no); + error_count++; + return NULL; + } + eat_spaces(str); + if (field_num != 0) { + (*str)++; // Get past comma + eat_spaces(str); + } + if ((info->u.struct_info.fields[field_num++] = + parse_type(str)) == NULL) + return NULL; + + // Must trim trailing spaces so the check for + // the closing paren is simple + eat_spaces(str); + } + (*str)++; // Get past closing paren + info->u.struct_info.fields[field_num] = NULL; + align_struct(info); + return info; + } + + default: + if (info->type == ARGTYPE_UNKNOWN) { + output_line(0, "Syntax error in `%s', line %d: " + "Unknown type encountered", + filename, line_no); + free(info); + error_count++; + return NULL; + } else { + return info; + } + } +} + +static arg_type_info * +parse_type(char **str) { + arg_type_info *info = parse_nonpointer_type(str); + while (**str == '*') { + arg_type_info *outer = malloc(sizeof(*info)); + outer->type = ARGTYPE_POINTER; + outer->u.ptr_info.info = info; + (*str)++; + info = outer; + } + return info; +} + +static Function * +process_line(char *buf) { + Function fun; + Function *fun_p; + char *str = buf; + char *tmp; + int i; + int float_num = 0; + + line_no++; + debug(3, "Reading line %d of `%s'", line_no, filename); + eat_spaces(&str); + fun.return_info = parse_type(&str); + if (fun.return_info == NULL) + return NULL; + if (fun.return_info->type == ARGTYPE_UNKNOWN) { + debug(3, " Skipping line %d", line_no); + return NULL; + } + debug(4, " return_type = %d", fun.return_info->type); + eat_spaces(&str); + tmp = start_of_arg_sig(str); + if (!tmp) { + output_line(0, "Syntax error in `%s', line %d", filename, + line_no); + error_count++; + return NULL; + } + *tmp = '\0'; + fun.name = strdup(str); + str = tmp + 1; + debug(3, " 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.arg_info[i] = parse_type(&str); + if (fun.arg_info[i] == NULL) { + output_line(0, "Syntax error in `%s', line %d" + ": unknown argument type", + filename, line_no); + error_count++; + return NULL; + } + if (fun.arg_info[i]->type == ARGTYPE_FLOAT) + fun.arg_info[i]->u.float_info.float_index = float_num++; + else if (fun.arg_info[i]->type == ARGTYPE_DOUBLE) + fun.arg_info[i]->u.double_info.float_index = float_num++; + eat_spaces(&str); + if (*str == ',') { + str++; + continue; + } else if (*str == ')') { + continue; + } else { + if (str[strlen(str) - 1] == '\n') + str[strlen(str) - 1] = '\0'; + output_line(0, "Syntax error in `%s', line %d at ...\"%s\"", + filename, line_no, str); + error_count++; + return NULL; + } + } + fun.num_params = i; + fun_p = malloc(sizeof(Function)); + if (!fun_p) { + perror("ltrace: malloc"); + exit(1); + } + memcpy(fun_p, &fun, sizeof(Function)); + return fun_p; +} + +void +read_config_file(char *file) { + FILE *stream; + char buf[1024]; + + filename = file; + stream = fopen(filename, "r"); + if (!stream) { + return; + } + + debug(1, "Reading config file `%s'...", filename); + + line_no = 0; + while (fgets(buf, 1024, stream)) { + Function *tmp; + + error_count = 0; + tmp = process_line(buf); + + if (tmp) { + debug(2, "New function: `%s'", tmp->name); + tmp->next = list_of_functions; + list_of_functions = tmp; + } + } + fclose(stream); +} diff --git a/read_config_file.h b/read_config_file.h new file mode 100644 index 0000000..8000b1c --- /dev/null +++ b/read_config_file.h @@ -0,0 +1 @@ +extern void read_config_file(char *); diff --git a/summary.c b/summary.c new file mode 100644 index 0000000..dab845c --- /dev/null +++ b/summary.c @@ -0,0 +1,86 @@ +#include "config.h" + +#include +#include +#include + +#include "common.h" + +static int num_entries = 0; +static struct entry_st { + char *name; + int count; + struct timeval tv; +} *entries = NULL; + +static int tot_count = 0; +static unsigned long int tot_usecs = 0; + +static void fill_struct(void *key, void *value, void *data) +{ + struct opt_c_struct *st = (struct opt_c_struct *)value; + + entries = realloc(entries, (num_entries + 1) * sizeof(struct entry_st)); + if (!entries) { + perror("realloc()"); + exit(1); + } + entries[num_entries].name = (char *)key; + entries[num_entries].count = st->count; + entries[num_entries].tv = st->tv; + + tot_count += st->count; + tot_usecs += 1000000 * st->tv.tv_sec; + tot_usecs += st->tv.tv_usec; + + num_entries++; +} + +static int compar(const void *a, const void *b) +{ + struct entry_st *en1, *en2; + + en1 = (struct entry_st *)a; + en2 = (struct entry_st *)b; + + if (en2->tv.tv_sec - en1->tv.tv_sec) { + return (en2->tv.tv_sec - en1->tv.tv_sec); + } else { + return (en2->tv.tv_usec - en1->tv.tv_usec); + } +} + +void show_summary(void) +{ + int i; + + num_entries = 0; + entries = NULL; + + dict_apply_to_all(dict_opt_c, fill_struct, NULL); + + qsort(entries, num_entries, sizeof(*entries), compar); + + fprintf(options.output, "%% time seconds usecs/call calls function\n"); + fprintf(options.output, "------ ----------- ----------- --------- --------------------\n"); + for (i = 0; i < num_entries; i++) { + unsigned long long int c; + unsigned long long int p; + c = 1000000 * (int)entries[i].tv.tv_sec + + (int)entries[i].tv.tv_usec; + p = 100000 * c / tot_usecs + 5; + fprintf(options.output, "%3lu.%02lu %4d.%06d %11lu %9d %s\n", + (unsigned long int)(p / 1000), + (unsigned long int)((p / 10) % 100), + (int)entries[i].tv.tv_sec, (int)entries[i].tv.tv_usec, + (unsigned long int)(c / entries[i].count), + entries[i].count, +#ifdef USE_DEMANGLE + options.demangle ? my_demangle(entries[i].name) : +#endif + entries[i].name); + } + fprintf(options.output, "------ ----------- ----------- --------- --------------------\n"); + fprintf(options.output, "100.00 %4lu.%06lu %9d total\n", tot_usecs / 1000000, + tot_usecs % 1000000, tot_count); +} diff --git a/sysdeps/README b/sysdeps/README new file mode 100644 index 0000000..ce033ef --- /dev/null +++ b/sysdeps/README @@ -0,0 +1,32 @@ +Each operating system must have a subdir here, with a Makefile +The first target of that Makefile must build a file "sysdep.o" in this +directory. +The "clean" target of that Makefile must undo all the efects of the +first target, and must remove "sysdep.o" in this dir. + +Files "sysdep.h", "signalent.h" and "syscallent.h" must be present +inside the directory after invoking the first target of the Makefile. + +----------- +"sysdep.o" must export the following functions: + +Event * next_event(void); +void continue_after_breakpoint(Process * proc, Breakpoint * sbp, int delete_it); +void continue_after_signal(pid_t pid, int signum); +void continue_enabling_breakpoint(pid_t pid, Breakpoint * sbp); +void continue_process(pid_t pid); +void enable_breakpoint(pid_t pid, Breakpoint * sbp); +void disable_breakpoint(pid_t pid, Breakpoint * sbp); +int fork_p(int sysnum); +int exec_p(int sysnum); +int syscall_p(Process * proc, int status, int * sysnum); +void * get_instruction_pointer(pid_t pid); +void * get_stack_pointer(pid_t pid); +void * get_return_addr(pid_t pid, void * stack_pointer); +long gimme_arg(enum tof type, Process * proc, arg_type_info*); +int umovestr(Process * proc, void * addr, int len, void * laddr); +int umovelong(Process * proc, void * addr, long * result); +char * pid2name(pid_t pid); +void trace_me(void); +int trace_pid(pid_t pid); +void untrace_pid(pid_t pid); diff --git a/sysdeps/linux-gnu/Makefile b/sysdeps/linux-gnu/Makefile new file mode 100644 index 0000000..eb1ec60 --- /dev/null +++ b/sysdeps/linux-gnu/Makefile @@ -0,0 +1,60 @@ +ARCH := $(shell uname -m | sed \ + -e s/i.86/i386/ \ + -e s/sun4u/sparc64/ \ + -e s/sparc64/sparc/ \ + -e s/arm.*/arm/ \ + -e s/sa110/arm/ \ + -e s/ppc64/ppc/ \ + -e s/s390x/s390/ \ + ) + +CPPFLAGS += -I$(TOPDIR)/sysdeps/linux-gnu/$(ARCH) + +OBJ = events.o trace.o proc.o breakpoint.o + +all: sysdep.h signalent.h syscallent.h arch_syscallent.h signalent1.h syscallent1.h ../sysdep.o + +sysdep.h: $(ARCH)/arch.h + cat $(ARCH)/arch.h > sysdep.h + +signalent.h: + cp $(ARCH)/signalent.h signalent.h +signalent1.h: + if [ -f $(ARCH)/signalent1.h ]; then \ + cp $(ARCH)/signalent1.h signalent1.h; \ + else \ + > signalent1.h; \ + fi + +syscallent.h: + cp $(ARCH)/syscallent.h syscallent.h + +syscallent1.h: + if [ -f $(ARCH)/syscallent1.h ]; then \ + cp $(ARCH)/syscallent1.h syscallent1.h; \ + else \ + > syscallent1.h; \ + fi + +arch_syscallent.h: + if [ -f $(ARCH)/arch_syscallent.h ]; then \ + cp $(ARCH)/arch_syscallent.h arch_syscallent.h; \ + else \ + > arch_syscallent.h; \ + fi + +../sysdep.o: os.o $(ARCH)/arch.o + $(CC) -nostdlib -r -o ../sysdep.o os.o $(ARCH)/arch.o + +os.o: $(OBJ) + $(CC) -nostdlib -r -o os.o $(OBJ) + +$(ARCH)/arch.o: dummy + $(MAKE) -C $(ARCH) + +clean: + $(MAKE) -C $(ARCH) clean + rm -f $(OBJ) sysdep.h signalent.h signalent1.h syscallent.h arch_syscallent.h + rm -f syscallent1.h os.o sysdep.o ../sysdep.o + +dummy: diff --git a/sysdeps/linux-gnu/README b/sysdeps/linux-gnu/README new file mode 100644 index 0000000..a8bc8ee --- /dev/null +++ b/sysdeps/linux-gnu/README @@ -0,0 +1,13 @@ +* "arch/syscallent.h" is made from . + It can be done automatically with "mksyscallent" for all the + architectures except "mips" (as of linux-2.2.12) + +* "arch/signalent.h" is made from . + It can be done automatically with "mksignalent" for all the + architectures. (linux-2.2.12) + +* s390 uses mksyscallent_s390, rather than mksyscallent + +* NOTE: This does not currently work for cross-compilers; Maybe + I should guess the architecture using `gcc -print-libgcc-file-name' + instead of `uname -m' (or even better, use the value returned by autoconf) diff --git a/sysdeps/linux-gnu/alpha/Makefile b/sysdeps/linux-gnu/alpha/Makefile new file mode 100644 index 0000000..60d7531 --- /dev/null +++ b/sysdeps/linux-gnu/alpha/Makefile @@ -0,0 +1,10 @@ +OBJ = trace.o regs.o plt.o + +all: arch.o + +arch.o: $(OBJ) + $(CC) -nostdlib -r -o arch.o $(OBJ) + +clean: + $(RM) $(OBJ) arch.o + diff --git a/sysdeps/linux-gnu/alpha/arch.h b/sysdeps/linux-gnu/alpha/arch.h new file mode 100644 index 0000000..1107b5f --- /dev/null +++ b/sysdeps/linux-gnu/alpha/arch.h @@ -0,0 +1,8 @@ +#define BREAKPOINT_VALUE { 0x80, 0x00, 0x00, 0x00 } +#define BREAKPOINT_LENGTH 4 +#define DECR_PC_AFTER_BREAK 4 + +#define LT_ELFCLASS ELFCLASS64 +#define LT_ELF_MACHINE EM_ALPHA +#define LT_ELFCLASS2 ELFCLASS64 +#define LT_ELF_MACHINE2 EM_FAKE_ALPHA diff --git a/sysdeps/linux-gnu/alpha/plt.c b/sysdeps/linux-gnu/alpha/plt.c new file mode 100644 index 0000000..83337b2 --- /dev/null +++ b/sysdeps/linux-gnu/alpha/plt.c @@ -0,0 +1,12 @@ +#include +#include "common.h" + +GElf_Addr +arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela * rela) { + return lte->plt_addr + ndx * 12 + 32; +} + +void * +sym2addr(Process *proc, struct library_symbol *sym) { + return sym->enter_addr; +} diff --git a/sysdeps/linux-gnu/alpha/ptrace.h b/sysdeps/linux-gnu/alpha/ptrace.h new file mode 100644 index 0000000..c3cbcb6 --- /dev/null +++ b/sysdeps/linux-gnu/alpha/ptrace.h @@ -0,0 +1 @@ +#include diff --git a/sysdeps/linux-gnu/alpha/regs.c b/sysdeps/linux-gnu/alpha/regs.c new file mode 100644 index 0000000..9554e48 --- /dev/null +++ b/sysdeps/linux-gnu/alpha/regs.c @@ -0,0 +1,40 @@ +#include "config.h" + +#include +#include +#include + +#include "common.h" + +#if (!defined(PTRACE_PEEKUSER) && defined(PTRACE_PEEKUSR)) +# define PTRACE_PEEKUSER PTRACE_PEEKUSR +#endif + +#if (!defined(PTRACE_POKEUSER) && defined(PTRACE_POKEUSR)) +# define PTRACE_POKEUSER PTRACE_POKEUSR +#endif + +void * +get_instruction_pointer(Process *proc) { + return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, 64 /* REG_PC */ , 0); +} + +void +set_instruction_pointer(Process *proc, void *addr) { + ptrace(PTRACE_POKEUSER, proc->pid, 64 /* REG_PC */ , addr); +} + +void * +get_stack_pointer(Process *proc) { + return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, 30 /* REG_FP */ , 0); +} + +void * +get_return_addr(Process *proc, void *stack_pointer) { + return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, 26 /* RA */ , 0); +} + +void +set_return_addr(Process *proc, void *addr) { + ptrace(PTRACE_POKEUSER, proc->pid, 26 /* RA */ , addr); +} diff --git a/sysdeps/linux-gnu/alpha/signalent.h b/sysdeps/linux-gnu/alpha/signalent.h new file mode 100644 index 0000000..c2a6170 --- /dev/null +++ b/sysdeps/linux-gnu/alpha/signalent.h @@ -0,0 +1,32 @@ +"SIG_0", /* 0 */ + "SIGHUP", /* 1 */ + "SIGINT", /* 2 */ + "SIGQUIT", /* 3 */ + "SIGILL", /* 4 */ + "SIGTRAP", /* 5 */ + "SIGABRT", /* 6 */ + "SIGEMT", /* 7 */ + "SIGFPE", /* 8 */ + "SIGKILL", /* 9 */ + "SIGBUS", /* 10 */ + "SIGSEGV", /* 11 */ + "SIGSYS", /* 12 */ + "SIGPIPE", /* 13 */ + "SIGALRM", /* 14 */ + "SIGTERM", /* 15 */ + "SIGURG", /* 16 */ + "SIGSTOP", /* 17 */ + "SIGTSTP", /* 18 */ + "SIGCONT", /* 19 */ + "SIGCHLD", /* 20 */ + "SIGTTIN", /* 21 */ + "SIGTTOU", /* 22 */ + "SIGIO", /* 23 */ + "SIGXCPU", /* 24 */ + "SIGXFSZ", /* 25 */ + "SIGVTALRM", /* 26 */ + "SIGPROF", /* 27 */ + "SIGWINCH", /* 28 */ + "SIGINFO", /* 29 */ + "SIGUSR1", /* 30 */ + "SIGUSR2", /* 31 */ diff --git a/sysdeps/linux-gnu/alpha/syscallent.h b/sysdeps/linux-gnu/alpha/syscallent.h new file mode 100644 index 0000000..7cacc8c --- /dev/null +++ b/sysdeps/linux-gnu/alpha/syscallent.h @@ -0,0 +1,439 @@ +"osf_syscall", /* 0, not implemented */ + "exit", /* 1 */ + "fork", /* 2 */ + "read", /* 3 */ + "write", /* 4 */ + "osf_old_open", /* 5, not implemented */ + "close", /* 6 */ + "osf_wait4", /* 7 */ + "osf_old_creat", /* 8, not implemented */ + "link", /* 9 */ + "unlink", /* 10 */ + "osf_execve", /* 11, not implemented */ + "chdir", /* 12 */ + "fchdir", /* 13 */ + "mknod", /* 14 */ + "chmod", /* 15 */ + "chown", /* 16 */ + "brk", /* 17 */ + "osf_getfsstat", /* 18, not implemented */ + "lseek", /* 19 */ + "getxpid", /* 20 */ + "osf_mount", /* 21 */ + "umount", /* 22 */ + "setuid", /* 23 */ + "getxuid", /* 24 */ + "exec_with_loader", /* 25, not implemented */ + "ptrace", /* 26 */ + "osf_nrecmsg", /* 27, not implemented */ + "osf_nsendmsg", /* 28, not implemented */ + "osf_nrecvfrom", /* 29, not implemented */ + "osf_naccept", /* 30, not implemented */ + "osf_ngetpeername", /* 31, not implemented */ + "osf_ngetsocketname", /* 32, not implemented */ + "access", /* 33 */ + "osf_chflags", /* 34, not implemented */ + "osf_fchflags", /* 35, not implemented */ + "sync", /* 36 */ + "kill", /* 37 */ + "osf_old_stat", /* 38, not implemented */ + "setpgid", /* 39 */ + "osf_old_lstat", /* 40, not implemented */ + "dup", /* 41 */ + "pipe", /* 42 */ + "osf_set_program_attributes", /* 43 */ + "osf_profil", /* 44, not implemented */ + "open", /* 45 */ + "osf_old_sigaction", /* 46, not implemented */ + "getxgid", /* 47 */ + "osf_sigprocmask", /* 48 */ + "osf_getlogin", /* 49, not implemented */ + "osf_setlogin", /* 50, not implemented */ + "acct", /* 51 */ + "sigpending", /* 52 */ + "SYS_53", /* 53 */ + "ioctl", /* 54 */ + "osf_reboot", /* 55, not implemented */ + "osf_revoke", /* 56, not implemented */ + "symlink", /* 57 */ + "readlink", /* 58 */ + "execve", /* 59 */ + "umask", /* 60 */ + "chroot", /* 61 */ + "osf_old_fstat", /* 62, not implemented */ + "getpgrp", /* 63 */ + "getpagesize", /* 64 */ + "osf_mremap", /* 65, not implemented */ + "vfork", /* 66 */ + "stat", /* 67 */ + "lstat", /* 68 */ + "osf_sbrk", /* 69, not implemented */ + "osf_sstk", /* 70, not implemented */ + "mmap", /* 71 */ + "osf_old_vadvise", /* 72, not implemented */ + "munmap", /* 73 */ + "mprotect", /* 74 */ + "madvise", /* 75 */ + "vhangup", /* 76 */ + "osf_kmodcall", /* 77, not implemented */ + "osf_mincore", /* 78, not implemented */ + "getgroups", /* 79 */ + "setgroups", /* 80 */ + "osf_old_getpgrp", /* 81, not implemented */ + "setpgrp", /* 82 */ + "osf_setitimer", /* 83 */ + "osf_old_wait", /* 84, not implemented */ + "osf_table", /* 85, not implemented */ + "osf_getitimer", /* 86 */ + "gethostname", /* 87 */ + "sethostname", /* 88 */ + "getdtablesize", /* 89 */ + "dup2", /* 90 */ + "fstat", /* 91 */ + "fcntl", /* 92 */ + "osf_select", /* 93 */ + "poll", /* 94 */ + "fsync", /* 95 */ + "setpriority", /* 96 */ + "socket", /* 97 */ + "connect", /* 98 */ + "accept", /* 99 */ + "osf_getpriority", /* 100 */ + "send", /* 101 */ + "recv", /* 102 */ + "sigreturn", /* 103 */ + "bind", /* 104 */ + "setsockopt", /* 105 */ + "listen", /* 106 */ + "osf_plock", /* 107, not implemented */ + "osf_old_sigvec", /* 108, not implemented */ + "osf_old_sigblock", /* 109, not implemented */ + "osf_old_sigsetmask", /* 110, not implemented */ + "sigsuspend", /* 111 */ + "sigstack", /* 112 */ + "recvmsg", /* 113 */ + "sendmsg", /* 114 */ + "osf_old_vtrace", /* 115, not implemented */ + "osf_gettimeofday", /* 116 */ + "osf_getrusage", /* 117 */ + "getsockopt", /* 118 */ + "SYS_119", /* 119 */ + "readv", /* 120 */ + "writev", /* 121 */ + "osf_settimeofday", /* 122 */ + "fchown", /* 123 */ + "fchmod", /* 124 */ + "recvfrom", /* 125 */ + "setreuid", /* 126 */ + "setregid", /* 127 */ + "rename", /* 128 */ + "truncate", /* 129 */ + "ftruncate", /* 130 */ + "flock", /* 131 */ + "setgid", /* 132 */ + "sendto", /* 133 */ + "shutdown", /* 134 */ + "socketpair", /* 135 */ + "mkdir", /* 136 */ + "rmdir", /* 137 */ + "osf_utimes", /* 138 */ + "osf_old_sigreturn", /* 139 */ + "osf_adjtime", /* 140, not implemented */ + "getpeername", /* 141 */ + "osf_gethostid", /* 142, not implemented */ + "osf_sethostid", /* 143, not implemented */ + "getrlimit", /* 144 */ + "setrlimit", /* 145 */ + "osf_old_killpg", /* 146, not implemented */ + "setsid", /* 147 */ + "quotactl", /* 148 */ + "osf_oldquota", /* 149, not implemented */ + "getsockname", /* 150 */ + "SYS_151", /* 151 */ + "SYS_152", /* 152 */ + "osf_pid_block", /* 153, not implemented */ + "osf_pid_unblock", /* 154, not implemented */ + "SYS_155", /* 155 */ + "sigaction", /* 156 */ + "osf_sigwaitprim", /* 157, not implemented */ + "osf_nfssvc", /* 158, not implemented */ + "osf_getdirentries", /* 159 */ + "osf_statfs", /* 160 */ + "osf_fstatfs", /* 161 */ + "SYS_162", /* 162 */ + "osf_asynch_daemon", /* 163, not implemented */ + "osf_getfh", /* 164, not implemented */ + "osf_getdomainname", /* 165 */ + "setdomainname", /* 166 */ + "SYS_167", /* 167 */ + "SYS_168", /* 168 */ + "osf_exportfs", /* 169, not implemented */ + "SYS_170", /* 170 */ + "SYS_171", /* 171 */ + "SYS_172", /* 172 */ + "SYS_173", /* 173 */ + "SYS_174", /* 174 */ + "SYS_175", /* 175 */ + "SYS_176", /* 176 */ + "SYS_177", /* 177 */ + "SYS_178", /* 178 */ + "SYS_179", /* 179 */ + "SYS_180", /* 180 */ + "osf_alt_plock", /* 181, not implemented */ + "SYS_182", /* 182 */ + "SYS_183", /* 183 */ + "osf_getmnt", /* 184, not implemented */ + "SYS_185", /* 185 */ + "SYS_186", /* 186 */ + "osf_alt_sigpending", /* 187, not implemented */ + "osf_alt_setsid", /* 188, not implemented */ + "SYS_189", /* 189 */ + "SYS_190", /* 190 */ + "SYS_191", /* 191 */ + "SYS_192", /* 192 */ + "SYS_193", /* 193 */ + "SYS_194", /* 194 */ + "SYS_195", /* 195 */ + "SYS_196", /* 196 */ + "SYS_197", /* 197 */ + "SYS_198", /* 198 */ + "osf_swapon", /* 199 */ + "msgctl", /* 200 */ + "msgget", /* 201 */ + "msgrcv", /* 202 */ + "msgsnd", /* 203 */ + "semctl", /* 204 */ + "semget", /* 205 */ + "semop", /* 206 */ + "osf_utsname", /* 207 */ + "lchown", /* 208 */ + "osf_shmat", /* 209 */ + "shmctl", /* 210 */ + "shmdt", /* 211 */ + "shmget", /* 212 */ + "osf_mvalid", /* 213, not implemented */ + "osf_getaddressconf", /* 214, not implemented */ + "osf_msleep", /* 215, not implemented */ + "osf_mwakeup", /* 216, not implemented */ + "msync", /* 217 */ + "osf_signal", /* 218, not implemented */ + "osf_utc_gettime", /* 219, not implemented */ + "osf_utc_adjtime", /* 220, not implemented */ + "SYS_221", /* 221 */ + "osf_security", /* 222, not implemented */ + "osf_kloadcall", /* 223, not implemented */ + "SYS_224", /* 224 */ + "SYS_225", /* 225 */ + "SYS_226", /* 226 */ + "SYS_227", /* 227 */ + "SYS_228", /* 228 */ + "SYS_229", /* 229 */ + "SYS_230", /* 230 */ + "SYS_231", /* 231 */ + "SYS_232", /* 232 */ + "getpgid", /* 233 */ + "getsid", /* 234 */ + "sigaltstack", /* 235 */ + "osf_waitid", /* 236, not implemented */ + "osf_priocntlset", /* 237, not implemented */ + "osf_sigsendset", /* 238, not implemented */ + "osf_set_speculative", /* 239, not implemented */ + "osf_msfs_syscall", /* 240, not implemented */ + "osf_sysinfo", /* 241 */ + "osf_uadmin", /* 242, not implemented */ + "osf_fuser", /* 243, not implemented */ + "osf_proplist_syscall", /* 244 */ + "osf_ntp_adjtime", /* 245, not implemented */ + "osf_ntp_gettime", /* 246, not implemented */ + "osf_pathconf", /* 247, not implemented */ + "osf_fpathconf", /* 248, not implemented */ + "SYS_249", /* 249 */ + "osf_uswitch", /* 250, not implemented */ + "osf_usleep_thread", /* 251 */ + "osf_audcntl", /* 252, not implemented */ + "osf_audgen", /* 253, not implemented */ + "sysfs", /* 254 */ + "osf_subsysinfo", /* 255, not implemented */ + "osf_getsysinfo", /* 256 */ + "osf_setsysinfo", /* 257 */ + "osf_afs_syscall", /* 258, not implemented */ + "osf_swapctl", /* 259, not implemented */ + "osf_memcntl", /* 260, not implemented */ + "osf_fdatasync", /* 261, not implemented */ + "SYS_262", /* 262 */ + "SYS_263", /* 263 */ + "SYS_264", /* 264 */ + "SYS_265", /* 265 */ + "SYS_266", /* 266 */ + "SYS_267", /* 267 */ + "SYS_268", /* 268 */ + "SYS_269", /* 269 */ + "SYS_270", /* 270 */ + "SYS_271", /* 271 */ + "SYS_272", /* 272 */ + "SYS_273", /* 273 */ + "SYS_274", /* 274 */ + "SYS_275", /* 275 */ + "SYS_276", /* 276 */ + "SYS_277", /* 277 */ + "SYS_278", /* 278 */ + "SYS_279", /* 279 */ + "SYS_280", /* 280 */ + "SYS_281", /* 281 */ + "SYS_282", /* 282 */ + "SYS_283", /* 283 */ + "SYS_284", /* 284 */ + "SYS_285", /* 285 */ + "SYS_286", /* 286 */ + "SYS_287", /* 287 */ + "SYS_288", /* 288 */ + "SYS_289", /* 289 */ + "SYS_290", /* 290 */ + "SYS_291", /* 291 */ + "SYS_292", /* 292 */ + "SYS_293", /* 293 */ + "SYS_294", /* 294 */ + "SYS_295", /* 295 */ + "SYS_296", /* 296 */ + "SYS_297", /* 297 */ + "SYS_298", /* 298 */ + "SYS_299", /* 299 */ + "bdflush", /* 300 */ + "sethae", /* 301 */ + "mount", /* 302 */ + "adjtimex32", /* 303 */ + "swapoff", /* 304 */ + "getdents", /* 305 */ + "create_module", /* 306 */ + "init_module", /* 307 */ + "delete_module", /* 308 */ + "get_kernel_syms", /* 309 */ + "syslog", /* 310 */ + "reboot", /* 311 */ + "clone", /* 312 */ + "uselib", /* 313 */ + "mlock", /* 314 */ + "munlock", /* 315 */ + "mlockall", /* 316 */ + "munlockall", /* 317 */ + "sysinfo", /* 318 */ + "sysctl", /* 319 */ + "idle", /* 320 */ + "oldumount", /* 321 */ + "swapon", /* 322 */ + "times", /* 323 */ + "personality", /* 324 */ + "setfsuid", /* 325 */ + "setfsgid", /* 326 */ + "ustat", /* 327 */ + "statfs", /* 328 */ + "fstatfs", /* 329 */ + "sched_setparam", /* 330 */ + "sched_getparam", /* 331 */ + "sched_setscheduler", /* 332 */ + "sched_getscheduler", /* 333 */ + "sched_yield", /* 334 */ + "sched_get_priority_max", /* 335 */ + "sched_get_priority_min", /* 336 */ + "sched_rr_get_interval", /* 337 */ + "afs_syscall", /* 338 */ + "uname", /* 339 */ + "nanosleep", /* 340 */ + "mremap", /* 341 */ + "nfsservctl", /* 342 */ + "setresuid", /* 343 */ + "getresuid", /* 344 */ + "pciconfig_read", /* 345 */ + "pciconfig_write", /* 346 */ + "query_module", /* 347 */ + "prctl", /* 348 */ + "pread", /* 349 */ + "pwrite", /* 350 */ + "rt_sigreturn", /* 351 */ + "rt_sigaction", /* 352 */ + "rt_sigprocmask", /* 353 */ + "rt_sigpending", /* 354 */ + "rt_sigtimedwait", /* 355 */ + "rt_sigqueueinfo", /* 356 */ + "rt_sigsuspend", /* 357 */ + "select", /* 358 */ + "gettimeofday", /* 359 */ + "settimeofday", /* 360 */ + "getitimer", /* 361 */ + "setitimer", /* 362 */ + "utimes", /* 363 */ + "getrusage", /* 364 */ + "wait4", /* 365 */ + "adjtimex", /* 366 */ + "getcwd", /* 367 */ + "capget", /* 368 */ + "capset", /* 369 */ + "sendfile", /* 370 */ + "setresgid", /* 371 */ + "getresgid", /* 372 */ + "dipc", /* 373, not implemented */ + "pivot_root", /* 374 */ + "mincore", /* 375 */ + "pciconfig_iobase", /* 376 */ + "getdents64", /* 377 */ + "gettid", /* 378 */ + "readahead", /* 379 */ + "SYS_380", /* 380 */ + "tkill", /* 381 */ + "setxattr", /* 382 */ + "lsetxattr", /* 383 */ + "fsetxattr", /* 384 */ + "getxattr", /* 385 */ + "lgetxattr", /* 386 */ + "fgetxattr", /* 387 */ + "listxattr", /* 388 */ + "llistxattr", /* 389 */ + "flistxattr", /* 390 */ + "removexattr", /* 391 */ + "lremovexattr", /* 392 */ + "fremovexattr", /* 393 */ + "futex", /* 394 */ + "sched_setaffinity", /* 395 */ + "sched_getaffinity", /* 396 */ + "tuxcall", /* 397 */ + "io_setup", /* 398 */ + "io_destroy", /* 399 */ + "io_getevents", /* 400 */ + "io_submit", /* 401 */ + "io_cancel", /* 402 */ + "SYS_403", /* 403 */ + "SYS_404", /* 404 */ + "exit_group", /* 405 */ + "lookup_dcookie", /* 406 */ + "epoll_create", /* 407 */ + "epoll_ctl", /* 408 */ + "epoll_wait", /* 409 */ + "remap_file_pages", /* 410 */ + "set_tid_address", /* 411 */ + "restart_syscall", /* 412 */ + "fadvise", /* 413 */ + "timer_create", /* 414 */ + "timer_settime", /* 415 */ + "timer_gettime", /* 416 */ + "timer_getoverrun", /* 417 */ + "timer_delete", /* 418 */ + "clock_settime", /* 419 */ + "clock_gettime", /* 420 */ + "clock_getres", /* 421 */ + "clock_nanosleep", /* 422 */ + "semtimedop", /* 423 */ + "tgkill", /* 424 */ + "stat64", /* 425 */ + "lstat64", /* 426 */ + "fstat64", /* 427 */ + "vserver", /* 428 */ + "mbind", /* 429 */ + "get_mempolicy", /* 430 */ + "set_mempolicy", /* 431 */ + "mq_open", /* 432 */ + "mq_unlink", /* 433 */ + "mq_timedsend", /* 434 */ + "mq_timedreceive", /* 435 */ + "mq_notify", /* 436 */ + "mq_getsetattr", /* 437 */ + "waitid" /* 438 */ diff --git a/sysdeps/linux-gnu/alpha/trace.c b/sysdeps/linux-gnu/alpha/trace.c new file mode 100644 index 0000000..e4d4063 --- /dev/null +++ b/sysdeps/linux-gnu/alpha/trace.c @@ -0,0 +1,75 @@ +#include "config.h" + +#include +#include +#include +#include +#include + +#include "common.h" +#include "debug.h" + +#if (!defined(PTRACE_PEEKUSER) && defined(PTRACE_PEEKUSR)) +# define PTRACE_PEEKUSER PTRACE_PEEKUSR +#endif + +#if (!defined(PTRACE_POKEUSER) && defined(PTRACE_POKEUSR)) +# define PTRACE_POKEUSER PTRACE_POKEUSR +#endif + +void +get_arch_dep(Process *proc) { +} + +/* Returns 1 if syscall, 2 if sysret, 0 otherwise. + */ +int +syscall_p(Process *proc, int status, int *sysnum) { + if (WIFSTOPPED(status) + && WSTOPSIG(status) == (SIGTRAP | proc->tracesysgood)) { + char *ip = get_instruction_pointer(proc) - 4; + long x = ptrace(PTRACE_PEEKTEXT, proc->pid, ip, 0); + debug(2, "instr: %016lx", x); + if ((x & 0xffffffff) != 0x00000083) + return 0; + *sysnum = + ptrace(PTRACE_PEEKUSER, proc->pid, 0 /* REG_R0 */ , 0); + if (proc->callstack_depth > 0 && + proc->callstack[proc->callstack_depth - 1].is_syscall && + proc->callstack[proc->callstack_depth - 1].c_un.syscall == *sysnum) { + return 2; + } + if (*sysnum >= 0 && *sysnum < 500) { + return 1; + } + } + return 0; +} + +long +gimme_arg(enum tof type, Process *proc, int arg_num, arg_type_info *info) { + if (arg_num == -1) { /* return value */ + return ptrace(PTRACE_PEEKUSER, proc->pid, 0 /* REG_R0 */ , 0); + } + + if (type == LT_TOF_FUNCTION || type == LT_TOF_FUNCTIONR) { + if (arg_num <= 5) + return ptrace(PTRACE_PEEKUSER, proc->pid, + arg_num + 16 /* REG_A0 */ , 0); + else + return ptrace(PTRACE_PEEKTEXT, proc->pid, + proc->stack_pointer + 8 * (arg_num - 6), + 0); + } else if (type == LT_TOF_SYSCALL || type == LT_TOF_SYSCALLR) { + return ptrace(PTRACE_PEEKUSER, proc->pid, + arg_num + 16 /* REG_A0 */ , 0); + } else { + fprintf(stderr, "gimme_arg called with wrong arguments\n"); + exit(1); + } + return 0; +} + +void +save_register_args(enum tof type, Process *proc) { +} diff --git a/sysdeps/linux-gnu/arch_mksyscallent b/sysdeps/linux-gnu/arch_mksyscallent new file mode 100644 index 0000000..853d62d --- /dev/null +++ b/sysdeps/linux-gnu/arch_mksyscallent @@ -0,0 +1,42 @@ +#!/usr/bin/awk -f + +# hack expression to generate arch_syscallent.h from +# It reads from stdin and writes to stdout +# Currently (linux-2.6.16), it works OK on arm +# It is untested in other architectures + +BEGIN { + max=0; + FS="[ \t\n()+]+"; +} + +{ +# printf("/%s/%s/%s/%s/\n", $1, $2, $3, $4); + if (($1 ~ /^#define$/) && ($2 ~ /^__[A-Z]+_NR_/)) { + sub(/^__[A-Z]+_NR_/,"",$2); + if (($3>=0) && ($3<=1000)) { + SYSCALL[$3]=$2; + if ($3 > max) { + max=$3; + } + } else if (($3 ~ /^__[A-Z]+_NR_BASE$/) && ($4>=0) && ($4<=1000)) { + SYSCALL[$4]=$2; + if ($4 > max) { + max=$4; + } + } + } +} + +END { + for(i=0; i<=max; i++) { + if (!SYSCALL[i]) { + SYSCALL[i] = i; + } + pad = 32 - length(SYSCALL[i]); + if (pad<1) { + pad=1; + } + printf("\t\"%s\",%*s/* %d */\n", SYSCALL[i], pad, "", i); + } +} diff --git a/sysdeps/linux-gnu/arm/Makefile b/sysdeps/linux-gnu/arm/Makefile new file mode 100644 index 0000000..f55ba48 --- /dev/null +++ b/sysdeps/linux-gnu/arm/Makefile @@ -0,0 +1,10 @@ +OBJ = trace.o regs.o plt.o breakpoint.o + +all: arch.o + +arch.o: $(OBJ) arch.h + $(CC) -nostdlib -r -o arch.o $(OBJ) + +clean: + $(RM) $(OBJ) arch.o + diff --git a/sysdeps/linux-gnu/arm/arch.h b/sysdeps/linux-gnu/arm/arch.h new file mode 100644 index 0000000..8f2dfb3 --- /dev/null +++ b/sysdeps/linux-gnu/arm/arch.h @@ -0,0 +1,11 @@ +#define ARCH_HAVE_ENABLE_BREAKPOINT 1 +#define ARCH_HAVE_DISABLE_BREAKPOINT 1 + +#define BREAKPOINT_VALUE { 0xf0, 0x01, 0xf0, 0xe7 } +#define BREAKPOINT_LENGTH 4 +#define THUMB_BREAKPOINT_VALUE { 0x01, 0xde } +#define THUMB_BREAKPOINT_LENGTH 2 +#define DECR_PC_AFTER_BREAK 0 + +#define LT_ELFCLASS ELFCLASS32 +#define LT_ELF_MACHINE EM_ARM diff --git a/sysdeps/linux-gnu/arm/arch_syscallent.h b/sysdeps/linux-gnu/arm/arch_syscallent.h new file mode 100644 index 0000000..ce1e844 --- /dev/null +++ b/sysdeps/linux-gnu/arm/arch_syscallent.h @@ -0,0 +1,6 @@ + "0", /* 0 */ + "breakpoint", /* 1 */ + "cacheflush", /* 2 */ + "usr26", /* 3 */ + "usr32", /* 4 */ + "set_tls", /* 5 */ diff --git a/sysdeps/linux-gnu/arm/breakpoint.c b/sysdeps/linux-gnu/arm/breakpoint.c new file mode 100644 index 0000000..4c20260 --- /dev/null +++ b/sysdeps/linux-gnu/arm/breakpoint.c @@ -0,0 +1,77 @@ +/* + * This file is part of ltrace. + * + * Copyright (C) 2007 by Instituto Nokia de Tecnologia (INdT) + * + * Author: Anderson Lizardo + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + * Modified from sysdeps/linux-gnu/breakpoint.c and added ARM Thumb support. + */ + +#include +#include "config.h" +#include "arch.h" +#include "options.h" +#include "output.h" +#include "debug.h" + +void +arch_enable_breakpoint(pid_t pid, Breakpoint *sbp) { + unsigned int i, j; + const unsigned char break_insn[] = BREAKPOINT_VALUE; + const unsigned char thumb_break_insn[] = THUMB_BREAKPOINT_VALUE; + + debug(1, "arch_enable_breakpoint(%d,%p)", pid, sbp->addr); + + for (i = 0; i < 1 + ((BREAKPOINT_LENGTH - 1) / sizeof(long)); i++) { + long a = ptrace(PTRACE_PEEKTEXT, pid, sbp->addr + i * sizeof(long), 0); + unsigned char *bytes = (unsigned char *)&a; + + debug(2, "current = 0x%lx, orig_value = 0x%lx, thumb_mode = %d", a, *(long *)&sbp->orig_value, sbp->thumb_mode); + for (j = 0; j < sizeof(long) && i * sizeof(long) + j < BREAKPOINT_LENGTH; j++) { + + sbp->orig_value[i * sizeof(long) + j] = bytes[j]; + if (!sbp->thumb_mode) { + bytes[j] = break_insn[i * sizeof(long) + j]; + } + else if (j < THUMB_BREAKPOINT_LENGTH) { + bytes[j] = thumb_break_insn[i * sizeof(long) + j]; + } + } + ptrace(PTRACE_POKETEXT, pid, sbp->addr + i * sizeof(long), a); + } +} + +void +arch_disable_breakpoint(pid_t pid, const Breakpoint *sbp) { + unsigned int i, j; + const unsigned char break_insn[] = BREAKPOINT_VALUE; + const unsigned char thumb_break_insn[] = THUMB_BREAKPOINT_VALUE; + + debug(1, "arch_disable_breakpoint(%d,%p)", pid, sbp->addr); + + for (i = 0; i < 1 + ((BREAKPOINT_LENGTH - 1) / sizeof(long)); i++) { + long a = ptrace(PTRACE_PEEKTEXT, pid, sbp->addr + i * sizeof(long), 0); + unsigned char *bytes = (unsigned char *)&a; + + debug(2, "current = 0x%lx, orig_value = 0x%lx, thumb_mode = %d", a, *(long *)&sbp->orig_value, sbp->thumb_mode); + for (j = 0; j < sizeof(long) && i * sizeof(long) + j < BREAKPOINT_LENGTH; j++) { + bytes[j] = sbp->orig_value[i * sizeof(long) + j]; + } + ptrace(PTRACE_POKETEXT, pid, sbp->addr + i * sizeof(long), a); + } +} diff --git a/sysdeps/linux-gnu/arm/plt.c b/sysdeps/linux-gnu/arm/plt.c new file mode 100644 index 0000000..bd92a63 --- /dev/null +++ b/sysdeps/linux-gnu/arm/plt.c @@ -0,0 +1,12 @@ +#include +#include "common.h" + +GElf_Addr +arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela * rela) { + return lte->plt_addr + 20 + ndx * 12; +} + +void * +sym2addr(Process *proc, struct library_symbol *sym) { + return sym->enter_addr; +} diff --git a/sysdeps/linux-gnu/arm/ptrace.h b/sysdeps/linux-gnu/arm/ptrace.h new file mode 100644 index 0000000..52215bc --- /dev/null +++ b/sysdeps/linux-gnu/arm/ptrace.h @@ -0,0 +1,9 @@ +#include +#include + +typedef struct { + int valid; + struct pt_regs regs; + long func_arg[5]; + long sysc_arg[5]; +} proc_archdep; diff --git a/sysdeps/linux-gnu/arm/regs.c b/sysdeps/linux-gnu/arm/regs.c new file mode 100644 index 0000000..2488b0a --- /dev/null +++ b/sysdeps/linux-gnu/arm/regs.c @@ -0,0 +1,51 @@ +#include "config.h" + +#include +#include +#include + +#include "common.h" + +#if (!defined(PTRACE_PEEKUSER) && defined(PTRACE_PEEKUSR)) +# define PTRACE_PEEKUSER PTRACE_PEEKUSR +#endif + +#if (!defined(PTRACE_POKEUSER) && defined(PTRACE_POKEUSR)) +# define PTRACE_POKEUSER PTRACE_POKEUSR +#endif + +#define off_pc 60 +#define off_lr 56 +#define off_sp 52 + +void * +get_instruction_pointer(Process *proc) { + return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, off_pc, 0); +} + +void +set_instruction_pointer(Process *proc, void *addr) { + ptrace(PTRACE_POKEUSER, proc->pid, off_pc, addr); +} + +void * +get_stack_pointer(Process *proc) { + return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, off_sp, 0); +} + +/* really, this is given the *stack_pointer expecting + * a CISC architecture; in our case, we don't need that */ +void * +get_return_addr(Process *proc, void *stack_pointer) { + long addr = ptrace(PTRACE_PEEKUSER, proc->pid, off_lr, 0); + + proc->thumb_mode = addr & 1; + if (proc->thumb_mode) + addr &= ~1; + return (void *)addr; +} + +void +set_return_addr(Process *proc, void *addr) { + ptrace(PTRACE_POKEUSER, proc->pid, off_lr, addr); +} diff --git a/sysdeps/linux-gnu/arm/signalent.h b/sysdeps/linux-gnu/arm/signalent.h new file mode 100644 index 0000000..0afb004 --- /dev/null +++ b/sysdeps/linux-gnu/arm/signalent.h @@ -0,0 +1,33 @@ + "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 */ + "SIGSYS", /* 31 */ + "SIGSWI", /* 32 */ diff --git a/sysdeps/linux-gnu/arm/syscallent.h b/sysdeps/linux-gnu/arm/syscallent.h new file mode 100644 index 0000000..4113234 --- /dev/null +++ b/sysdeps/linux-gnu/arm/syscallent.h @@ -0,0 +1,322 @@ + "restart_syscall", /* 0 */ + "exit", /* 1 */ + "fork", /* 2 */ + "read", /* 3 */ + "write", /* 4 */ + "open", /* 5 */ + "close", /* 6 */ + "7", /* 7 */ + "creat", /* 8 */ + "link", /* 9 */ + "unlink", /* 10 */ + "execve", /* 11 */ + "chdir", /* 12 */ + "time", /* 13 */ + "mknod", /* 14 */ + "chmod", /* 15 */ + "lchown", /* 16 */ + "17", /* 17 */ + "18", /* 18 */ + "lseek", /* 19 */ + "getpid", /* 20 */ + "mount", /* 21 */ + "umount", /* 22 */ + "setuid", /* 23 */ + "getuid", /* 24 */ + "stime", /* 25 */ + "ptrace", /* 26 */ + "alarm", /* 27 */ + "28", /* 28 */ + "pause", /* 29 */ + "utime", /* 30 */ + "31", /* 31 */ + "32", /* 32 */ + "access", /* 33 */ + "nice", /* 34 */ + "35", /* 35 */ + "sync", /* 36 */ + "kill", /* 37 */ + "rename", /* 38 */ + "mkdir", /* 39 */ + "rmdir", /* 40 */ + "dup", /* 41 */ + "pipe", /* 42 */ + "times", /* 43 */ + "44", /* 44 */ + "brk", /* 45 */ + "setgid", /* 46 */ + "getgid", /* 47 */ + "48", /* 48 */ + "geteuid", /* 49 */ + "getegid", /* 50 */ + "acct", /* 51 */ + "umount2", /* 52 */ + "53", /* 53 */ + "ioctl", /* 54 */ + "fcntl", /* 55 */ + "56", /* 56 */ + "setpgid", /* 57 */ + "58", /* 58 */ + "59", /* 59 */ + "umask", /* 60 */ + "chroot", /* 61 */ + "ustat", /* 62 */ + "dup2", /* 63 */ + "getppid", /* 64 */ + "getpgrp", /* 65 */ + "setsid", /* 66 */ + "sigaction", /* 67 */ + "68", /* 68 */ + "69", /* 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 */ + "84", /* 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 */ + "98", /* 98 */ + "statfs", /* 99 */ + "fstatfs", /* 100 */ + "101", /* 101 */ + "socketcall", /* 102 */ + "syslog", /* 103 */ + "setitimer", /* 104 */ + "getitimer", /* 105 */ + "stat", /* 106 */ + "lstat", /* 107 */ + "fstat", /* 108 */ + "109", /* 109 */ + "110", /* 110 */ + "vhangup", /* 111 */ + "112", /* 112 */ + "syscall", /* 113 */ + "wait4", /* 114 */ + "swapoff", /* 115 */ + "sysinfo", /* 116 */ + "ipc", /* 117 */ + "fsync", /* 118 */ + "sigreturn", /* 119 */ + "clone", /* 120 */ + "setdomainname", /* 121 */ + "uname", /* 122 */ + "123", /* 123 */ + "adjtimex", /* 124 */ + "mprotect", /* 125 */ + "sigprocmask", /* 126 */ + "127", /* 127 */ + "init_module", /* 128 */ + "delete_module", /* 129 */ + "130", /* 130 */ + "quotactl", /* 131 */ + "getpgid", /* 132 */ + "fchdir", /* 133 */ + "bdflush", /* 134 */ + "sysfs", /* 135 */ + "personality", /* 136 */ + "137", /* 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 */ + "setresuid", /* 164 */ + "getresuid", /* 165 */ + "166", /* 166 */ + "167", /* 167 */ + "poll", /* 168 */ + "nfsservctl", /* 169 */ + "setresgid", /* 170 */ + "getresgid", /* 171 */ + "prctl", /* 172 */ + "rt_sigreturn", /* 173 */ + "rt_sigaction", /* 174 */ + "rt_sigprocmask", /* 175 */ + "rt_sigpending", /* 176 */ + "rt_sigtimedwait", /* 177 */ + "rt_sigqueueinfo", /* 178 */ + "rt_sigsuspend", /* 179 */ + "pread64", /* 180 */ + "pwrite64", /* 181 */ + "chown", /* 182 */ + "getcwd", /* 183 */ + "capget", /* 184 */ + "capset", /* 185 */ + "sigaltstack", /* 186 */ + "sendfile", /* 187 */ + "188", /* 188 */ + "189", /* 189 */ + "vfork", /* 190 */ + "ugetrlimit", /* 191 */ + "mmap2", /* 192 */ + "truncate64", /* 193 */ + "ftruncate64", /* 194 */ + "stat64", /* 195 */ + "lstat64", /* 196 */ + "fstat64", /* 197 */ + "lchown32", /* 198 */ + "getuid32", /* 199 */ + "getgid32", /* 200 */ + "geteuid32", /* 201 */ + "getegid32", /* 202 */ + "setreuid32", /* 203 */ + "setregid32", /* 204 */ + "getgroups32", /* 205 */ + "setgroups32", /* 206 */ + "fchown32", /* 207 */ + "setresuid32", /* 208 */ + "getresuid32", /* 209 */ + "setresgid32", /* 210 */ + "getresgid32", /* 211 */ + "chown32", /* 212 */ + "setuid32", /* 213 */ + "setgid32", /* 214 */ + "setfsuid32", /* 215 */ + "setfsgid32", /* 216 */ + "getdents64", /* 217 */ + "pivot_root", /* 218 */ + "mincore", /* 219 */ + "madvise", /* 220 */ + "fcntl64", /* 221 */ + "222", /* 222 */ + "223", /* 223 */ + "gettid", /* 224 */ + "readahead", /* 225 */ + "setxattr", /* 226 */ + "lsetxattr", /* 227 */ + "fsetxattr", /* 228 */ + "getxattr", /* 229 */ + "lgetxattr", /* 230 */ + "fgetxattr", /* 231 */ + "listxattr", /* 232 */ + "llistxattr", /* 233 */ + "flistxattr", /* 234 */ + "removexattr", /* 235 */ + "lremovexattr", /* 236 */ + "fremovexattr", /* 237 */ + "tkill", /* 238 */ + "sendfile64", /* 239 */ + "futex", /* 240 */ + "sched_setaffinity", /* 241 */ + "sched_getaffinity", /* 242 */ + "io_setup", /* 243 */ + "io_destroy", /* 244 */ + "io_getevents", /* 245 */ + "io_submit", /* 246 */ + "io_cancel", /* 247 */ + "exit_group", /* 248 */ + "lookup_dcookie", /* 249 */ + "epoll_create", /* 250 */ + "epoll_ctl", /* 251 */ + "epoll_wait", /* 252 */ + "remap_file_pages", /* 253 */ + "254", /* 254 */ + "255", /* 255 */ + "set_tid_address", /* 256 */ + "timer_create", /* 257 */ + "timer_settime", /* 258 */ + "timer_gettime", /* 259 */ + "timer_getoverrun", /* 260 */ + "timer_delete", /* 261 */ + "clock_settime", /* 262 */ + "clock_gettime", /* 263 */ + "clock_getres", /* 264 */ + "clock_nanosleep", /* 265 */ + "statfs64", /* 266 */ + "fstatfs64", /* 267 */ + "tgkill", /* 268 */ + "utimes", /* 269 */ + "arm_fadvise64_64", /* 270 */ + "pciconfig_iobase", /* 271 */ + "pciconfig_read", /* 272 */ + "pciconfig_write", /* 273 */ + "mq_open", /* 274 */ + "mq_unlink", /* 275 */ + "mq_timedsend", /* 276 */ + "mq_timedreceive", /* 277 */ + "mq_notify", /* 278 */ + "mq_getsetattr", /* 279 */ + "waitid", /* 280 */ + "socket", /* 281 */ + "bind", /* 282 */ + "connect", /* 283 */ + "listen", /* 284 */ + "accept", /* 285 */ + "getsockname", /* 286 */ + "getpeername", /* 287 */ + "socketpair", /* 288 */ + "send", /* 289 */ + "sendto", /* 290 */ + "recv", /* 291 */ + "recvfrom", /* 292 */ + "shutdown", /* 293 */ + "setsockopt", /* 294 */ + "getsockopt", /* 295 */ + "sendmsg", /* 296 */ + "recvmsg", /* 297 */ + "semop", /* 298 */ + "semget", /* 299 */ + "semctl", /* 300 */ + "msgsnd", /* 301 */ + "msgrcv", /* 302 */ + "msgget", /* 303 */ + "msgctl", /* 304 */ + "shmat", /* 305 */ + "shmdt", /* 306 */ + "shmget", /* 307 */ + "shmctl", /* 308 */ + "add_key", /* 309 */ + "request_key", /* 310 */ + "keyctl", /* 311 */ + "semtimedop", /* 312 */ + "vserver", /* 313 */ + "ioprio_set", /* 314 */ + "ioprio_get", /* 315 */ + "inotify_init", /* 316 */ + "inotify_add_watch", /* 317 */ + "inotify_rm_watch", /* 318 */ + "mbind", /* 319 */ + "get_mempolicy", /* 320 */ + "set_mempolicy", /* 321 */ diff --git a/sysdeps/linux-gnu/arm/trace.c b/sysdeps/linux-gnu/arm/trace.c new file mode 100644 index 0000000..10f7cc4 --- /dev/null +++ b/sysdeps/linux-gnu/arm/trace.c @@ -0,0 +1,131 @@ +#include "config.h" + +#include +#include +#include +#include +#include +#include + +#include "common.h" +#include "output.h" +#include "ptrace.h" + +#if (!defined(PTRACE_PEEKUSER) && defined(PTRACE_PEEKUSR)) +# define PTRACE_PEEKUSER PTRACE_PEEKUSR +#endif + +#if (!defined(PTRACE_POKEUSER) && defined(PTRACE_POKEUSR)) +# define PTRACE_POKEUSER PTRACE_POKEUSR +#endif + +#define off_r0 0 +#define off_r7 28 +#define off_ip 48 +#define off_pc 60 + +void +get_arch_dep(Process *proc) { + proc_archdep *a; + + if (!proc->arch_ptr) + proc->arch_ptr = (void *)malloc(sizeof(proc_archdep)); + a = (proc_archdep *) (proc->arch_ptr); + a->valid = (ptrace(PTRACE_GETREGS, proc->pid, 0, &a->regs) >= 0); +} + +/* Returns 0 if not a syscall, + * 1 if syscall entry, 2 if syscall exit, + * 3 if arch-specific syscall entry, 4 if arch-specific syscall exit, + * -1 on error. + */ +int +syscall_p(Process *proc, int status, int *sysnum) { + if (WIFSTOPPED(status) + && WSTOPSIG(status) == (SIGTRAP | proc->tracesysgood)) { + /* get the user's pc (plus 8) */ + int pc = ptrace(PTRACE_PEEKUSER, proc->pid, off_pc, 0); + /* fetch the SWI instruction */ + int insn = ptrace(PTRACE_PEEKTEXT, proc->pid, pc - 4, 0); + int ip = ptrace(PTRACE_PEEKUSER, proc->pid, off_ip, 0); + + if (insn == 0xef000000 || insn == 0x0f000000) { + /* EABI syscall */ + *sysnum = ptrace(PTRACE_PEEKUSER, proc->pid, off_r7, 0); + } else if ((insn & 0xfff00000) == 0xef900000) { + /* old ABI syscall */ + *sysnum = insn & 0xfffff; + } else { + /* TODO: handle swi variations */ + /* one possible reason for getting in here is that we + * are coming from a signal handler, so the current + * PC does not point to the instruction just after the + * "swi" one. */ + output_line(proc, "unexpected instruction 0x%x at %p", insn, pc - 4); + return -1; + } + if ((*sysnum & 0xf0000) == 0xf0000) { + /* arch-specific syscall */ + *sysnum &= ~0xf0000; + return ip ? 4 : 3; + } + /* ARM syscall convention: on syscall entry, ip is zero; + * on syscall exit, ip is non-zero */ + return ip ? 2 : 1; + } + return 0; +} + +long +gimme_arg(enum tof type, Process *proc, int arg_num, arg_type_info *info) { + proc_archdep *a = (proc_archdep *) proc->arch_ptr; + + if (arg_num == -1) { /* return value */ + return ptrace(PTRACE_PEEKUSER, proc->pid, off_r0, 0); + } + + /* deal with the ARM calling conventions */ + if (type == LT_TOF_FUNCTION || type == LT_TOF_FUNCTIONR) { + if (arg_num < 4) { + if (a->valid && type == LT_TOF_FUNCTION) + return a->regs.uregs[arg_num]; + if (a->valid && type == LT_TOF_FUNCTIONR) + return a->func_arg[arg_num]; + return ptrace(PTRACE_PEEKUSER, proc->pid, 4 * arg_num, + 0); + } else { + return ptrace(PTRACE_PEEKDATA, proc->pid, + proc->stack_pointer + 4 * (arg_num - 4), + 0); + } + } else if (type == LT_TOF_SYSCALL || type == LT_TOF_SYSCALLR) { + if (arg_num < 5) { + if (a->valid && type == LT_TOF_SYSCALL) + return a->regs.uregs[arg_num]; + if (a->valid && type == LT_TOF_SYSCALLR) + return a->sysc_arg[arg_num]; + return ptrace(PTRACE_PEEKUSER, proc->pid, 4 * arg_num, + 0); + } else { + return ptrace(PTRACE_PEEKDATA, proc->pid, + proc->stack_pointer + 4 * (arg_num - 5), + 0); + } + } else { + fprintf(stderr, "gimme_arg called with wrong arguments\n"); + exit(1); + } + + return 0; +} + +void +save_register_args(enum tof type, Process *proc) { + proc_archdep *a = (proc_archdep *) proc->arch_ptr; + if (a->valid) { + if (type == LT_TOF_FUNCTION) + memcpy(a->func_arg, a->regs.uregs, sizeof(a->func_arg)); + else + memcpy(a->sysc_arg, a->regs.uregs, sizeof(a->sysc_arg)); + } +} diff --git a/sysdeps/linux-gnu/breakpoint.c b/sysdeps/linux-gnu/breakpoint.c new file mode 100644 index 0000000..5ca131a --- /dev/null +++ b/sysdeps/linux-gnu/breakpoint.c @@ -0,0 +1,86 @@ +#include "config.h" + +#include +#include + +#include "common.h" +#include "arch.h" + +static unsigned char break_insn[] = BREAKPOINT_VALUE; + +#ifdef ARCH_HAVE_ENABLE_BREAKPOINT +extern void arch_enable_breakpoint(pid_t, Breakpoint *); +void +enable_breakpoint(pid_t pid, Breakpoint *sbp) { + if (sbp->libsym) { + debug(DEBUG_PROCESS, "enable_breakpoint: pid=%d, addr=%p, symbol=%s", pid, sbp->addr, sbp->libsym->name); + } else { + debug(DEBUG_PROCESS, "enable_breakpoint: pid=%d, addr=%p", pid, sbp->addr); + } + arch_enable_breakpoint(pid, sbp); +} +#else +void +enable_breakpoint(pid_t pid, Breakpoint *sbp) { + unsigned int i, j; + + if (sbp->libsym) { + debug(DEBUG_PROCESS, "enable_breakpoint: pid=%d, addr=%p, symbol=%s", pid, sbp->addr, sbp->libsym->name); + } else { + debug(DEBUG_PROCESS, "enable_breakpoint: pid=%d, addr=%p", pid, sbp->addr); + } + + for (i = 0; i < 1 + ((BREAKPOINT_LENGTH - 1) / sizeof(long)); i++) { + long a = + ptrace(PTRACE_PEEKTEXT, pid, sbp->addr + i * sizeof(long), + 0); + for (j = 0; + j < sizeof(long) + && i * sizeof(long) + j < BREAKPOINT_LENGTH; j++) { + unsigned char *bytes = (unsigned char *)&a; + + sbp->orig_value[i * sizeof(long) + j] = bytes[j]; + bytes[j] = break_insn[i * sizeof(long) + j]; + } + ptrace(PTRACE_POKETEXT, pid, sbp->addr + i * sizeof(long), a); + } +} +#endif /* ARCH_HAVE_ENABLE_BREAKPOINT */ + +#ifdef ARCH_HAVE_DISABLE_BREAKPOINT +extern void arch_disable_breakpoint(pid_t, const Breakpoint *sbp); +void +disable_breakpoint(pid_t pid, const Breakpoint *sbp) { + if (sbp->libsym) { + debug(DEBUG_PROCESS, "disable_breakpoint: pid=%d, addr=%p, symbol=%s", pid, sbp->addr, sbp->libsym->name); + } else { + debug(DEBUG_PROCESS, "disable_breakpoint: pid=%d, addr=%p", pid, sbp->addr); + } + arch_disable_breakpoint(pid, sbp); +} +#else +void +disable_breakpoint(pid_t pid, const Breakpoint *sbp) { + unsigned int i, j; + + if (sbp->libsym) { + debug(DEBUG_PROCESS, "disable_breakpoint: pid=%d, addr=%p, symbol=%s", pid, sbp->addr, sbp->libsym->name); + } else { + debug(DEBUG_PROCESS, "disable_breakpoint: pid=%d, addr=%p", pid, sbp->addr); + } + + for (i = 0; i < 1 + ((BREAKPOINT_LENGTH - 1) / sizeof(long)); i++) { + long a = + ptrace(PTRACE_PEEKTEXT, pid, sbp->addr + i * sizeof(long), + 0); + for (j = 0; + j < sizeof(long) + && i * sizeof(long) + j < BREAKPOINT_LENGTH; j++) { + unsigned char *bytes = (unsigned char *)&a; + + bytes[j] = sbp->orig_value[i * sizeof(long) + j]; + } + ptrace(PTRACE_POKETEXT, pid, sbp->addr + i * sizeof(long), a); + } +} +#endif /* ARCH_HAVE_DISABLE_BREAKPOINT */ diff --git a/sysdeps/linux-gnu/events.c b/sysdeps/linux-gnu/events.c new file mode 100644 index 0000000..a1e2a14 --- /dev/null +++ b/sysdeps/linux-gnu/events.c @@ -0,0 +1,161 @@ +#include "config.h" + +#define _GNU_SOURCE 1 +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" + +static Event event; + +Event * +next_event(void) { + pid_t pid; + int status; + int tmp; + int stop_signal; + + debug(DEBUG_FUNCTION, "next_event()"); + if (!list_of_processes) { + debug(DEBUG_EVENT, "event: No more traced programs: exiting"); + exit(0); + } + pid = waitpid(-1, &status, __WALL); + if (pid == -1) { + if (errno == ECHILD) { + debug(DEBUG_EVENT, "event: No more traced programs: exiting"); + exit(0); + } else if (errno == EINTR) { + debug(DEBUG_EVENT, "event: none (wait received EINTR?)"); + event.type = EVENT_NONE; + return &event; + } + perror("wait"); + exit(1); + } + event.proc = pid2proc(pid); + if (!event.proc || event.proc->state == STATE_BEING_CREATED) { + event.type = EVENT_NEW; + event.e_un.newpid = pid; + debug(DEBUG_EVENT, "event: NEW: pid=%d", pid); + return &event; + } + get_arch_dep(event.proc); + event.proc->instruction_pointer = NULL; + debug(3, "event from pid %u", pid); + if (event.proc->breakpoints_enabled == -1) { + enable_all_breakpoints(event.proc); + event.type = EVENT_NONE; + trace_set_options(event.proc, event.proc->pid); + continue_process(event.proc->pid); + debug(DEBUG_EVENT, "event: NONE: pid=%d (enabling breakpoints)", pid); + return &event; + } + if (opt_i) { + event.proc->instruction_pointer = + get_instruction_pointer(event.proc); + } + switch (syscall_p(event.proc, status, &tmp)) { + case 1: + event.type = EVENT_SYSCALL; + event.e_un.sysnum = tmp; + debug(DEBUG_EVENT, "event: SYSCALL: pid=%d, sysnum=%d", pid, tmp); + return &event; + case 2: + event.type = EVENT_SYSRET; + event.e_un.sysnum = tmp; + debug(DEBUG_EVENT, "event: SYSRET: pid=%d, sysnum=%d", pid, tmp); + return &event; + case 3: + event.type = EVENT_ARCH_SYSCALL; + event.e_un.sysnum = tmp; + debug(DEBUG_EVENT, "event: ARCH_SYSCALL: pid=%d, sysnum=%d", pid, tmp); + return &event; + case 4: + event.type = EVENT_ARCH_SYSRET; + event.e_un.sysnum = tmp; + debug(DEBUG_EVENT, "event: ARCH_SYSRET: pid=%d, sysnum=%d", pid, tmp); + return &event; + case -1: + event.type = EVENT_NONE; + continue_process(event.proc->pid); + debug(DEBUG_EVENT, "event: NONE: pid=%d (syscall_p returned -1)", pid); + return &event; + } + if (WIFSTOPPED(status) && ((status>>16 == PTRACE_EVENT_FORK) || (status>>16 == PTRACE_EVENT_VFORK) || (status>>16 == PTRACE_EVENT_CLONE))) { + unsigned long data; + ptrace(PTRACE_GETEVENTMSG, pid, NULL, &data); + event.type = EVENT_CLONE; + event.e_un.newpid = data; + debug(DEBUG_EVENT, "event: CLONE: pid=%d, newpid=%d", pid, (int)data); + return &event; + } + if (WIFSTOPPED(status) && (status>>16 == PTRACE_EVENT_EXEC)) { + event.type = EVENT_EXEC; + debug(DEBUG_EVENT, "event: EXEC: pid=%d", pid); + return &event; + } + if (WIFEXITED(status)) { + event.type = EVENT_EXIT; + event.e_un.ret_val = WEXITSTATUS(status); + debug(DEBUG_EVENT, "event: EXIT: pid=%d, status=%d", pid, event.e_un.ret_val); + return &event; + } + if (WIFSIGNALED(status)) { + event.type = EVENT_EXIT_SIGNAL; + event.e_un.signum = WTERMSIG(status); + debug(DEBUG_EVENT, "event: EXIT_SIGNAL: pid=%d, signum=%d", pid, event.e_un.signum); + return &event; + } + if (!WIFSTOPPED(status)) { + /* should never happen */ + event.type = EVENT_NONE; + debug(DEBUG_EVENT, "event: NONE: pid=%d (wait error?)", pid); + return &event; + } + + stop_signal = WSTOPSIG(status); + + /* On some targets, breakpoints are signalled not using + SIGTRAP, but also with SIGILL, SIGSEGV or SIGEMT. Check + for these. (TODO: is this true?) */ + if (stop_signal == SIGSEGV + || stop_signal == SIGILL +#ifdef SIGEMT + || stop_signal == SIGEMT +#endif + ) { + if (!event.proc->instruction_pointer) { + event.proc->instruction_pointer = + get_instruction_pointer(event.proc); + } + + if (address2bpstruct(event.proc, event.proc->instruction_pointer)) + stop_signal = SIGTRAP; + } + + if (stop_signal != (SIGTRAP | event.proc->tracesysgood) + && stop_signal != SIGTRAP) { + event.type = EVENT_SIGNAL; + event.e_un.signum = stop_signal; + debug(DEBUG_EVENT, "event: SIGNAL: pid=%d, signum=%d", pid, stop_signal); + return &event; + } + + /* last case [by exhaustion] */ + event.type = EVENT_BREAKPOINT; + + if (!event.proc->instruction_pointer) { + event.proc->instruction_pointer = + get_instruction_pointer(event.proc); + } + event.e_un.brk_addr = + event.proc->instruction_pointer - DECR_PC_AFTER_BREAK; + debug(DEBUG_EVENT, "event: BREAKPOINT: pid=%d, addr=%p", pid, event.e_un.brk_addr); + return &event; +} diff --git a/sysdeps/linux-gnu/i386/Makefile b/sysdeps/linux-gnu/i386/Makefile new file mode 100644 index 0000000..60d7531 --- /dev/null +++ b/sysdeps/linux-gnu/i386/Makefile @@ -0,0 +1,10 @@ +OBJ = trace.o regs.o plt.o + +all: arch.o + +arch.o: $(OBJ) + $(CC) -nostdlib -r -o arch.o $(OBJ) + +clean: + $(RM) $(OBJ) arch.o + diff --git a/sysdeps/linux-gnu/i386/arch.h b/sysdeps/linux-gnu/i386/arch.h new file mode 100644 index 0000000..dc7383f --- /dev/null +++ b/sysdeps/linux-gnu/i386/arch.h @@ -0,0 +1,6 @@ +#define BREAKPOINT_VALUE {0xcc} +#define BREAKPOINT_LENGTH 1 +#define DECR_PC_AFTER_BREAK 1 + +#define LT_ELFCLASS ELFCLASS32 +#define LT_ELF_MACHINE EM_386 diff --git a/sysdeps/linux-gnu/i386/plt.c b/sysdeps/linux-gnu/i386/plt.c new file mode 100644 index 0000000..b53ff44 --- /dev/null +++ b/sysdeps/linux-gnu/i386/plt.c @@ -0,0 +1,12 @@ +#include +#include "common.h" + +GElf_Addr +arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela * rela) { + return lte->plt_addr + (ndx + 1) * 16; +} + +void * +sym2addr(Process *proc, struct library_symbol *sym) { + return sym->enter_addr; +} diff --git a/sysdeps/linux-gnu/i386/ptrace.h b/sysdeps/linux-gnu/i386/ptrace.h new file mode 100644 index 0000000..c3cbcb6 --- /dev/null +++ b/sysdeps/linux-gnu/i386/ptrace.h @@ -0,0 +1 @@ +#include diff --git a/sysdeps/linux-gnu/i386/regs.c b/sysdeps/linux-gnu/i386/regs.c new file mode 100644 index 0000000..6777f17 --- /dev/null +++ b/sysdeps/linux-gnu/i386/regs.c @@ -0,0 +1,40 @@ +#include "config.h" + +#include +#include +#include + +#include "common.h" + +#if (!defined(PTRACE_PEEKUSER) && defined(PTRACE_PEEKUSR)) +# define PTRACE_PEEKUSER PTRACE_PEEKUSR +#endif + +#if (!defined(PTRACE_POKEUSER) && defined(PTRACE_POKEUSR)) +# define PTRACE_POKEUSER PTRACE_POKEUSR +#endif + +void * +get_instruction_pointer(Process *proc) { + return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, 4 * EIP, 0); +} + +void +set_instruction_pointer(Process *proc, void *addr) { + ptrace(PTRACE_POKEUSER, proc->pid, 4 * EIP, (long)addr); +} + +void * +get_stack_pointer(Process *proc) { + return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, 4 * UESP, 0); +} + +void * +get_return_addr(Process *proc, void *stack_pointer) { + return (void *)ptrace(PTRACE_PEEKTEXT, proc->pid, stack_pointer, 0); +} + +void +set_return_addr(Process *proc, void *addr) { + ptrace(PTRACE_POKETEXT, proc->pid, proc->stack_pointer, (long)addr); +} diff --git a/sysdeps/linux-gnu/i386/signalent.h b/sysdeps/linux-gnu/i386/signalent.h new file mode 100644 index 0000000..5395f82 --- /dev/null +++ b/sysdeps/linux-gnu/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 */ + "SIGSYS", /* 31 */ diff --git a/sysdeps/linux-gnu/i386/syscallent.h b/sysdeps/linux-gnu/i386/syscallent.h new file mode 100644 index 0000000..8f4c887 --- /dev/null +++ b/sysdeps/linux-gnu/i386/syscallent.h @@ -0,0 +1,317 @@ + "restart_syscall", /* 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 */ + "lchown", /* 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 */ + "umount2", /* 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 */ + "vm86old", /* 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 */ + "setresuid", /* 164 */ + "getresuid", /* 165 */ + "vm86", /* 166 */ + "query_module", /* 167 */ + "poll", /* 168 */ + "nfsservctl", /* 169 */ + "setresgid", /* 170 */ + "getresgid", /* 171 */ + "prctl", /* 172 */ + "rt_sigreturn", /* 173 */ + "rt_sigaction", /* 174 */ + "rt_sigprocmask", /* 175 */ + "rt_sigpending", /* 176 */ + "rt_sigtimedwait", /* 177 */ + "rt_sigqueueinfo", /* 178 */ + "rt_sigsuspend", /* 179 */ + "pread64", /* 180 */ + "pwrite64", /* 181 */ + "chown", /* 182 */ + "getcwd", /* 183 */ + "capget", /* 184 */ + "capset", /* 185 */ + "sigaltstack", /* 186 */ + "sendfile", /* 187 */ + "getpmsg", /* 188 */ + "putpmsg", /* 189 */ + "vfork", /* 190 */ + "ugetrlimit", /* 191 */ + "mmap2", /* 192 */ + "truncate64", /* 193 */ + "ftruncate64", /* 194 */ + "stat64", /* 195 */ + "lstat64", /* 196 */ + "fstat64", /* 197 */ + "lchown32", /* 198 */ + "getuid32", /* 199 */ + "getgid32", /* 200 */ + "geteuid32", /* 201 */ + "getegid32", /* 202 */ + "setreuid32", /* 203 */ + "setregid32", /* 204 */ + "getgroups32", /* 205 */ + "setgroups32", /* 206 */ + "fchown32", /* 207 */ + "setresuid32", /* 208 */ + "getresuid32", /* 209 */ + "setresgid32", /* 210 */ + "getresgid32", /* 211 */ + "chown32", /* 212 */ + "setuid32", /* 213 */ + "setgid32", /* 214 */ + "setfsuid32", /* 215 */ + "setfsgid32", /* 216 */ + "pivot_root", /* 217 */ + "mincore", /* 218 */ + "madvise1", /* 219 */ + "getdents64", /* 220 */ + "fcntl64", /* 221 */ + "222", /* 222 */ + "223", /* 223 */ + "gettid", /* 224 */ + "readahead", /* 225 */ + "setxattr", /* 226 */ + "lsetxattr", /* 227 */ + "fsetxattr", /* 228 */ + "getxattr", /* 229 */ + "lgetxattr", /* 230 */ + "fgetxattr", /* 231 */ + "listxattr", /* 232 */ + "llistxattr", /* 233 */ + "flistxattr", /* 234 */ + "removexattr", /* 235 */ + "lremovexattr", /* 236 */ + "fremovexattr", /* 237 */ + "tkill", /* 238 */ + "sendfile64", /* 239 */ + "futex", /* 240 */ + "sched_setaffinity", /* 241 */ + "sched_getaffinity", /* 242 */ + "set_thread_area", /* 243 */ + "get_thread_area", /* 244 */ + "io_setup", /* 245 */ + "io_destroy", /* 246 */ + "io_getevents", /* 247 */ + "io_submit", /* 248 */ + "io_cancel", /* 249 */ + "fadvise64", /* 250 */ + "251", /* 251 */ + "exit_group", /* 252 */ + "lookup_dcookie", /* 253 */ + "epoll_create", /* 254 */ + "epoll_ctl", /* 255 */ + "epoll_wait", /* 256 */ + "remap_file_pages", /* 257 */ + "set_tid_address", /* 258 */ + "timer_create", /* 259 */ + "260", /* 260 */ + "261", /* 261 */ + "262", /* 262 */ + "263", /* 263 */ + "264", /* 264 */ + "265", /* 265 */ + "266", /* 266 */ + "267", /* 267 */ + "statfs64", /* 268 */ + "fstatfs64", /* 269 */ + "tgkill", /* 270 */ + "utimes", /* 271 */ + "fadvise64_64", /* 272 */ + "vserver", /* 273 */ + "mbind", /* 274 */ + "get_mempolicy", /* 275 */ + "set_mempolicy", /* 276 */ + "mq_open", /* 277 */ + "278", /* 278 */ + "279", /* 279 */ + "280", /* 280 */ + "281", /* 281 */ + "282", /* 282 */ + "kexec_load", /* 283 */ + "waitid", /* 284 */ + "285", /* 285 */ + "add_key", /* 286 */ + "request_key", /* 287 */ + "keyctl", /* 288 */ + "ioprio_set", /* 289 */ + "ioprio_get", /* 290 */ + "inotify_init", /* 291 */ + "inotify_add_watch", /* 292 */ + "inotify_rm_watch", /* 293 */ + "migrate_pages", /* 294 */ + "openat", /* 295 */ + "mkdirat", /* 296 */ + "mknodat", /* 297 */ + "fchownat", /* 298 */ + "futimesat", /* 299 */ + "fstatat64", /* 300 */ + "unlinkat", /* 301 */ + "renameat", /* 302 */ + "linkat", /* 303 */ + "symlinkat", /* 304 */ + "readlinkat", /* 305 */ + "fchmodat", /* 306 */ + "faccessat", /* 307 */ + "pselect6", /* 308 */ + "ppoll", /* 309 */ + "unshare", /* 310 */ + "set_robust_list", /* 311 */ + "get_robust_list", /* 312 */ + "splice", /* 313 */ + "sync_file_range", /* 314 */ + "tee", /* 315 */ + "vmsplice", /* 316 */ diff --git a/sysdeps/linux-gnu/i386/trace.c b/sysdeps/linux-gnu/i386/trace.c new file mode 100644 index 0000000..76f1105 --- /dev/null +++ b/sysdeps/linux-gnu/i386/trace.c @@ -0,0 +1,85 @@ +#include "config.h" + +#include +#include +#include +#include +#include +#include + +#include "common.h" + +#if (!defined(PTRACE_PEEKUSER) && defined(PTRACE_PEEKUSR)) +# define PTRACE_PEEKUSER PTRACE_PEEKUSR +#endif + +#if (!defined(PTRACE_POKEUSER) && defined(PTRACE_POKEUSR)) +# define PTRACE_POKEUSER PTRACE_POKEUSR +#endif + +void +get_arch_dep(Process *proc) { +} + +/* Returns 1 if syscall, 2 if sysret, 0 otherwise. + */ +int +syscall_p(Process *proc, int status, int *sysnum) { + if (WIFSTOPPED(status) + && WSTOPSIG(status) == (SIGTRAP | proc->tracesysgood)) { + *sysnum = ptrace(PTRACE_PEEKUSER, proc->pid, 4 * ORIG_EAX, 0); + + if (proc->callstack_depth > 0 && + proc->callstack[proc->callstack_depth - 1].is_syscall && + proc->callstack[proc->callstack_depth - 1].c_un.syscall == *sysnum) { + return 2; + } + + if (*sysnum >= 0) { + return 1; + } + } + return 0; +} + +long +gimme_arg(enum tof type, Process *proc, int arg_num, arg_type_info *info) { + if (arg_num == -1) { /* return value */ + return ptrace(PTRACE_PEEKUSER, proc->pid, 4 * EAX, 0); + } + + if (type == LT_TOF_FUNCTION || type == LT_TOF_FUNCTIONR) { + return ptrace(PTRACE_PEEKTEXT, proc->pid, + proc->stack_pointer + 4 * (arg_num + 1), 0); + } else if (type == LT_TOF_SYSCALL || type == LT_TOF_SYSCALLR) { +#if 0 + switch (arg_num) { + case 0: + return ptrace(PTRACE_PEEKUSER, proc->pid, 4 * EBX, 0); + case 1: + return ptrace(PTRACE_PEEKUSER, proc->pid, 4 * ECX, 0); + case 2: + return ptrace(PTRACE_PEEKUSER, proc->pid, 4 * EDX, 0); + case 3: + return ptrace(PTRACE_PEEKUSER, proc->pid, 4 * ESI, 0); + case 4: + return ptrace(PTRACE_PEEKUSER, proc->pid, 4 * EDI, 0); + default: + fprintf(stderr, + "gimme_arg called with wrong arguments\n"); + exit(2); + } +#else + return ptrace(PTRACE_PEEKUSER, proc->pid, 4 * arg_num, 0); +#endif + } else { + fprintf(stderr, "gimme_arg called with wrong arguments\n"); + exit(1); + } + + return 0; +} + +void +save_register_args(enum tof type, Process *proc) { +} diff --git a/sysdeps/linux-gnu/ia64/Makefile b/sysdeps/linux-gnu/ia64/Makefile new file mode 100644 index 0000000..4f0ef63 --- /dev/null +++ b/sysdeps/linux-gnu/ia64/Makefile @@ -0,0 +1,10 @@ +OBJ = trace.o regs.o plt.o breakpoint.o + +all: arch.o + +arch.o: $(OBJ) + $(LD) -r -o arch.o $(OBJ) + +clean: + $(RM) $(OBJ) arch.o + diff --git a/sysdeps/linux-gnu/ia64/arch.h b/sysdeps/linux-gnu/ia64/arch.h new file mode 100644 index 0000000..673047c --- /dev/null +++ b/sysdeps/linux-gnu/ia64/arch.h @@ -0,0 +1,13 @@ +#define ARCH_HAVE_DISABLE_BREAKPOINT 1 +#define ARCH_HAVE_ENABLE_BREAKPOINT 1 + +#define BREAKPOINT_LENGTH 16 +#define BREAKPOINT_VALUE {0} +#define DECR_PC_AFTER_BREAK 0 + +#define LT_ELFCLASS ELFCLASS64 +#define LT_ELF_MACHINE EM_IA_64 + +// ia64 actually does use .opd, but we don't need to do the +// translation manually. +#undef ARCH_SUPPORTS_OPD diff --git a/sysdeps/linux-gnu/ia64/breakpoint.c b/sysdeps/linux-gnu/ia64/breakpoint.c new file mode 100644 index 0000000..4f09173 --- /dev/null +++ b/sysdeps/linux-gnu/ia64/breakpoint.c @@ -0,0 +1,212 @@ +/* IA64 breakpoint support. Much of this clagged from gdb + * -Ian Wienand 10/3/2005 + */ + +#include "config.h" + +#include +#include +#include "arch.h" +#include "options.h" +#include "output.h" +#include "debug.h" + +static long long +extract_bit_field(char *bundle, int from, int len) { + long long result = 0LL; + int to = from + len; + int from_byte = from / 8; + int to_byte = to / 8; + unsigned char *b = (unsigned char *)bundle; + unsigned char c; + int lshift; + int i; + + c = b[from_byte]; + if (from_byte == to_byte) + c = ((unsigned char)(c << (8 - to % 8))) >> (8 - to % 8); + result = c >> (from % 8); + lshift = 8 - (from % 8); + + for (i = from_byte + 1; i < to_byte; i++) { + result |= ((long long)b[i]) << lshift; + lshift += 8; + } + + if (from_byte < to_byte && (to % 8 != 0)) { + c = b[to_byte]; + c = ((unsigned char)(c << (8 - to % 8))) >> (8 - to % 8); + result |= ((long long)c) << lshift; + } + + return result; +} + +/* Replace the specified bits in an instruction bundle */ +static void +replace_bit_field(char *bundle, long long val, int from, int len) { + int to = from + len; + int from_byte = from / 8; + int to_byte = to / 8; + unsigned char *b = (unsigned char *)bundle; + unsigned char c; + + if (from_byte == to_byte) { + unsigned char left, right; + c = b[from_byte]; + left = (c >> (to % 8)) << (to % 8); + right = + ((unsigned char)(c << (8 - from % 8))) >> (8 - from % 8); + c = (unsigned char)(val & 0xff); + c = (unsigned char)(c << (from % 8 + 8 - to % 8)) >> (8 - + to % 8); + c |= right | left; + b[from_byte] = c; + } else { + int i; + c = b[from_byte]; + c = ((unsigned char)(c << (8 - from % 8))) >> (8 - from % 8); + c = c | (val << (from % 8)); + b[from_byte] = c; + val >>= 8 - from % 8; + + for (i = from_byte + 1; i < to_byte; i++) { + c = val & 0xff; + val >>= 8; + b[i] = c; + } + + if (to % 8 != 0) { + unsigned char cv = (unsigned char)val; + c = b[to_byte]; + c = c >> (to % 8) << (to % 8); + c |= ((unsigned char)(cv << (8 - to % 8))) >> (8 - + to % 8); + b[to_byte] = c; + } + } +} + +/* Return the contents of slot N (for N = 0, 1, or 2) in + and instruction bundle */ +static long long +slotN_contents(char *bundle, int slotnum) { + return extract_bit_field(bundle, 5 + 41 * slotnum, 41); +} + +/* Store an instruction in an instruction bundle */ + +static void +replace_slotN_contents(char *bundle, long long instr, int slotnum) { + replace_bit_field(bundle, instr, 5 + 41 * slotnum, 41); +} + +typedef enum instruction_type { + A, /* Integer ALU ; I-unit or M-unit */ + I, /* Non-ALU integer; I-unit */ + M, /* Memory ; M-unit */ + F, /* Floating-point ; F-unit */ + B, /* Branch ; B-unit */ + L, /* Extended (L+X) ; I-unit */ + X, /* Extended (L+X) ; I-unit */ + undefined /* undefined or reserved */ +} instruction_type; + +static enum instruction_type template_encoding_table[32][3] = { + {M, I, I}, /* 00 */ + {M, I, I}, /* 01 */ + {M, I, I}, /* 02 */ + {M, I, I}, /* 03 */ + {M, L, X}, /* 04 */ + {M, L, X}, /* 05 */ + {undefined, undefined, undefined}, /* 06 */ + {undefined, undefined, undefined}, /* 07 */ + {M, M, I}, /* 08 */ + {M, M, I}, /* 09 */ + {M, M, I}, /* 0A */ + {M, M, I}, /* 0B */ + {M, F, I}, /* 0C */ + {M, F, I}, /* 0D */ + {M, M, F}, /* 0E */ + {M, M, F}, /* 0F */ + {M, I, B}, /* 10 */ + {M, I, B}, /* 11 */ + {M, B, B}, /* 12 */ + {M, B, B}, /* 13 */ + {undefined, undefined, undefined}, /* 14 */ + {undefined, undefined, undefined}, /* 15 */ + {B, B, B}, /* 16 */ + {B, B, B}, /* 17 */ + {M, M, B}, /* 18 */ + {M, M, B}, /* 19 */ + {undefined, undefined, undefined}, /* 1A */ + {undefined, undefined, undefined}, /* 1B */ + {M, F, B}, /* 1C */ + {M, F, B}, /* 1D */ + {undefined, undefined, undefined}, /* 1E */ + {undefined, undefined, undefined}, /* 1F */ +}; + +union bundle_t { + char cbundle[16]; + unsigned long ubundle[2]; +}; + +void +arch_enable_breakpoint(pid_t pid, Breakpoint *sbp) { + + unsigned long addr = (unsigned long)sbp->addr; + union bundle_t bundle; + int slotnum = (int)(addr & 0x0f) & 0x3; + long long instr; + int template; + + debug(1, "Enable Breakpoint at %p)", sbp->addr); + + if (slotnum > 2) + printf + ("Can't insert breakpoint for slot numbers greater than 2."); + + addr &= ~0x0f; + bundle.ubundle[0] = ptrace(PTRACE_PEEKTEXT, pid, addr, 0); + bundle.ubundle[1] = ptrace(PTRACE_PEEKTEXT, pid, addr + 8, 0); + + /* Check for L type instruction in 2nd slot, if present then + bump up the slot number to the 3rd slot */ + template = extract_bit_field(bundle.cbundle, 0, 5); + if (slotnum == 1 && template_encoding_table[template][1] == L) { + slotnum = 2; + } + + instr = slotN_contents(bundle.cbundle, slotnum); + + memcpy(sbp->orig_value, &instr, sizeof(instr)); + + replace_slotN_contents(bundle.cbundle, 0x00002000040LL, slotnum); + + ptrace(PTRACE_POKETEXT, pid, addr, bundle.ubundle[0]); + ptrace(PTRACE_POKETEXT, pid, addr + 8, bundle.ubundle[1]); + +} + +void +arch_disable_breakpoint(pid_t pid, const Breakpoint *sbp) { + + unsigned long addr = (unsigned long)sbp->addr; + int slotnum = (int)(addr & 0x0f) & 0x3; + union bundle_t bundle; + unsigned long instr; + + debug(1, "Disable Breakpoint at %p", sbp->addr); + + addr &= ~0x0f; + + bundle.ubundle[0] = ptrace(PTRACE_PEEKTEXT, pid, addr, 0); + bundle.ubundle[1] = ptrace(PTRACE_PEEKTEXT, pid, addr + 8, 0); + + memcpy(&instr, sbp->orig_value, sizeof(instr)); + + replace_slotN_contents(bundle.cbundle, instr, slotnum); + ptrace(PTRACE_POKETEXT, pid, addr, bundle.ubundle[0]); + ptrace(PTRACE_POKETEXT, pid, addr + 8, bundle.ubundle[1]); +} diff --git a/sysdeps/linux-gnu/ia64/plt.c b/sysdeps/linux-gnu/ia64/plt.c new file mode 100644 index 0000000..7fd451b --- /dev/null +++ b/sysdeps/linux-gnu/ia64/plt.c @@ -0,0 +1,46 @@ +#include +#include "common.h" + +/* A bundle is 128 bits */ +#define BUNDLE_SIZE 16 + +/* + + The PLT has + + ] 3 bundles as a header + + ] The special reserved entry + + ] Following that, each PLT entry has it's initial code that the GOT entry + points to. Each PLT entry has one bundle allocated. + + ] Following that, each PLT entry has two bundles of actual PLT code, + i.e. load up the address from the GOT and jump to it. This is the + point we want to insert the breakpoint, as this will be captured + every time we jump to the PLT entry in the code. + +*/ + +GElf_Addr +arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela * rela) { + /* Find number of entires by removing header and special + * entry, dividing total size by three, since each PLT entry + * will have 3 bundles (1 for inital entry and two for the PLT + * code). */ + int entries = (lte->plt_size - 4 * BUNDLE_SIZE) / (3 * BUNDLE_SIZE); + + /* Now the point we want to break on is the PLT entry after + * all the header stuff */ + unsigned long addr = + lte->plt_addr + (4 * BUNDLE_SIZE) + (BUNDLE_SIZE * entries) + + (2 * ndx * BUNDLE_SIZE); + debug(3, "Found PLT %d entry at %lx\n", ndx, addr); + + return addr; +} + +void * +sym2addr(Process *proc, struct library_symbol *sym) { + return sym->enter_addr; +} diff --git a/sysdeps/linux-gnu/ia64/ptrace.h b/sysdeps/linux-gnu/ia64/ptrace.h new file mode 100644 index 0000000..c3cbcb6 --- /dev/null +++ b/sysdeps/linux-gnu/ia64/ptrace.h @@ -0,0 +1 @@ +#include diff --git a/sysdeps/linux-gnu/ia64/regs.c b/sysdeps/linux-gnu/ia64/regs.c new file mode 100644 index 0000000..d161d34 --- /dev/null +++ b/sysdeps/linux-gnu/ia64/regs.c @@ -0,0 +1,51 @@ +#include "config.h" + +#include +#include + +#include +#include + +#include +#include "debug.h" +#include "common.h" + +void * +get_instruction_pointer(Process *proc) { + unsigned long ip = ptrace(PTRACE_PEEKUSER, proc->pid, PT_CR_IIP, 0); + unsigned long slot = + (ptrace(PTRACE_PEEKUSER, proc->pid, PT_CR_IPSR, 0) >> 41) & 3; + + return (void *)(ip | slot); +} + +void +set_instruction_pointer(Process *proc, void *addr) { + + unsigned long newip = (unsigned long)addr; + unsigned long slot = (unsigned long)addr & 0xf; + unsigned long psr = ptrace(PTRACE_PEEKUSER, proc->pid, PT_CR_IPSR, 0); + + psr &= ~(3UL << 41); + psr |= (slot & 0x3) << 41; + + newip &= ~0xfUL; + + ptrace(PTRACE_POKEUSER, proc->pid, PT_CR_IIP, (long)newip); + ptrace(PTRACE_POKEUSER, proc->pid, PT_CR_IPSR, psr); +} + +void * +get_stack_pointer(Process *proc) { + return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, PT_R12, 0); +} + +void * +get_return_addr(Process *proc, void *stack_pointer) { + return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, PT_B0, 0); +} + +void +set_return_addr(Process *proc, void *addr) { + ptrace(PTRACE_POKEUSER, proc->pid, PT_B0, addr); +} diff --git a/sysdeps/linux-gnu/ia64/signalent.h b/sysdeps/linux-gnu/ia64/signalent.h new file mode 100644 index 0000000..5395f82 --- /dev/null +++ b/sysdeps/linux-gnu/ia64/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 */ + "SIGSYS", /* 31 */ diff --git a/sysdeps/linux-gnu/ia64/syscallent.h b/sysdeps/linux-gnu/ia64/syscallent.h new file mode 100644 index 0000000..9bb4fb8 --- /dev/null +++ b/sysdeps/linux-gnu/ia64/syscallent.h @@ -0,0 +1,1303 @@ + "0", /* 0 */ + "1", /* 1 */ + "2", /* 2 */ + "3", /* 3 */ + "4", /* 4 */ + "5", /* 5 */ + "6", /* 6 */ + "7", /* 7 */ + "8", /* 8 */ + "9", /* 9 */ + "10", /* 10 */ + "11", /* 11 */ + "12", /* 12 */ + "13", /* 13 */ + "14", /* 14 */ + "15", /* 15 */ + "16", /* 16 */ + "17", /* 17 */ + "18", /* 18 */ + "19", /* 19 */ + "20", /* 20 */ + "21", /* 21 */ + "22", /* 22 */ + "23", /* 23 */ + "24", /* 24 */ + "25", /* 25 */ + "26", /* 26 */ + "27", /* 27 */ + "28", /* 28 */ + "29", /* 29 */ + "30", /* 30 */ + "31", /* 31 */ + "32", /* 32 */ + "33", /* 33 */ + "34", /* 34 */ + "35", /* 35 */ + "36", /* 36 */ + "37", /* 37 */ + "38", /* 38 */ + "39", /* 39 */ + "40", /* 40 */ + "41", /* 41 */ + "42", /* 42 */ + "43", /* 43 */ + "44", /* 44 */ + "45", /* 45 */ + "46", /* 46 */ + "47", /* 47 */ + "48", /* 48 */ + "49", /* 49 */ + "50", /* 50 */ + "51", /* 51 */ + "52", /* 52 */ + "53", /* 53 */ + "54", /* 54 */ + "55", /* 55 */ + "56", /* 56 */ + "57", /* 57 */ + "58", /* 58 */ + "59", /* 59 */ + "60", /* 60 */ + "61", /* 61 */ + "62", /* 62 */ + "63", /* 63 */ + "64", /* 64 */ + "65", /* 65 */ + "66", /* 66 */ + "67", /* 67 */ + "68", /* 68 */ + "69", /* 69 */ + "70", /* 70 */ + "71", /* 71 */ + "72", /* 72 */ + "73", /* 73 */ + "74", /* 74 */ + "75", /* 75 */ + "76", /* 76 */ + "77", /* 77 */ + "78", /* 78 */ + "79", /* 79 */ + "80", /* 80 */ + "81", /* 81 */ + "82", /* 82 */ + "83", /* 83 */ + "84", /* 84 */ + "85", /* 85 */ + "86", /* 86 */ + "87", /* 87 */ + "88", /* 88 */ + "89", /* 89 */ + "90", /* 90 */ + "91", /* 91 */ + "92", /* 92 */ + "93", /* 93 */ + "94", /* 94 */ + "95", /* 95 */ + "96", /* 96 */ + "97", /* 97 */ + "98", /* 98 */ + "99", /* 99 */ + "100", /* 100 */ + "101", /* 101 */ + "102", /* 102 */ + "103", /* 103 */ + "104", /* 104 */ + "105", /* 105 */ + "106", /* 106 */ + "107", /* 107 */ + "108", /* 108 */ + "109", /* 109 */ + "110", /* 110 */ + "111", /* 111 */ + "112", /* 112 */ + "113", /* 113 */ + "114", /* 114 */ + "115", /* 115 */ + "116", /* 116 */ + "117", /* 117 */ + "118", /* 118 */ + "119", /* 119 */ + "120", /* 120 */ + "121", /* 121 */ + "122", /* 122 */ + "123", /* 123 */ + "124", /* 124 */ + "125", /* 125 */ + "126", /* 126 */ + "127", /* 127 */ + "128", /* 128 */ + "129", /* 129 */ + "130", /* 130 */ + "131", /* 131 */ + "132", /* 132 */ + "133", /* 133 */ + "134", /* 134 */ + "135", /* 135 */ + "136", /* 136 */ + "137", /* 137 */ + "138", /* 138 */ + "139", /* 139 */ + "140", /* 140 */ + "141", /* 141 */ + "142", /* 142 */ + "143", /* 143 */ + "144", /* 144 */ + "145", /* 145 */ + "146", /* 146 */ + "147", /* 147 */ + "148", /* 148 */ + "149", /* 149 */ + "150", /* 150 */ + "151", /* 151 */ + "152", /* 152 */ + "153", /* 153 */ + "154", /* 154 */ + "155", /* 155 */ + "156", /* 156 */ + "157", /* 157 */ + "158", /* 158 */ + "159", /* 159 */ + "160", /* 160 */ + "161", /* 161 */ + "162", /* 162 */ + "163", /* 163 */ + "164", /* 164 */ + "165", /* 165 */ + "166", /* 166 */ + "167", /* 167 */ + "168", /* 168 */ + "169", /* 169 */ + "170", /* 170 */ + "171", /* 171 */ + "172", /* 172 */ + "173", /* 173 */ + "174", /* 174 */ + "175", /* 175 */ + "176", /* 176 */ + "177", /* 177 */ + "178", /* 178 */ + "179", /* 179 */ + "180", /* 180 */ + "181", /* 181 */ + "182", /* 182 */ + "183", /* 183 */ + "184", /* 184 */ + "185", /* 185 */ + "186", /* 186 */ + "187", /* 187 */ + "188", /* 188 */ + "189", /* 189 */ + "190", /* 190 */ + "191", /* 191 */ + "192", /* 192 */ + "193", /* 193 */ + "194", /* 194 */ + "195", /* 195 */ + "196", /* 196 */ + "197", /* 197 */ + "198", /* 198 */ + "199", /* 199 */ + "200", /* 200 */ + "201", /* 201 */ + "202", /* 202 */ + "203", /* 203 */ + "204", /* 204 */ + "205", /* 205 */ + "206", /* 206 */ + "207", /* 207 */ + "208", /* 208 */ + "209", /* 209 */ + "210", /* 210 */ + "211", /* 211 */ + "212", /* 212 */ + "213", /* 213 */ + "214", /* 214 */ + "215", /* 215 */ + "216", /* 216 */ + "217", /* 217 */ + "218", /* 218 */ + "219", /* 219 */ + "220", /* 220 */ + "221", /* 221 */ + "222", /* 222 */ + "223", /* 223 */ + "224", /* 224 */ + "225", /* 225 */ + "226", /* 226 */ + "227", /* 227 */ + "228", /* 228 */ + "229", /* 229 */ + "230", /* 230 */ + "231", /* 231 */ + "232", /* 232 */ + "233", /* 233 */ + "234", /* 234 */ + "235", /* 235 */ + "236", /* 236 */ + "237", /* 237 */ + "238", /* 238 */ + "239", /* 239 */ + "240", /* 240 */ + "241", /* 241 */ + "242", /* 242 */ + "243", /* 243 */ + "244", /* 244 */ + "245", /* 245 */ + "246", /* 246 */ + "247", /* 247 */ + "248", /* 248 */ + "249", /* 249 */ + "250", /* 250 */ + "251", /* 251 */ + "252", /* 252 */ + "253", /* 253 */ + "254", /* 254 */ + "255", /* 255 */ + "256", /* 256 */ + "257", /* 257 */ + "258", /* 258 */ + "259", /* 259 */ + "260", /* 260 */ + "261", /* 261 */ + "262", /* 262 */ + "263", /* 263 */ + "264", /* 264 */ + "265", /* 265 */ + "266", /* 266 */ + "267", /* 267 */ + "268", /* 268 */ + "269", /* 269 */ + "270", /* 270 */ + "271", /* 271 */ + "272", /* 272 */ + "273", /* 273 */ + "274", /* 274 */ + "275", /* 275 */ + "276", /* 276 */ + "277", /* 277 */ + "278", /* 278 */ + "279", /* 279 */ + "280", /* 280 */ + "281", /* 281 */ + "282", /* 282 */ + "283", /* 283 */ + "284", /* 284 */ + "285", /* 285 */ + "286", /* 286 */ + "287", /* 287 */ + "288", /* 288 */ + "289", /* 289 */ + "290", /* 290 */ + "291", /* 291 */ + "292", /* 292 */ + "293", /* 293 */ + "294", /* 294 */ + "295", /* 295 */ + "296", /* 296 */ + "297", /* 297 */ + "298", /* 298 */ + "299", /* 299 */ + "300", /* 300 */ + "301", /* 301 */ + "302", /* 302 */ + "303", /* 303 */ + "304", /* 304 */ + "305", /* 305 */ + "306", /* 306 */ + "307", /* 307 */ + "308", /* 308 */ + "309", /* 309 */ + "310", /* 310 */ + "311", /* 311 */ + "312", /* 312 */ + "313", /* 313 */ + "314", /* 314 */ + "315", /* 315 */ + "316", /* 316 */ + "317", /* 317 */ + "318", /* 318 */ + "319", /* 319 */ + "320", /* 320 */ + "321", /* 321 */ + "322", /* 322 */ + "323", /* 323 */ + "324", /* 324 */ + "325", /* 325 */ + "326", /* 326 */ + "327", /* 327 */ + "328", /* 328 */ + "329", /* 329 */ + "330", /* 330 */ + "331", /* 331 */ + "332", /* 332 */ + "333", /* 333 */ + "334", /* 334 */ + "335", /* 335 */ + "336", /* 336 */ + "337", /* 337 */ + "338", /* 338 */ + "339", /* 339 */ + "340", /* 340 */ + "341", /* 341 */ + "342", /* 342 */ + "343", /* 343 */ + "344", /* 344 */ + "345", /* 345 */ + "346", /* 346 */ + "347", /* 347 */ + "348", /* 348 */ + "349", /* 349 */ + "350", /* 350 */ + "351", /* 351 */ + "352", /* 352 */ + "353", /* 353 */ + "354", /* 354 */ + "355", /* 355 */ + "356", /* 356 */ + "357", /* 357 */ + "358", /* 358 */ + "359", /* 359 */ + "360", /* 360 */ + "361", /* 361 */ + "362", /* 362 */ + "363", /* 363 */ + "364", /* 364 */ + "365", /* 365 */ + "366", /* 366 */ + "367", /* 367 */ + "368", /* 368 */ + "369", /* 369 */ + "370", /* 370 */ + "371", /* 371 */ + "372", /* 372 */ + "373", /* 373 */ + "374", /* 374 */ + "375", /* 375 */ + "376", /* 376 */ + "377", /* 377 */ + "378", /* 378 */ + "379", /* 379 */ + "380", /* 380 */ + "381", /* 381 */ + "382", /* 382 */ + "383", /* 383 */ + "384", /* 384 */ + "385", /* 385 */ + "386", /* 386 */ + "387", /* 387 */ + "388", /* 388 */ + "389", /* 389 */ + "390", /* 390 */ + "391", /* 391 */ + "392", /* 392 */ + "393", /* 393 */ + "394", /* 394 */ + "395", /* 395 */ + "396", /* 396 */ + "397", /* 397 */ + "398", /* 398 */ + "399", /* 399 */ + "400", /* 400 */ + "401", /* 401 */ + "402", /* 402 */ + "403", /* 403 */ + "404", /* 404 */ + "405", /* 405 */ + "406", /* 406 */ + "407", /* 407 */ + "408", /* 408 */ + "409", /* 409 */ + "410", /* 410 */ + "411", /* 411 */ + "412", /* 412 */ + "413", /* 413 */ + "414", /* 414 */ + "415", /* 415 */ + "416", /* 416 */ + "417", /* 417 */ + "418", /* 418 */ + "419", /* 419 */ + "420", /* 420 */ + "421", /* 421 */ + "422", /* 422 */ + "423", /* 423 */ + "424", /* 424 */ + "425", /* 425 */ + "426", /* 426 */ + "427", /* 427 */ + "428", /* 428 */ + "429", /* 429 */ + "430", /* 430 */ + "431", /* 431 */ + "432", /* 432 */ + "433", /* 433 */ + "434", /* 434 */ + "435", /* 435 */ + "436", /* 436 */ + "437", /* 437 */ + "438", /* 438 */ + "439", /* 439 */ + "440", /* 440 */ + "441", /* 441 */ + "442", /* 442 */ + "443", /* 443 */ + "444", /* 444 */ + "445", /* 445 */ + "446", /* 446 */ + "447", /* 447 */ + "448", /* 448 */ + "449", /* 449 */ + "450", /* 450 */ + "451", /* 451 */ + "452", /* 452 */ + "453", /* 453 */ + "454", /* 454 */ + "455", /* 455 */ + "456", /* 456 */ + "457", /* 457 */ + "458", /* 458 */ + "459", /* 459 */ + "460", /* 460 */ + "461", /* 461 */ + "462", /* 462 */ + "463", /* 463 */ + "464", /* 464 */ + "465", /* 465 */ + "466", /* 466 */ + "467", /* 467 */ + "468", /* 468 */ + "469", /* 469 */ + "470", /* 470 */ + "471", /* 471 */ + "472", /* 472 */ + "473", /* 473 */ + "474", /* 474 */ + "475", /* 475 */ + "476", /* 476 */ + "477", /* 477 */ + "478", /* 478 */ + "479", /* 479 */ + "480", /* 480 */ + "481", /* 481 */ + "482", /* 482 */ + "483", /* 483 */ + "484", /* 484 */ + "485", /* 485 */ + "486", /* 486 */ + "487", /* 487 */ + "488", /* 488 */ + "489", /* 489 */ + "490", /* 490 */ + "491", /* 491 */ + "492", /* 492 */ + "493", /* 493 */ + "494", /* 494 */ + "495", /* 495 */ + "496", /* 496 */ + "497", /* 497 */ + "498", /* 498 */ + "499", /* 499 */ + "500", /* 500 */ + "501", /* 501 */ + "502", /* 502 */ + "503", /* 503 */ + "504", /* 504 */ + "505", /* 505 */ + "506", /* 506 */ + "507", /* 507 */ + "508", /* 508 */ + "509", /* 509 */ + "510", /* 510 */ + "511", /* 511 */ + "512", /* 512 */ + "513", /* 513 */ + "514", /* 514 */ + "515", /* 515 */ + "516", /* 516 */ + "517", /* 517 */ + "518", /* 518 */ + "519", /* 519 */ + "520", /* 520 */ + "521", /* 521 */ + "522", /* 522 */ + "523", /* 523 */ + "524", /* 524 */ + "525", /* 525 */ + "526", /* 526 */ + "527", /* 527 */ + "528", /* 528 */ + "529", /* 529 */ + "530", /* 530 */ + "531", /* 531 */ + "532", /* 532 */ + "533", /* 533 */ + "534", /* 534 */ + "535", /* 535 */ + "536", /* 536 */ + "537", /* 537 */ + "538", /* 538 */ + "539", /* 539 */ + "540", /* 540 */ + "541", /* 541 */ + "542", /* 542 */ + "543", /* 543 */ + "544", /* 544 */ + "545", /* 545 */ + "546", /* 546 */ + "547", /* 547 */ + "548", /* 548 */ + "549", /* 549 */ + "550", /* 550 */ + "551", /* 551 */ + "552", /* 552 */ + "553", /* 553 */ + "554", /* 554 */ + "555", /* 555 */ + "556", /* 556 */ + "557", /* 557 */ + "558", /* 558 */ + "559", /* 559 */ + "560", /* 560 */ + "561", /* 561 */ + "562", /* 562 */ + "563", /* 563 */ + "564", /* 564 */ + "565", /* 565 */ + "566", /* 566 */ + "567", /* 567 */ + "568", /* 568 */ + "569", /* 569 */ + "570", /* 570 */ + "571", /* 571 */ + "572", /* 572 */ + "573", /* 573 */ + "574", /* 574 */ + "575", /* 575 */ + "576", /* 576 */ + "577", /* 577 */ + "578", /* 578 */ + "579", /* 579 */ + "580", /* 580 */ + "581", /* 581 */ + "582", /* 582 */ + "583", /* 583 */ + "584", /* 584 */ + "585", /* 585 */ + "586", /* 586 */ + "587", /* 587 */ + "588", /* 588 */ + "589", /* 589 */ + "590", /* 590 */ + "591", /* 591 */ + "592", /* 592 */ + "593", /* 593 */ + "594", /* 594 */ + "595", /* 595 */ + "596", /* 596 */ + "597", /* 597 */ + "598", /* 598 */ + "599", /* 599 */ + "600", /* 600 */ + "601", /* 601 */ + "602", /* 602 */ + "603", /* 603 */ + "604", /* 604 */ + "605", /* 605 */ + "606", /* 606 */ + "607", /* 607 */ + "608", /* 608 */ + "609", /* 609 */ + "610", /* 610 */ + "611", /* 611 */ + "612", /* 612 */ + "613", /* 613 */ + "614", /* 614 */ + "615", /* 615 */ + "616", /* 616 */ + "617", /* 617 */ + "618", /* 618 */ + "619", /* 619 */ + "620", /* 620 */ + "621", /* 621 */ + "622", /* 622 */ + "623", /* 623 */ + "624", /* 624 */ + "625", /* 625 */ + "626", /* 626 */ + "627", /* 627 */ + "628", /* 628 */ + "629", /* 629 */ + "630", /* 630 */ + "631", /* 631 */ + "632", /* 632 */ + "633", /* 633 */ + "634", /* 634 */ + "635", /* 635 */ + "636", /* 636 */ + "637", /* 637 */ + "638", /* 638 */ + "639", /* 639 */ + "640", /* 640 */ + "641", /* 641 */ + "642", /* 642 */ + "643", /* 643 */ + "644", /* 644 */ + "645", /* 645 */ + "646", /* 646 */ + "647", /* 647 */ + "648", /* 648 */ + "649", /* 649 */ + "650", /* 650 */ + "651", /* 651 */ + "652", /* 652 */ + "653", /* 653 */ + "654", /* 654 */ + "655", /* 655 */ + "656", /* 656 */ + "657", /* 657 */ + "658", /* 658 */ + "659", /* 659 */ + "660", /* 660 */ + "661", /* 661 */ + "662", /* 662 */ + "663", /* 663 */ + "664", /* 664 */ + "665", /* 665 */ + "666", /* 666 */ + "667", /* 667 */ + "668", /* 668 */ + "669", /* 669 */ + "670", /* 670 */ + "671", /* 671 */ + "672", /* 672 */ + "673", /* 673 */ + "674", /* 674 */ + "675", /* 675 */ + "676", /* 676 */ + "677", /* 677 */ + "678", /* 678 */ + "679", /* 679 */ + "680", /* 680 */ + "681", /* 681 */ + "682", /* 682 */ + "683", /* 683 */ + "684", /* 684 */ + "685", /* 685 */ + "686", /* 686 */ + "687", /* 687 */ + "688", /* 688 */ + "689", /* 689 */ + "690", /* 690 */ + "691", /* 691 */ + "692", /* 692 */ + "693", /* 693 */ + "694", /* 694 */ + "695", /* 695 */ + "696", /* 696 */ + "697", /* 697 */ + "698", /* 698 */ + "699", /* 699 */ + "700", /* 700 */ + "701", /* 701 */ + "702", /* 702 */ + "703", /* 703 */ + "704", /* 704 */ + "705", /* 705 */ + "706", /* 706 */ + "707", /* 707 */ + "708", /* 708 */ + "709", /* 709 */ + "710", /* 710 */ + "711", /* 711 */ + "712", /* 712 */ + "713", /* 713 */ + "714", /* 714 */ + "715", /* 715 */ + "716", /* 716 */ + "717", /* 717 */ + "718", /* 718 */ + "719", /* 719 */ + "720", /* 720 */ + "721", /* 721 */ + "722", /* 722 */ + "723", /* 723 */ + "724", /* 724 */ + "725", /* 725 */ + "726", /* 726 */ + "727", /* 727 */ + "728", /* 728 */ + "729", /* 729 */ + "730", /* 730 */ + "731", /* 731 */ + "732", /* 732 */ + "733", /* 733 */ + "734", /* 734 */ + "735", /* 735 */ + "736", /* 736 */ + "737", /* 737 */ + "738", /* 738 */ + "739", /* 739 */ + "740", /* 740 */ + "741", /* 741 */ + "742", /* 742 */ + "743", /* 743 */ + "744", /* 744 */ + "745", /* 745 */ + "746", /* 746 */ + "747", /* 747 */ + "748", /* 748 */ + "749", /* 749 */ + "750", /* 750 */ + "751", /* 751 */ + "752", /* 752 */ + "753", /* 753 */ + "754", /* 754 */ + "755", /* 755 */ + "756", /* 756 */ + "757", /* 757 */ + "758", /* 758 */ + "759", /* 759 */ + "760", /* 760 */ + "761", /* 761 */ + "762", /* 762 */ + "763", /* 763 */ + "764", /* 764 */ + "765", /* 765 */ + "766", /* 766 */ + "767", /* 767 */ + "768", /* 768 */ + "769", /* 769 */ + "770", /* 770 */ + "771", /* 771 */ + "772", /* 772 */ + "773", /* 773 */ + "774", /* 774 */ + "775", /* 775 */ + "776", /* 776 */ + "777", /* 777 */ + "778", /* 778 */ + "779", /* 779 */ + "780", /* 780 */ + "781", /* 781 */ + "782", /* 782 */ + "783", /* 783 */ + "784", /* 784 */ + "785", /* 785 */ + "786", /* 786 */ + "787", /* 787 */ + "788", /* 788 */ + "789", /* 789 */ + "790", /* 790 */ + "791", /* 791 */ + "792", /* 792 */ + "793", /* 793 */ + "794", /* 794 */ + "795", /* 795 */ + "796", /* 796 */ + "797", /* 797 */ + "798", /* 798 */ + "799", /* 799 */ + "800", /* 800 */ + "801", /* 801 */ + "802", /* 802 */ + "803", /* 803 */ + "804", /* 804 */ + "805", /* 805 */ + "806", /* 806 */ + "807", /* 807 */ + "808", /* 808 */ + "809", /* 809 */ + "810", /* 810 */ + "811", /* 811 */ + "812", /* 812 */ + "813", /* 813 */ + "814", /* 814 */ + "815", /* 815 */ + "816", /* 816 */ + "817", /* 817 */ + "818", /* 818 */ + "819", /* 819 */ + "820", /* 820 */ + "821", /* 821 */ + "822", /* 822 */ + "823", /* 823 */ + "824", /* 824 */ + "825", /* 825 */ + "826", /* 826 */ + "827", /* 827 */ + "828", /* 828 */ + "829", /* 829 */ + "830", /* 830 */ + "831", /* 831 */ + "832", /* 832 */ + "833", /* 833 */ + "834", /* 834 */ + "835", /* 835 */ + "836", /* 836 */ + "837", /* 837 */ + "838", /* 838 */ + "839", /* 839 */ + "840", /* 840 */ + "841", /* 841 */ + "842", /* 842 */ + "843", /* 843 */ + "844", /* 844 */ + "845", /* 845 */ + "846", /* 846 */ + "847", /* 847 */ + "848", /* 848 */ + "849", /* 849 */ + "850", /* 850 */ + "851", /* 851 */ + "852", /* 852 */ + "853", /* 853 */ + "854", /* 854 */ + "855", /* 855 */ + "856", /* 856 */ + "857", /* 857 */ + "858", /* 858 */ + "859", /* 859 */ + "860", /* 860 */ + "861", /* 861 */ + "862", /* 862 */ + "863", /* 863 */ + "864", /* 864 */ + "865", /* 865 */ + "866", /* 866 */ + "867", /* 867 */ + "868", /* 868 */ + "869", /* 869 */ + "870", /* 870 */ + "871", /* 871 */ + "872", /* 872 */ + "873", /* 873 */ + "874", /* 874 */ + "875", /* 875 */ + "876", /* 876 */ + "877", /* 877 */ + "878", /* 878 */ + "879", /* 879 */ + "880", /* 880 */ + "881", /* 881 */ + "882", /* 882 */ + "883", /* 883 */ + "884", /* 884 */ + "885", /* 885 */ + "886", /* 886 */ + "887", /* 887 */ + "888", /* 888 */ + "889", /* 889 */ + "890", /* 890 */ + "891", /* 891 */ + "892", /* 892 */ + "893", /* 893 */ + "894", /* 894 */ + "895", /* 895 */ + "896", /* 896 */ + "897", /* 897 */ + "898", /* 898 */ + "899", /* 899 */ + "900", /* 900 */ + "901", /* 901 */ + "902", /* 902 */ + "903", /* 903 */ + "904", /* 904 */ + "905", /* 905 */ + "906", /* 906 */ + "907", /* 907 */ + "908", /* 908 */ + "909", /* 909 */ + "910", /* 910 */ + "911", /* 911 */ + "912", /* 912 */ + "913", /* 913 */ + "914", /* 914 */ + "915", /* 915 */ + "916", /* 916 */ + "917", /* 917 */ + "918", /* 918 */ + "919", /* 919 */ + "920", /* 920 */ + "921", /* 921 */ + "922", /* 922 */ + "923", /* 923 */ + "924", /* 924 */ + "925", /* 925 */ + "926", /* 926 */ + "927", /* 927 */ + "928", /* 928 */ + "929", /* 929 */ + "930", /* 930 */ + "931", /* 931 */ + "932", /* 932 */ + "933", /* 933 */ + "934", /* 934 */ + "935", /* 935 */ + "936", /* 936 */ + "937", /* 937 */ + "938", /* 938 */ + "939", /* 939 */ + "940", /* 940 */ + "941", /* 941 */ + "942", /* 942 */ + "943", /* 943 */ + "944", /* 944 */ + "945", /* 945 */ + "946", /* 946 */ + "947", /* 947 */ + "948", /* 948 */ + "949", /* 949 */ + "950", /* 950 */ + "951", /* 951 */ + "952", /* 952 */ + "953", /* 953 */ + "954", /* 954 */ + "955", /* 955 */ + "956", /* 956 */ + "957", /* 957 */ + "958", /* 958 */ + "959", /* 959 */ + "960", /* 960 */ + "961", /* 961 */ + "962", /* 962 */ + "963", /* 963 */ + "964", /* 964 */ + "965", /* 965 */ + "966", /* 966 */ + "967", /* 967 */ + "968", /* 968 */ + "969", /* 969 */ + "970", /* 970 */ + "971", /* 971 */ + "972", /* 972 */ + "973", /* 973 */ + "974", /* 974 */ + "975", /* 975 */ + "976", /* 976 */ + "977", /* 977 */ + "978", /* 978 */ + "979", /* 979 */ + "980", /* 980 */ + "981", /* 981 */ + "982", /* 982 */ + "983", /* 983 */ + "984", /* 984 */ + "985", /* 985 */ + "986", /* 986 */ + "987", /* 987 */ + "988", /* 988 */ + "989", /* 989 */ + "990", /* 990 */ + "991", /* 991 */ + "992", /* 992 */ + "993", /* 993 */ + "994", /* 994 */ + "995", /* 995 */ + "996", /* 996 */ + "997", /* 997 */ + "998", /* 998 */ + "999", /* 999 */ + "1000", /* 1000 */ + "1001", /* 1001 */ + "1002", /* 1002 */ + "1003", /* 1003 */ + "1004", /* 1004 */ + "1005", /* 1005 */ + "1006", /* 1006 */ + "1007", /* 1007 */ + "1008", /* 1008 */ + "1009", /* 1009 */ + "1010", /* 1010 */ + "1011", /* 1011 */ + "1012", /* 1012 */ + "1013", /* 1013 */ + "1014", /* 1014 */ + "1015", /* 1015 */ + "1016", /* 1016 */ + "1017", /* 1017 */ + "1018", /* 1018 */ + "1019", /* 1019 */ + "1020", /* 1020 */ + "1021", /* 1021 */ + "1022", /* 1022 */ + "1023", /* 1023 */ + "ni_syscall", /* 1024 */ + "exit", /* 1025 */ + "read", /* 1026 */ + "write", /* 1027 */ + "open", /* 1028 */ + "close", /* 1029 */ + "creat", /* 1030 */ + "link", /* 1031 */ + "unlink", /* 1032 */ + "execve", /* 1033 */ + "chdir", /* 1034 */ + "fchdir", /* 1035 */ + "utimes", /* 1036 */ + "mknod", /* 1037 */ + "chmod", /* 1038 */ + "chown", /* 1039 */ + "lseek", /* 1040 */ + "getpid", /* 1041 */ + "getppid", /* 1042 */ + "mount", /* 1043 */ + "umount", /* 1044 */ + "setuid", /* 1045 */ + "getuid", /* 1046 */ + "geteuid", /* 1047 */ + "ptrace", /* 1048 */ + "access", /* 1049 */ + "sync", /* 1050 */ + "fsync", /* 1051 */ + "fdatasync", /* 1052 */ + "kill", /* 1053 */ + "rename", /* 1054 */ + "mkdir", /* 1055 */ + "rmdir", /* 1056 */ + "dup", /* 1057 */ + "pipe", /* 1058 */ + "times", /* 1059 */ + "brk", /* 1060 */ + "setgid", /* 1061 */ + "getgid", /* 1062 */ + "getegid", /* 1063 */ + "acct", /* 1064 */ + "ioctl", /* 1065 */ + "fcntl", /* 1066 */ + "umask", /* 1067 */ + "chroot", /* 1068 */ + "ustat", /* 1069 */ + "dup2", /* 1070 */ + "setreuid", /* 1071 */ + "setregid", /* 1072 */ + "getresuid", /* 1073 */ + "setresuid", /* 1074 */ + "getresgid", /* 1075 */ + "setresgid", /* 1076 */ + "getgroups", /* 1077 */ + "setgroups", /* 1078 */ + "getpgid", /* 1079 */ + "setpgid", /* 1080 */ + "setsid", /* 1081 */ + "getsid", /* 1082 */ + "sethostname", /* 1083 */ + "setrlimit", /* 1084 */ + "getrlimit", /* 1085 */ + "getrusage", /* 1086 */ + "gettimeofday", /* 1087 */ + "settimeofday", /* 1088 */ + "select", /* 1089 */ + "poll", /* 1090 */ + "symlink", /* 1091 */ + "readlink", /* 1092 */ + "uselib", /* 1093 */ + "swapon", /* 1094 */ + "swapoff", /* 1095 */ + "reboot", /* 1096 */ + "truncate", /* 1097 */ + "ftruncate", /* 1098 */ + "fchmod", /* 1099 */ + "fchown", /* 1100 */ + "getpriority", /* 1101 */ + "setpriority", /* 1102 */ + "statfs", /* 1103 */ + "fstatfs", /* 1104 */ + "gettid", /* 1105 */ + "semget", /* 1106 */ + "semop", /* 1107 */ + "semctl", /* 1108 */ + "msgget", /* 1109 */ + "msgsnd", /* 1110 */ + "msgrcv", /* 1111 */ + "msgctl", /* 1112 */ + "shmget", /* 1113 */ + "shmat", /* 1114 */ + "shmdt", /* 1115 */ + "shmctl", /* 1116 */ + "syslog", /* 1117 */ + "setitimer", /* 1118 */ + "getitimer", /* 1119 */ + "1120", /* 1120 */ + "1121", /* 1121 */ + "1122", /* 1122 */ + "vhangup", /* 1123 */ + "lchown", /* 1124 */ + "remap_file_pages", /* 1125 */ + "wait4", /* 1126 */ + "sysinfo", /* 1127 */ + "clone", /* 1128 */ + "setdomainname", /* 1129 */ + "uname", /* 1130 */ + "adjtimex", /* 1131 */ + "1132", /* 1132 */ + "init_module", /* 1133 */ + "delete_module", /* 1134 */ + "1135", /* 1135 */ + "1136", /* 1136 */ + "quotactl", /* 1137 */ + "bdflush", /* 1138 */ + "sysfs", /* 1139 */ + "personality", /* 1140 */ + "afs_syscall", /* 1141 */ + "setfsuid", /* 1142 */ + "setfsgid", /* 1143 */ + "getdents", /* 1144 */ + "flock", /* 1145 */ + "readv", /* 1146 */ + "writev", /* 1147 */ + "pread64", /* 1148 */ + "pwrite64", /* 1149 */ + "_sysctl", /* 1150 */ + "mmap", /* 1151 */ + "munmap", /* 1152 */ + "mlock", /* 1153 */ + "mlockall", /* 1154 */ + "mprotect", /* 1155 */ + "mremap", /* 1156 */ + "msync", /* 1157 */ + "munlock", /* 1158 */ + "munlockall", /* 1159 */ + "sched_getparam", /* 1160 */ + "sched_setparam", /* 1161 */ + "sched_getscheduler", /* 1162 */ + "sched_setscheduler", /* 1163 */ + "sched_yield", /* 1164 */ + "sched_get_priority_max", /* 1165 */ + "sched_get_priority_min", /* 1166 */ + "sched_rr_get_interval", /* 1167 */ + "nanosleep", /* 1168 */ + "nfsservctl", /* 1169 */ + "prctl", /* 1170 */ + "1171", /* 1171 */ + "mmap2", /* 1172 */ + "pciconfig_read", /* 1173 */ + "pciconfig_write", /* 1174 */ + "perfmonctl", /* 1175 */ + "sigaltstack", /* 1176 */ + "rt_sigaction", /* 1177 */ + "rt_sigpending", /* 1178 */ + "rt_sigprocmask", /* 1179 */ + "rt_sigqueueinfo", /* 1180 */ + "rt_sigreturn", /* 1181 */ + "rt_sigsuspend", /* 1182 */ + "rt_sigtimedwait", /* 1183 */ + "getcwd", /* 1184 */ + "capget", /* 1185 */ + "capset", /* 1186 */ + "sendfile", /* 1187 */ + "getpmsg", /* 1188 */ + "putpmsg", /* 1189 */ + "socket", /* 1190 */ + "bind", /* 1191 */ + "connect", /* 1192 */ + "listen", /* 1193 */ + "accept", /* 1194 */ + "getsockname", /* 1195 */ + "getpeername", /* 1196 */ + "socketpair", /* 1197 */ + "send", /* 1198 */ + "sendto", /* 1199 */ + "recv", /* 1200 */ + "recvfrom", /* 1201 */ + "shutdown", /* 1202 */ + "setsockopt", /* 1203 */ + "getsockopt", /* 1204 */ + "sendmsg", /* 1205 */ + "recvmsg", /* 1206 */ + "pivot_root", /* 1207 */ + "mincore", /* 1208 */ + "madvise", /* 1209 */ + "stat", /* 1210 */ + "lstat", /* 1211 */ + "fstat", /* 1212 */ + "clone2", /* 1213 */ + "getdents64", /* 1214 */ + "getunwind", /* 1215 */ + "readahead", /* 1216 */ + "setxattr", /* 1217 */ + "lsetxattr", /* 1218 */ + "fsetxattr", /* 1219 */ + "getxattr", /* 1220 */ + "lgetxattr", /* 1221 */ + "fgetxattr", /* 1222 */ + "listxattr", /* 1223 */ + "llistxattr", /* 1224 */ + "flistxattr", /* 1225 */ + "removexattr", /* 1226 */ + "lremovexattr", /* 1227 */ + "fremovexattr", /* 1228 */ + "tkill", /* 1229 */ + "futex", /* 1230 */ + "sched_setaffinity", /* 1231 */ + "sched_getaffinity", /* 1232 */ + "set_tid_address", /* 1233 */ + "fadvise64", /* 1234 */ + "tgkill", /* 1235 */ + "exit_group", /* 1236 */ + "lookup_dcookie", /* 1237 */ + "io_setup", /* 1238 */ + "io_destroy", /* 1239 */ + "io_getevents", /* 1240 */ + "io_submit", /* 1241 */ + "io_cancel", /* 1242 */ + "epoll_create", /* 1243 */ + "epoll_ctl", /* 1244 */ + "epoll_wait", /* 1245 */ + "restart_syscall", /* 1246 */ + "semtimedop", /* 1247 */ + "timer_create", /* 1248 */ + "timer_settime", /* 1249 */ + "timer_gettime", /* 1250 */ + "timer_getoverrun", /* 1251 */ + "timer_delete", /* 1252 */ + "clock_settime", /* 1253 */ + "clock_gettime", /* 1254 */ + "clock_getres", /* 1255 */ + "clock_nanosleep", /* 1256 */ + "fstatfs64", /* 1257 */ + "statfs64", /* 1258 */ + "mbind", /* 1259 */ + "get_mempolicy", /* 1260 */ + "set_mempolicy", /* 1261 */ + "mq_open", /* 1262 */ + "mq_unlink", /* 1263 */ + "mq_timedsend", /* 1264 */ + "mq_timedreceive", /* 1265 */ + "mq_notify", /* 1266 */ + "mq_getsetattr", /* 1267 */ + "kexec_load", /* 1268 */ + "vserver", /* 1269 */ + "waitid", /* 1270 */ + "add_key", /* 1271 */ + "request_key", /* 1272 */ + "keyctl", /* 1273 */ + "ioprio_set", /* 1274 */ + "ioprio_get", /* 1275 */ + "1276", /* 1276 */ + "inotify_init", /* 1277 */ + "inotify_add_watch", /* 1278 */ + "inotify_rm_watch", /* 1279 */ + "migrate_pages", /* 1280 */ + "openat", /* 1281 */ + "mkdirat", /* 1282 */ + "mknodat", /* 1283 */ + "fchownat", /* 1284 */ + "futimesat", /* 1285 */ + "newfstatat", /* 1286 */ + "unlinkat", /* 1287 */ + "renameat", /* 1288 */ + "linkat", /* 1289 */ + "symlinkat", /* 1290 */ + "readlinkat", /* 1291 */ + "fchmodat", /* 1292 */ + "faccessat", /* 1293 */ + "1294", /* 1294 */ + "1295", /* 1295 */ + "unshare", /* 1296 */ + "splice", /* 1297 */ + "set_robust_list", /* 1298 */ + "get_robust_list", /* 1299 */ + "sync_file_range", /* 1300 */ + "tee", /* 1301 */ + "vmsplice", /* 1302 */ diff --git a/sysdeps/linux-gnu/ia64/trace.c b/sysdeps/linux-gnu/ia64/trace.c new file mode 100644 index 0000000..799e0ff --- /dev/null +++ b/sysdeps/linux-gnu/ia64/trace.c @@ -0,0 +1,268 @@ +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" + +/* What we think of as a bundle, ptrace thinks of it as two unsigned + * longs */ +union bundle_t { + /* An IA64 instruction bundle has a 5 bit header describing the + * type of bundle, then 3 41 bit instructions + */ + struct { + struct { + unsigned long template:5; + unsigned long slot0:41; + unsigned long bot_slot1:18; + } word0; + struct { + unsigned long top_slot1:23; + unsigned long slot2:41; + } word1; + } bitmap; + unsigned long code[2]; +}; + +union cfm_t { + struct { + unsigned long sof:7; + unsigned long sol:7; + unsigned long sor:4; + unsigned long rrb_gr:7; + unsigned long rrb_fr:7; + unsigned long rrb_pr:6; + } cfm; + unsigned long value; +}; + +int +syscall_p(Process *proc, int status, int *sysnum) { + if (WIFSTOPPED(status) + && WSTOPSIG(status) == (SIGTRAP | proc->tracesysgood)) { + unsigned long slot = + (ptrace(PTRACE_PEEKUSER, proc->pid, PT_CR_IPSR, 0) >> 41) & + 0x3; + unsigned long ip = + ptrace(PTRACE_PEEKUSER, proc->pid, PT_CR_IIP, 0); + + /* r15 holds the system call number */ + unsigned long r15 = + ptrace(PTRACE_PEEKUSER, proc->pid, PT_R15, 0); + unsigned long insn; + + union bundle_t bundle; + + /* On fault, the IP has moved forward to the next + * slot. If that is zero, then the actual place we + * broke was in the previous bundle, so wind back the + * IP. + */ + if (slot == 0) + ip = ip - 16; + bundle.code[0] = ptrace(PTRACE_PEEKTEXT, proc->pid, ip, 0); + bundle.code[1] = ptrace(PTRACE_PEEKTEXT, proc->pid, ip + 8, 0); + + unsigned long bot = 0UL | bundle.bitmap.word0.bot_slot1; + unsigned long top = 0UL | bundle.bitmap.word1.top_slot1; + + /* handle the rollback, slot 0 is actually slot 2 of + * the previous instruction (see above) */ + switch (slot) { + case 0: + insn = bundle.bitmap.word1.slot2; + break; + case 1: + insn = bundle.bitmap.word0.slot0; + break; + case 2: + /* make sure we're shifting about longs */ + insn = 0UL | bot | (top << 18UL); + break; + default: + printf("Ummm, can't find instruction slot?\n"); + exit(1); + } + + /* We need to support both the older break instruction + * type syscalls, and the new epc type ones. + * + * Bit 20 of the break constant is encoded in the "i" + * bit (bit 36) of the instruction, hence you should + * see 0x1000000000. + * + * An EPC call is just 0x1ffffffffff + */ + if (insn == 0x1000000000 || insn == 0x1ffffffffff) { + *sysnum = r15; + if (proc->callstack_depth > 0 && + proc->callstack[proc->callstack_depth - 1].is_syscall && + proc->callstack[proc->callstack_depth - 1].c_un.syscall == *sysnum) { + return 2; + } + return 1; + } + } + return 0; +} + +/* Stolen from David Mosberger's utrace tool, which he released under + the GPL + (http://www.gelato.unsw.edu.au/archives/linux-ia64/0104/1405.html) */ +static inline double +fpreg_to_double (struct ia64_fpreg *fp) { + double result; + + asm ("ldf.fill %0=%1" : "=f"(result) : "m"(*fp)); + return result; +} + +static long +gimme_long_arg(enum tof type, Process *proc, int arg_num) { + union cfm_t cfm; + unsigned long bsp; + + bsp = ptrace(PTRACE_PEEKUSER, proc->pid, PT_AR_BSP, 0); + cfm.value = ptrace(PTRACE_PEEKUSER, proc->pid, PT_CFM, 0); + + if (arg_num == -1) /* return value */ + return ptrace(PTRACE_PEEKUSER, proc->pid, PT_R8, 0); + + /* First 8 arguments are passed in registers on the register + * stack, the following arguments are passed on the stack + * after a 16 byte scratch area + * + * If the function has returned, the ia64 register window has + * been reverted to the caller's configuration. So although in + * the callee, the first parameter is in R32, in the caller + * the first parameter comes in the registers after the local + * registers (really, input parameters plus locals, but the + * hardware doesn't track the distinction.) So we have to add + * in the size of the local area (sol) to find the first + * parameter passed to the callee. */ + if (type == LT_TOF_FUNCTION || type == LT_TOF_FUNCTIONR) { + if (arg_num < 8) { + if (type == LT_TOF_FUNCTIONR) + arg_num += cfm.cfm.sol; + + return ptrace(PTRACE_PEEKDATA, proc->pid, + (long)ia64_rse_skip_regs((unsigned long *)bsp, + -cfm.cfm.sof + arg_num), + 0); + } else { + unsigned long sp = + ptrace(PTRACE_PEEKUSER, proc->pid, PT_R12, 0) + 16; + return ptrace(PTRACE_PEEKDATA, proc->pid, + sp + (8 * (arg_num - 8))); + } + } + + if (type == LT_TOF_SYSCALL || LT_TOF_SYSCALLR) + return ptrace(PTRACE_PEEKDATA, proc->pid, + (long)ia64_rse_skip_regs((unsigned long *)bsp, arg_num), + 0); + + /* error if we get here */ + fprintf(stderr, "gimme_arg called with wrong arguments\n"); + exit(1); +} + +static long float_regs[8] = { PT_F8, PT_F9, PT_F10, PT_F11, + PT_F12, PT_F13, PT_F14, PT_F15 }; +static double +gimme_float_arg(enum tof type, Process *proc, int arg_num) { + union cfm_t cfm; + unsigned long bsp; + struct ia64_fpreg reg; + + if (arg_num == -1) { /* return value */ + reg.u.bits[0] = ptrace(PTRACE_PEEKUSER, proc->pid, + PT_F8, 0); + reg.u.bits[1] = ptrace(PTRACE_PEEKUSER, proc->pid, + PT_F8 + 0x8, 0); + return fpreg_to_double(®); + } + + bsp = ptrace(PTRACE_PEEKUSER, proc->pid, PT_AR_BSP, 0); + cfm.value = ptrace(PTRACE_PEEKUSER, proc->pid, PT_CFM, 0); + + /* The first 8 arguments are passed in regular registers + * (counting from R32), unless they are floating point values + * (the case in question here). In that case, up to the first + * 8 regular registers are still "allocated" for each of the + * first 8 parameters, but if a parameter is floating point, + * then the register is left unset and the parameter is passed + * in the first available floating-point register, counting + * from F8. + * + * Take func(int a, float f, int b, double d), for example. + * a - passed in R32 + * f - R33 left unset, value passed in F8 + * b - passed in R34 + * d - R35 left unset, value passed in F9 + * + * ltrace handles this by counting floating point arguments + * while parsing declarations. The "arg_num" in this routine + * (which is only called for floating point values) really + * means which floating point parameter we're looking for, + * ignoring everything else. + * + * Following the first 8 arguments, the remaining arguments + * are passed on the stack after a 16 byte scratch area + */ + if (type == LT_TOF_FUNCTION || type == LT_TOF_FUNCTIONR) { + if (arg_num < 8) { + reg.u.bits[0] = ptrace(PTRACE_PEEKUSER, proc->pid, + float_regs[arg_num], 0); + reg.u.bits[1] = ptrace(PTRACE_PEEKUSER, proc->pid, + float_regs[arg_num] + 0x8, 0); + return fpreg_to_double(®); + } else { + unsigned long sp = + ptrace(PTRACE_PEEKUSER, proc->pid, PT_R12, 0) + 16; + reg.u.bits[0] = ptrace(PTRACE_PEEKDATA, proc->pid, + sp + (8 * (arg_num - 8))); + reg.u.bits[0] = ptrace(PTRACE_PEEKDATA, proc->pid, + sp + (8 * (arg_num - 8)) + 0x8); + return fpreg_to_double(®); + } + } + + /* error if we get here */ + fprintf(stderr, "gimme_arg called with wrong arguments\n"); + exit(1); +} + +long +gimme_arg(enum tof type, Process *proc, int arg_num, arg_type_info *info) { + union { + long l; + float f; + double d; + } cvt; + + if (info->type == ARGTYPE_FLOAT) + cvt.f = gimme_float_arg(type, proc, info->u.float_info.float_index); + else if (info->type == ARGTYPE_DOUBLE) + cvt.d = gimme_float_arg(type, proc, info->u.double_info.float_index); + else + cvt.l = gimme_long_arg(type, proc, arg_num); + + return cvt.l; +} + +void +save_register_args(enum tof type, Process *proc) { +} + +void +get_arch_dep(Process *proc) { +} diff --git a/sysdeps/linux-gnu/m68k/Makefile b/sysdeps/linux-gnu/m68k/Makefile new file mode 100644 index 0000000..60d7531 --- /dev/null +++ b/sysdeps/linux-gnu/m68k/Makefile @@ -0,0 +1,10 @@ +OBJ = trace.o regs.o plt.o + +all: arch.o + +arch.o: $(OBJ) + $(CC) -nostdlib -r -o arch.o $(OBJ) + +clean: + $(RM) $(OBJ) arch.o + diff --git a/sysdeps/linux-gnu/m68k/arch.h b/sysdeps/linux-gnu/m68k/arch.h new file mode 100644 index 0000000..1790d09 --- /dev/null +++ b/sysdeps/linux-gnu/m68k/arch.h @@ -0,0 +1,6 @@ +#define BREAKPOINT_VALUE { 0x4e, 0x4f } +#define BREAKPOINT_LENGTH 2 +#define DECR_PC_AFTER_BREAK 2 + +#define LT_ELFCLASS ELFCLASS32 +#define LT_ELF_MACHINE EM_68K diff --git a/sysdeps/linux-gnu/m68k/plt.c b/sysdeps/linux-gnu/m68k/plt.c new file mode 100644 index 0000000..508d7fc --- /dev/null +++ b/sysdeps/linux-gnu/m68k/plt.c @@ -0,0 +1,13 @@ +#include +#include "common.h" + +GElf_Addr +arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela * rela) { + return lte->plt_addr + (ndx + 1) + * ((lte->ehdr.e_flags & EF_CPU32) ? 24 : 12); +} + +void * +sym2addr(Process *proc, struct library_symbol *sym) { + return sym->enter_addr; +} diff --git a/sysdeps/linux-gnu/m68k/ptrace.h b/sysdeps/linux-gnu/m68k/ptrace.h new file mode 100644 index 0000000..c3cbcb6 --- /dev/null +++ b/sysdeps/linux-gnu/m68k/ptrace.h @@ -0,0 +1 @@ +#include diff --git a/sysdeps/linux-gnu/m68k/regs.c b/sysdeps/linux-gnu/m68k/regs.c new file mode 100644 index 0000000..959a60e --- /dev/null +++ b/sysdeps/linux-gnu/m68k/regs.c @@ -0,0 +1,40 @@ +#include "config.h" + +#include +#include +#include + +#include "common.h" + +#if (!defined(PTRACE_PEEKUSER) && defined(PTRACE_PEEKUSR)) +# define PTRACE_PEEKUSER PTRACE_PEEKUSR +#endif + +#if (!defined(PTRACE_POKEUSER) && defined(PTRACE_POKEUSR)) +# define PTRACE_POKEUSER PTRACE_POKEUSR +#endif + +void * +get_instruction_pointer(Process *proc) { + return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, 4 * PT_PC, 0); +} + +void +set_instruction_pointer(Process *proc, void *addr) { + ptrace(PTRACE_POKEUSER, proc->pid, 4 * PT_PC, addr); +} + +void * +get_stack_pointer(Process *proc) { + return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, 4 * PT_USP, 0); +} + +void * +get_return_addr(Process *proc, void *stack_pointer) { + return (void *)ptrace(PTRACE_PEEKTEXT, proc->pid, stack_pointer, 0); +} + +void +set_return_addr(Process *proc, void *addr) { + ptrace(PTRACE_POKETEXT, proc->pid, proc->stack_pointer, addr); +} diff --git a/sysdeps/linux-gnu/m68k/signalent.h b/sysdeps/linux-gnu/m68k/signalent.h new file mode 100644 index 0000000..5395f82 --- /dev/null +++ b/sysdeps/linux-gnu/m68k/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 */ + "SIGSYS", /* 31 */ diff --git a/sysdeps/linux-gnu/m68k/syscallent.h b/sysdeps/linux-gnu/m68k/syscallent.h new file mode 100644 index 0000000..4d65b39 --- /dev/null +++ b/sysdeps/linux-gnu/m68k/syscallent.h @@ -0,0 +1,282 @@ + "0", /* 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 */ + "umount2", /* 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 */ + "110", /* 110 */ + "vhangup", /* 111 */ + "112", /* 112 */ + "113", /* 113 */ + "wait4", /* 114 */ + "swapoff", /* 115 */ + "sysinfo", /* 116 */ + "ipc", /* 117 */ + "fsync", /* 118 */ + "sigreturn", /* 119 */ + "clone", /* 120 */ + "setdomainname", /* 121 */ + "uname", /* 122 */ + "cacheflush", /* 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 */ + "setresuid", /* 164 */ + "getresuid", /* 165 */ + "getpagesize", /* 166 */ + "query_module", /* 167 */ + "poll", /* 168 */ + "nfsservctl", /* 169 */ + "setresgid", /* 170 */ + "getresgid", /* 171 */ + "prctl", /* 172 */ + "rt_sigreturn", /* 173 */ + "rt_sigaction", /* 174 */ + "rt_sigprocmask", /* 175 */ + "rt_sigpending", /* 176 */ + "rt_sigtimedwait", /* 177 */ + "rt_sigqueueinfo", /* 178 */ + "rt_sigsuspend", /* 179 */ + "pread64", /* 180 */ + "pwrite64", /* 181 */ + "lchown", /* 182 */ + "getcwd", /* 183 */ + "capget", /* 184 */ + "capset", /* 185 */ + "sigaltstack", /* 186 */ + "sendfile", /* 187 */ + "getpmsg", /* 188 */ + "putpmsg", /* 189 */ + "vfork", /* 190 */ + "ugetrlimit", /* 191 */ + "mmap2", /* 192 */ + "truncate64", /* 193 */ + "ftruncate64", /* 194 */ + "stat64", /* 195 */ + "lstat64", /* 196 */ + "fstat64", /* 197 */ + "chown32", /* 198 */ + "getuid32", /* 199 */ + "getgid32", /* 200 */ + "geteuid32", /* 201 */ + "getegid32", /* 202 */ + "setreuid32", /* 203 */ + "setregid32", /* 204 */ + "getgroups32", /* 205 */ + "setgroups32", /* 206 */ + "fchown32", /* 207 */ + "setresuid32", /* 208 */ + "getresuid32", /* 209 */ + "setresgid32", /* 210 */ + "getresgid32", /* 211 */ + "lchown32", /* 212 */ + "setuid32", /* 213 */ + "setgid32", /* 214 */ + "setfsuid32", /* 215 */ + "setfsgid32", /* 216 */ + "pivot_root", /* 217 */ + "218", /* 218 */ + "219", /* 219 */ + "getdents64", /* 220 */ + "gettid", /* 221 */ + "tkill", /* 222 */ + "setxattr", /* 223 */ + "lsetxattr", /* 224 */ + "fsetxattr", /* 225 */ + "getxattr", /* 226 */ + "lgetxattr", /* 227 */ + "fgetxattr", /* 228 */ + "listxattr", /* 229 */ + "llistxattr", /* 230 */ + "flistxattr", /* 231 */ + "removexattr", /* 232 */ + "lremovexattr", /* 233 */ + "fremovexattr", /* 234 */ + "futex", /* 235 */ + "sendfile64", /* 236 */ + "mincore", /* 237 */ + "madvise", /* 238 */ + "fcntl64", /* 239 */ + "readahead", /* 240 */ + "io_setup", /* 241 */ + "io_destroy", /* 242 */ + "io_getevents", /* 243 */ + "io_submit", /* 244 */ + "io_cancel", /* 245 */ + "fadvise64", /* 246 */ + "exit_group", /* 247 */ + "lookup_dcookie", /* 248 */ + "epoll_create", /* 249 */ + "epoll_ctl", /* 250 */ + "epoll_wait", /* 251 */ + "remap_file_pages", /* 252 */ + "set_tid_address", /* 253 */ + "timer_create", /* 254 */ + "timer_settime", /* 255 */ + "timer_gettime", /* 256 */ + "timer_getoverrun", /* 257 */ + "timer_delete", /* 258 */ + "clock_settime", /* 259 */ + "clock_gettime", /* 260 */ + "clock_getres", /* 261 */ + "clock_nanosleep", /* 262 */ + "statfs64", /* 263 */ + "fstatfs64", /* 264 */ + "tgkill", /* 265 */ + "utimes", /* 266 */ + "fadvise64_64", /* 267 */ + "mbind", /* 268 */ + "get_mempolicy", /* 269 */ + "set_mempolicy", /* 270 */ + "mq_open", /* 271 */ + "mq_unlink", /* 272 */ + "mq_timedsend", /* 273 */ + "mq_timedreceive", /* 274 */ + "mq_notify", /* 275 */ + "mq_getsetattr", /* 276 */ + "waitid", /* 277 */ + "vserver", /* 278 */ + "add_key", /* 279 */ + "request_key", /* 280 */ + "keyctl", /* 281 */ diff --git a/sysdeps/linux-gnu/m68k/trace.c b/sysdeps/linux-gnu/m68k/trace.c new file mode 100644 index 0000000..2f89fdf --- /dev/null +++ b/sysdeps/linux-gnu/m68k/trace.c @@ -0,0 +1,89 @@ +#include "config.h" + +#include +#include +#include +#include +#include + +#include "common.h" + +#if (!defined(PTRACE_PEEKUSER) && defined(PTRACE_PEEKUSR)) +# define PTRACE_PEEKUSER PTRACE_PEEKUSR +#endif + +#if (!defined(PTRACE_POKEUSER) && defined(PTRACE_POKEUSR)) +# define PTRACE_POKEUSER PTRACE_POKEUSR +#endif + +void +get_arch_dep(Process *proc) { +} + +/* Returns 1 if syscall, 2 if sysret, 0 otherwise. + */ +int +syscall_p(Process *proc, int status, int *sysnum) { + int depth; + + if (WIFSTOPPED(status) + && WSTOPSIG(status) == (SIGTRAP | proc->tracesysgood)) { + *sysnum = ptrace(PTRACE_PEEKUSER, proc->pid, 4 * PT_ORIG_D0, 0); + if (*sysnum == -1) + return 0; + if (*sysnum >= 0) { + depth = proc->callstack_depth; + if (depth > 0 && + proc->callstack[depth - 1].is_syscall && + proc->callstack[depth - 1].c_un.syscall == *sysnum) { + return 2; + } else { + return 1; + } + } + } + return 0; +} + +long +gimme_arg(enum tof type, Process *proc, int arg_num, arg_type_info *info) { + if (arg_num == -1) { /* return value */ + return ptrace(PTRACE_PEEKUSER, proc->pid, 4 * PT_D0, 0); + } + + if (type == LT_TOF_FUNCTION || type == LT_TOF_FUNCTIONR) { + return ptrace(PTRACE_PEEKTEXT, proc->pid, + proc->stack_pointer + 4 * (arg_num + 1), 0); + } else if (type == LT_TOF_SYSCALL || type == LT_TOF_SYSCALLR) { +#if 0 + switch (arg_num) { + case 0: + return ptrace(PTRACE_PEEKUSER, proc->pid, 4 * PT_D1, 0); + case 1: + return ptrace(PTRACE_PEEKUSER, proc->pid, 4 * PT_D2, 0); + case 2: + return ptrace(PTRACE_PEEKUSER, proc->pid, 4 * PT_D3, 0); + case 3: + return ptrace(PTRACE_PEEKUSER, proc->pid, 4 * PT_D4, 0); + case 4: + return ptrace(PTRACE_PEEKUSER, proc->pid, 4 * PT_D5, 0); + default: + fprintf(stderr, + "gimme_arg called with wrong arguments\n"); + exit(2); + } +#else + /* That hack works on m68k, too */ + return ptrace(PTRACE_PEEKUSER, proc->pid, 4 * arg_num, 0); +#endif + } else { + fprintf(stderr, "gimme_arg called with wrong arguments\n"); + exit(1); + } + + return 0; +} + +void +save_register_args(enum tof type, Process *proc) { +} diff --git a/sysdeps/linux-gnu/mipsel/Doxyfile b/sysdeps/linux-gnu/mipsel/Doxyfile new file mode 100644 index 0000000..b4f5eb2 --- /dev/null +++ b/sysdeps/linux-gnu/mipsel/Doxyfile @@ -0,0 +1,275 @@ +# Doxyfile 1.5.1 + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- +PROJECT_NAME = ltrace-mipsel +PROJECT_NUMBER = +OUTPUT_DIRECTORY = +CREATE_SUBDIRS = NO +OUTPUT_LANGUAGE = English +USE_WINDOWS_ENCODING = NO +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the +ALWAYS_DETAILED_SEC = NO +INLINE_INHERITED_MEMB = NO +FULL_PATH_NAMES = YES +STRIP_FROM_PATH = +STRIP_FROM_INC_PATH = +SHORT_NAMES = NO +JAVADOC_AUTOBRIEF = NO +MULTILINE_CPP_IS_BRIEF = NO +DETAILS_AT_TOP = NO +INHERIT_DOCS = YES +SEPARATE_MEMBER_PAGES = NO +TAB_SIZE = 8 +ALIASES = +OPTIMIZE_OUTPUT_FOR_C = NO +OPTIMIZE_OUTPUT_JAVA = NO +BUILTIN_STL_SUPPORT = NO +DISTRIBUTE_GROUP_DOC = NO +SUBGROUPING = YES +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- +EXTRACT_ALL = YES +EXTRACT_PRIVATE = YES +EXTRACT_STATIC = YES +EXTRACT_LOCAL_CLASSES = YES +EXTRACT_LOCAL_METHODS = YES +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = NO +INTERNAL_DOCS = NO +CASE_SENSE_NAMES = YES +HIDE_SCOPE_NAMES = NO +SHOW_INCLUDE_FILES = YES +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +SORT_BRIEF_DOCS = YES +SORT_BY_SCOPE_NAME = YES +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = YES +SHOW_DIRECTORIES = NO +FILE_VERSION_FILTER = +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +QUIET = NO +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_IF_DOC_ERROR = YES +WARN_NO_PARAMDOC = NO +WARN_FORMAT = "$file:$line: $text" +WARN_LOGFILE = +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- +INPUT = . +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.d \ + *.java \ + *.ii \ + *.ixx \ + *.ipp \ + *.i++ \ + *.inl \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.idl \ + *.odl \ + *.cs \ + *.php \ + *.php3 \ + *.inc \ + *.m \ + *.mm \ + *.dox \ + *.py \ + *.C \ + *.CC \ + *.C++ \ + *.II \ + *.I++ \ + *.H \ + *.HH \ + *.H++ \ + *.CS \ + *.PHP \ + *.PHP3 \ + *.M \ + *.MM \ + *.PY +RECURSIVE = NO +EXCLUDE = +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = +EXAMPLE_PATH = +EXAMPLE_PATTERNS = * +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = +INPUT_FILTER = +FILTER_PATTERNS = +FILTER_SOURCE_FILES = NO +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- +SOURCE_BROWSER = YES +INLINE_SOURCES = YES +STRIP_CODE_COMMENTS = YES +REFERENCED_BY_RELATION = YES +REFERENCES_RELATION = YES +REFERENCES_LINK_SOURCE = YES +USE_HTAGS = NO +VERBATIM_HEADERS = YES +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = NO +COLS_IN_ALPHA_INDEX = 5 +IGNORE_PREFIX = +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = html +HTML_FILE_EXTENSION = .html +HTML_HEADER = +HTML_FOOTER = +HTML_STYLESHEET = +HTML_ALIGN_MEMBERS = YES +GENERATE_HTMLHELP = NO +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +BINARY_TOC = NO +TOC_EXPAND = NO +DISABLE_INDEX = NO +ENUM_VALUES_PER_LINE = 4 +GENERATE_TREEVIEW = NO +TREEVIEW_WIDTH = 250 +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = NO +LATEX_OUTPUT = latex +LATEX_CMD_NAME = latex +MAKEINDEX_CMD_NAME = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4wide +EXTRA_PACKAGES = +LATEX_HEADER = +PDF_HYPERLINKS = NO +USE_PDFLATEX = NO +LATEX_BATCHMODE = NO +LATEX_HIDE_INDICES = NO +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = NO +RTF_OUTPUT = rtf +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = NO +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_LINKS = NO +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- +GENERATE_XML = NO +XML_OUTPUT = xml +XML_SCHEMA = +XML_DTD = +XML_PROGRAMLISTING = YES +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- +GENERATE_AUTOGEN_DEF = NO +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = NO +EXPAND_ONLY_PREDEF = NO +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- +TAGFILES = +GENERATE_TAGFILE = +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +PERL_PATH = /usr/bin/perl +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +CLASS_DIAGRAMS = YES +HIDE_UNDOC_RELATIONS = YES +HAVE_DOT = YES +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +GROUP_GRAPHS = YES +UML_LOOK = YES +TEMPLATE_RELATIONS = YES +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +CALL_GRAPH = YES +CALLER_GRAPH = YES +GRAPHICAL_HIERARCHY = YES +DIRECTORY_GRAPH = YES +DOT_IMAGE_FORMAT = png +DOT_PATH = +DOTFILE_DIRS = +MAX_DOT_GRAPH_WIDTH = 1024 +MAX_DOT_GRAPH_HEIGHT = 1024 +MAX_DOT_GRAPH_DEPTH = 1000 +DOT_TRANSPARENT = NO +DOT_MULTI_TARGETS = NO +GENERATE_LEGEND = YES +DOT_CLEANUP = NO +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- +SEARCHENGINE = NO diff --git a/sysdeps/linux-gnu/mipsel/Makefile b/sysdeps/linux-gnu/mipsel/Makefile new file mode 100644 index 0000000..44f4aae --- /dev/null +++ b/sysdeps/linux-gnu/mipsel/Makefile @@ -0,0 +1,22 @@ +.PHONY: all deps clean docs + +OBJ = trace.o regs.o plt.o +SRC=$(OBJ:.o=.c) + +all: arch.o + +deps: + $(CC) $(CFLAGS) $(CPPFLAGS) -M $(SRC) > .depends + +arch.o: $(OBJ) arch.h + $(CC) -nostdlib -r -o arch.o $(OBJ) + +clean: + -rm -f $(OBJ) arch.o + -rm -rf html + +docs: + doxygen + + +-include .depends diff --git a/sysdeps/linux-gnu/mipsel/arch.h b/sysdeps/linux-gnu/mipsel/arch.h new file mode 100644 index 0000000..dd0ca35 --- /dev/null +++ b/sysdeps/linux-gnu/mipsel/arch.h @@ -0,0 +1,9 @@ +#define BREAKPOINT_VALUE { 0x0d, 0x00, 0x00, 0x00 } +#define BREAKPOINT_LENGTH 4 +#define DECR_PC_AFTER_BREAK 0 + +#define LT_ELFCLASS ELFCLASS32 +#define LT_ELF_MACHINE EM_MIPS + +#define PLTs_INIT_BY_HERE "_start" +#define E_ENTRY_NAME "_start" diff --git a/sysdeps/linux-gnu/mipsel/mipsel.h b/sysdeps/linux-gnu/mipsel/mipsel.h new file mode 100644 index 0000000..a63cafd --- /dev/null +++ b/sysdeps/linux-gnu/mipsel/mipsel.h @@ -0,0 +1,11 @@ +#ifndef MIPSEL_h +#define MIPSEL_h +// linux-2.4.30/arch/mips/kernel/ptrace.c for these offsets. +#define off_v0 2 +#define off_pc 64 +#define off_a0 4 +#define off_a3 7 +#define off_lr 31 +#define off_sp 29 + +#endif // MIPSEL_h diff --git a/sysdeps/linux-gnu/mipsel/plt.c b/sysdeps/linux-gnu/mipsel/plt.c new file mode 100644 index 0000000..003171b --- /dev/null +++ b/sysdeps/linux-gnu/mipsel/plt.c @@ -0,0 +1,72 @@ +#include +#include +#include +#include "common.h" + +/** + \addtogroup mipsel + @{ + */ + +/** + \param lte Structure containing link table entry information + \param ndx Index into .dynsym + \param rela Not used. + \return Address of GOT table entry + + MIPS ABI Supplement: + + DT_PLTGOT This member holds the address of the .got section. + + DT_MIPS_SYMTABNO This member holds the number of entries in the + .dynsym section. + + DT_MIPS_LOCAL_GOTNO This member holds the number of local global + offset table entries. + + DT_MIPS_GOTSYM This member holds the index of the first dyamic + symbol table entry that corresponds to an entry in the gobal offset + table. + + Called by read_elf when building the symbol table. + + */ +GElf_Addr +arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela * rela) { + debug(1,"plt_addr %x ndx %#x",lte->pltgot_addr, ndx); + return lte->pltgot_addr + + sizeof(void *) * (lte->mips_local_gotno + (ndx - lte->mips_gotsym)); +} +/** + \param proc The process to work on. + \param sym The library symbol. + \return What is at the got table address + + The return value should be the address to put the breakpoint at. + + On the mips the library_symbol.enter_addr is the .got addr for the + symbol and the breakpoint.addr is the actual breakpoint address. + + Other processors use a plt, the mips is "special" in that is uses + the .got for both function and data relocations. Prior to program + startup, return 0. + + \warning MIPS relocations are lazy. This means that the breakpoint + may move after the first call. Ltrace dictionary routines don't + have a delete and symbol is one to one with breakpoint, so if the + breakpoint changes I just add a new breakpoint for the new address. + */ +void * +sym2addr(Process *proc, struct library_symbol *sym) { + long ret; + if(!proc->pid){ + return 0; + } + ret=ptrace(PTRACE_PEEKTEXT, proc->pid, sym->enter_addr, 0); + if(ret==-1){ + ret =0; + } + return (void *)ret;; +} + +/**@}*/ diff --git a/sysdeps/linux-gnu/mipsel/ptrace.h b/sysdeps/linux-gnu/mipsel/ptrace.h new file mode 100644 index 0000000..c3cbcb6 --- /dev/null +++ b/sysdeps/linux-gnu/mipsel/ptrace.h @@ -0,0 +1 @@ +#include diff --git a/sysdeps/linux-gnu/mipsel/regs.c b/sysdeps/linux-gnu/mipsel/regs.c new file mode 100644 index 0000000..a7a6de1 --- /dev/null +++ b/sysdeps/linux-gnu/mipsel/regs.c @@ -0,0 +1,76 @@ +#include "config.h" + +#include +#include +#include +#include +#include + +#include "common.h" +#include "mipsel.h" + +#if (!defined(PTRACE_PEEKUSER) && defined(PTRACE_PEEKUSR)) +# define PTRACE_PEEKUSER PTRACE_PEEKUSR +#endif + +#if (!defined(PTRACE_POKEUSER) && defined(PTRACE_POKEUSR)) +# define PTRACE_POKEUSER PTRACE_POKEUSR +#endif + +/** + \addtogroup mipsel + @{ + */ + + +/** + \param proc The process to work on. + \return The current instruction pointer. + */ +void * +get_instruction_pointer(Process *proc) { + return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, off_pc, 0); +} + +/** + \param proc The process to work on. + \param addr The address to set to. + + Called by \c continue_after_breakpoint(). + + \todo Our mips kernel ptrace doesn't support PTRACE_SINGLESTEP, so + we \c continue_process() after a breakpoint. Check if this is OK. + */ +void +set_instruction_pointer(Process *proc, void *addr) { + ptrace(PTRACE_POKEUSER, proc->pid, off_pc, addr); +} + +/** + \param proc The process to work on. + \return The current stack pointer. + */ +void * +get_stack_pointer(Process *proc) { + return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, off_sp, 0); +} + +/** + \param proc The process to work on. + \param stack_pointer The current stack pointer for proc + \return The current return address. + + Called by \c handle_breakpoint(). + + Mips uses r31 for the return address, so the stack_pointer is + unused. + */ +void * +get_return_addr(Process *proc, void *stack_pointer) { + return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, off_lr, 0); +} + +void +set_return_addr(Process *proc, void *addr) { + ptrace(PTRACE_POKEUSER, proc->pid, off_lr, addr); +} diff --git a/sysdeps/linux-gnu/mipsel/signalent.h b/sysdeps/linux-gnu/mipsel/signalent.h new file mode 100644 index 0000000..6bb1ff6 --- /dev/null +++ b/sysdeps/linux-gnu/mipsel/signalent.h @@ -0,0 +1,32 @@ +"SIG_0", /* 0 */ + "SIGHUP", // 1 /* Hangup (POSIX). */ + "SIGINT", // 2 /* Interrupt (ANSI). */ + "SIGQUIT", // 3 /* Quit (POSIX). */ + "SIGILL", // 4 /* Illegal instruction (ANSI). */ + "SIGTRAP", // 5 /* Trace trap (POSIX). */ + "SIGIOT", // 6 /* IOT trap (4.2 BSD). */ + "SIGEMT", // 7 + "SIGFPE", // 8 /* Floating-point exception (ANSI). */ + "SIGKILL", // 9 /* Kill, unblockable (POSIX). */ + "SIGBUS", // 10 /* BUS error (4.2 BSD). */ + "SIGSEGV", // 11 /* Segmentation violation (ANSI). */ + "SIGSYS", // 12 + "SIGPIPE", // 13 /* Broken pipe (POSIX). */ + "SIGALRM", // 14 /* Alarm clock (POSIX). */ + "SIGTERM", // 15 /* Termination (ANSI). */ + "SIGUSR1", // 16 /* User-defined signal 1 (POSIX). */ + "SIGUSR2", // 17 /* User-defined signal 2 (POSIX). */ + "SIGCHLD", // 18 /* Child status has changed (POSIX). */ + "SIGPWR", // 19 /* Power failure restart (System V). */ + "SIGWINCH", // 20 /* Window size change (4.3 BSD, Sun). */ + "SIGURG", // 21 /* Urgent condition on socket (4.2 BSD). */ + "SIGIO", // 22 /* I/O now possible (4.2 BSD). */ + "SIGSTOP", // 23 /* Stop, unblockable (POSIX). */ + "SIGTSTP", // 24 /* Keyboard stop (POSIX). */ + "SIGCONT", // 25 /* Continue (POSIX). */ + "SIGTTIN", // 26 /* Background read from tty (POSIX). */ + "SIGTTOU", // 27 /* Background write to tty (POSIX). */ + "SIGVTALRM", // 28 /* Virtual alarm clock (4.2 BSD). */ + "SIGPROF", // 29 /* Profiling alarm clock (4.2 BSD). */ + "SIGXCPU", // 30 /* CPU limit exceeded (4.2 BSD). */ + "SIGXFSZ", // 31 /* File size limit exceeded (4.2 BSD). */ diff --git a/sysdeps/linux-gnu/mipsel/syscallent.h b/sysdeps/linux-gnu/mipsel/syscallent.h new file mode 100644 index 0000000..bed43fe --- /dev/null +++ b/sysdeps/linux-gnu/mipsel/syscallent.h @@ -0,0 +1,241 @@ + "0", /*Linux + 0*/ + "exit", /*Linux + 1*/ + "fork", /*Linux + 2*/ + "read", /*Linux + 3*/ + "write", /*Linux + 4*/ + "open", /*Linux + 5*/ + "close", /*Linux + 6*/ + "waitpid", /*Linux + 7*/ + "creat", /*Linux + 8*/ + "link", /*Linux + 9*/ + "unlink", /*Linux + 10*/ + "execve", /*Linux + 11*/ + "chdir", /*Linux + 12*/ + "time", /*Linux + 13*/ + "mknod", /*Linux + 14*/ + "chmod", /*Linux + 15*/ + "lchown", /*Linux + 16*/ + "break", /*Linux + 17*/ + "unused18", /*Linux + 18*/ + "lseek", /*Linux + 19*/ + "getpid", /*Linux + 20*/ + "mount", /*Linux + 21*/ + "umount", /*Linux + 22*/ + "setuid", /*Linux + 23*/ + "getuid", /*Linux + 24*/ + "stime", /*Linux + 25*/ + "ptrace", /*Linux + 26*/ + "alarm", /*Linux + 27*/ + "unused28", /*Linux + 28*/ + "pause", /*Linux + 29*/ + "utime", /*Linux + 30*/ + "stty", /*Linux + 31*/ + "gtty", /*Linux + 32*/ + "access", /*Linux + 33*/ + "nice", /*Linux + 34*/ + "ftime", /*Linux + 35*/ + "sync", /*Linux + 36*/ + "kill", /*Linux + 37*/ + "rename", /*Linux + 38*/ + "mkdir", /*Linux + 39*/ + "rmdir", /*Linux + 40*/ + "dup", /*Linux + 41*/ + "pipe", /*Linux + 42*/ + "times", /*Linux + 43*/ + "prof", /*Linux + 44*/ + "brk", /*Linux + 45*/ + "setgid", /*Linux + 46*/ + "getgid", /*Linux + 47*/ + "signal", /*Linux + 48*/ + "geteuid", /*Linux + 49*/ + "getegid", /*Linux + 50*/ + "acct", /*Linux + 51*/ + "umount2", /*Linux + 52*/ + "lock", /*Linux + 53*/ + "ioctl", /*Linux + 54*/ + "fcntl", /*Linux + 55*/ + "mpx", /*Linux + 56*/ + "setpgid", /*Linux + 57*/ + "ulimit", /*Linux + 58*/ + "unused59", /*Linux + 59*/ + "umask", /*Linux + 60*/ + "chroot", /*Linux + 61*/ + "ustat", /*Linux + 62*/ + "dup2", /*Linux + 63*/ + "getppid", /*Linux + 64*/ + "getpgrp", /*Linux + 65*/ + "setsid", /*Linux + 66*/ + "sigaction", /*Linux + 67*/ + "sgetmask", /*Linux + 68*/ + "ssetmask", /*Linux + 69*/ + "setreuid", /*Linux + 70*/ + "setregid", /*Linux + 71*/ + "sigsuspend", /*Linux + 72*/ + "sigpending", /*Linux + 73*/ + "sethostname", /*Linux + 74*/ + "setrlimit", /*Linux + 75*/ + "getrlimit", /*Linux + 76*/ + "getrusage", /*Linux + 77*/ + "gettimeofday", /*Linux + 78*/ + "settimeofday", /*Linux + 79*/ + "getgroups", /*Linux + 80*/ + "setgroups", /*Linux + 81*/ + "reserved82", /*Linux + 82*/ + "symlink", /*Linux + 83*/ + "unused84", /*Linux + 84*/ + "readlink", /*Linux + 85*/ + "uselib", /*Linux + 86*/ + "swapon", /*Linux + 87*/ + "reboot", /*Linux + 88*/ + "readdir", /*Linux + 89*/ + "mmap", /*Linux + 90*/ + "munmap", /*Linux + 91*/ + "truncate", /*Linux + 92*/ + "ftruncate", /*Linux + 93*/ + "fchmod", /*Linux + 94*/ + "fchown", /*Linux + 95*/ + "getpriority", /*Linux + 96*/ + "setpriority", /*Linux + 97*/ + "profil", /*Linux + 98*/ + "statfs", /*Linux + 99*/ + "fstatfs", /*Linux + 100*/ + "ioperm", /*Linux + 101*/ + "socketcall", /*Linux + 102*/ + "syslog", /*Linux + 103*/ + "setitimer", /*Linux + 104*/ + "getitimer", /*Linux + 105*/ + "stat", /*Linux + 106*/ + "lstat", /*Linux + 107*/ + "fstat", /*Linux + 108*/ + "unused109", /*Linux + 109*/ + "iopl", /*Linux + 110*/ + "vhangup", /*Linux + 111*/ + "idle", /*Linux + 112*/ + "vm86", /*Linux + 113*/ + "wait4", /*Linux + 114*/ + "swapoff", /*Linux + 115*/ + "sysinfo", /*Linux + 116*/ + "ipc", /*Linux + 117*/ + "fsync", /*Linux + 118*/ + "sigreturn", /*Linux + 119*/ + "clone", /*Linux + 120*/ + "setdomainname", /*Linux + 121*/ + "uname", /*Linux + 122*/ + "modify_ldt", /*Linux + 123*/ + "adjtimex", /*Linux + 124*/ + "mprotect", /*Linux + 125*/ + "sigprocmask", /*Linux + 126*/ + "create_module", /*Linux + 127*/ + "init_module", /*Linux + 128*/ + "delete_module", /*Linux + 129*/ + "get_kernel_syms", /*Linux + 130*/ + "quotactl", /*Linux + 131*/ + "getpgid", /*Linux + 132*/ + "fchdir", /*Linux + 133*/ + "bdflush", /*Linux + 134*/ + "sysfs", /*Linux + 135*/ + "personality", /*Linux + 136*/ + "afs_syscall", /*Linux + 137*/ /* Syscall for Andrew File System */ + "setfsuid", /*Linux + 138*/ + "setfsgid", /*Linux + 139*/ + "_llseek", /*Linux + 140*/ + "getdents", /*Linux + 141*/ + "_newselect", /*Linux + 142*/ + "flock", /*Linux + 143*/ + "msync", /*Linux + 144*/ + "readv", /*Linux + 145*/ + "writev", /*Linux + 146*/ + "cacheflush", /*Linux + 147*/ + "cachectl", /*Linux + 148*/ + "sysmips", /*Linux + 149*/ + "unused150", /*Linux + 150*/ + "getsid", /*Linux + 151*/ + "fdatasync", /*Linux + 152*/ + "_sysctl", /*Linux + 153*/ + "mlock", /*Linux + 154*/ + "munlock", /*Linux + 155*/ + "mlockall", /*Linux + 156*/ + "munlockall", /*Linux + 157*/ + "sched_setparam", /*Linux + 158*/ + "sched_getparam", /*Linux + 159*/ + "sched_setscheduler", /*Linux + 160*/ + "sched_getscheduler", /*Linux + 161*/ + "sched_yield", /*Linux + 162*/ + "sched_get_priority_max", /*Linux + 163*/ + "sched_get_priority_min", /*Linux + 164*/ + "sched_rr_get_interval", /*Linux + 165*/ + "nanosleep", /*Linux + 166*/ + "mremap", /*Linux + 167*/ + "accept", /*Linux + 168*/ + "bind", /*Linux + 169*/ + "connect", /*Linux + 170*/ + "getpeername", /*Linux + 171*/ + "getsockname", /*Linux + 172*/ + "getsockopt", /*Linux + 173*/ + "listen", /*Linux + 174*/ + "recv", /*Linux + 175*/ + "recvfrom", /*Linux + 176*/ + "recvmsg", /*Linux + 177*/ + "send", /*Linux + 178*/ + "sendmsg", /*Linux + 179*/ + "sendto", /*Linux + 180*/ + "setsockopt", /*Linux + 181*/ + "shutdown", /*Linux + 182*/ + "socket", /*Linux + 183*/ + "socketpair", /*Linux + 184*/ + "setresuid", /*Linux + 185*/ + "getresuid", /*Linux + 186*/ + "query_module", /*Linux + 187*/ + "poll", /*Linux + 188*/ + "nfsservctl", /*Linux + 189*/ + "setresgid", /*Linux + 190*/ + "getresgid", /*Linux + 191*/ + "prctl", /*Linux + 192*/ + "rt_sigreturn", /*Linux + 193*/ + "rt_sigaction", /*Linux + 194*/ + "rt_sigprocmask", /*Linux + 195*/ + "rt_sigpending", /*Linux + 196*/ + "rt_sigtimedwait", /*Linux + 197*/ + "rt_sigqueueinfo", /*Linux + 198*/ + "rt_sigsuspend", /*Linux + 199*/ + "pread", /*Linux + 200*/ + "pwrite", /*Linux + 201*/ + "chown", /*Linux + 202*/ + "getcwd", /*Linux + 203*/ + "capget", /*Linux + 204*/ + "capset", /*Linux + 205*/ + "sigaltstack", /*Linux + 206*/ + "sendfile", /*Linux + 207*/ + "getpmsg", /*Linux + 208*/ + "putpmsg", /*Linux + 209*/ + "mmap2", /*Linux + 210*/ + "truncate64", /*Linux + 211*/ + "ftruncate64", /*Linux + 212*/ + "stat64", /*Linux + 213*/ + "lstat64", /*Linux + 214*/ + "fstat64", /*Linux + 215*/ + "pivot_root", /*Linux + 216*/ + "mincore", /*Linux + 217*/ + "madvise", /*Linux + 218*/ + "getdents64", /*Linux + 219*/ + "fcntl64", /*Linux + 220*/ + "security", /*Linux + 221*/ + "gettid", /*Linux + 222*/ + "readahead", /*Linux + 223*/ + "setxattr", /*Linux + 224*/ + "lsetxattr", /*Linux + 225*/ + "fsetxattr", /*Linux + 226*/ + "getxattr", /*Linux + 227*/ + "lgetxattr", /*Linux + 228*/ + "fgetxattr", /*Linux + 229*/ + "listxattr", /*Linux + 230*/ + "llistxattr", /*Linux + 231*/ + "flistxattr", /*Linux + 232*/ + "removexattr", /*Linux + 233*/ + "lremovexattr", /*Linux + 234*/ + "fremovexattr", /*Linux + 235*/ + "tkill", /*Linux + 236*/ + "sendfile64", /*Linux + 237*/ + "futex", /*Linux + 238*/ + "sched_setaffinity", /*Linux + 239*/ + "sched_getaffinity", /*Linux + 240*/ diff --git a/sysdeps/linux-gnu/mipsel/trace.c b/sysdeps/linux-gnu/mipsel/trace.c new file mode 100644 index 0000000..ff94930 --- /dev/null +++ b/sysdeps/linux-gnu/mipsel/trace.c @@ -0,0 +1,167 @@ +#include "config.h" + +#include +#include +#include +#include +#include +#include "debug.h" +#include "common.h" +#include "mipsel.h" +#if (!defined(PTRACE_PEEKUSER) && defined(PTRACE_PEEKUSR)) +# define PTRACE_PEEKUSER PTRACE_PEEKUSR +#endif + +#if (!defined(PTRACE_POKEUSER) && defined(PTRACE_POKEUSR)) +# define PTRACE_POKEUSER PTRACE_POKEUSR +#endif + + +/** + \addtogroup mipsel Mipsel specific functions. + + These are the functions that it looks like I need to implement in + order to get ltrace to work on our target. + + @{ + */ + +/** + \param proc The process that had an event. + + Called by \c next_event() right after the return from wait. + + Most targets just return here. A couple use proc->arch_ptr for a + private data area. + */ +void +get_arch_dep(Process *proc) { +} + +/** + \param proc Process that had event. + \param status From \c wait() + \param sysnum 0-based syscall number. + \return 1 if syscall, 2 if sysret, 0 otherwise. + + Called by \c next_event() after the call to get_arch_dep() + + It seems that the ptrace call trips twice on a system call, once + just before the system call and once when it returns. Both times, + the pc points at the instruction just after the mipsel "syscall" + instruction. + + There are several possiblities for system call sets, each is offset + by a base from the others. On our system, it looks like the base + for the system calls is 4000. + */ +int +syscall_p(Process *proc, int status, int *sysnum) { + if (WIFSTOPPED(status) + && WSTOPSIG(status) == (SIGTRAP | proc->tracesysgood)) { + /* get the user's pc (plus 8) */ + long pc = (long)get_instruction_pointer(proc); + /* fetch the SWI instruction */ + int insn = ptrace(PTRACE_PEEKTEXT, proc->pid, pc - 4, 0); + int num = ptrace(PTRACE_PEEKTEXT, proc->pid, pc - 8, 0); + + /* + On a mipsel, syscall looks like: + 24040fa1 li v0, 0x0fa1 # 4001 --> _exit syscall + 0000000c syscall + */ + if(insn!=0x0000000c){ + return 0; + } + + *sysnum = (num & 0xFFFF) - 4000; + /* if it is a syscall, return 1 or 2 */ + if (proc->callstack_depth > 0 && + proc->callstack[proc->callstack_depth - 1].is_syscall && + proc->callstack[proc->callstack_depth - 1].c_un.syscall == *sysnum) { + return 2; + } + + if (*sysnum >= 0) { + return 1; + } + } + return 0; +} +/** + \param type Function/syscall call or return. + \param proc The process that had an event. + \param arg_num -1 for return value, + \return The argument to fetch. + + A couple of assumptions. + +- Type is LT_TOF_FUNCTIONR or LT_TOF_SYSCALLR if arg_num==-1. These + types are only used in calls for output_right(), which only uses -1 + for arg_num. +- Type is LT_TOF_FUNCTION or LT_TOF_SYSCALL for args 0...4. +- I'm only displaying the first 4 args (Registers a0..a3). Good + enough for now. + + Mipsel conventions seem to be: +- syscall parameters: r4...r9 +- syscall return: if(!a3){ return v0;} else{ errno=v0;return -1;} +- function call: r4..r7. Not sure how to get arg number 5. +- function return: v0 + +The argument registers are wiped by a call, so it is a mistake to ask +for arguments on a return. If ltrace does this, we will need to cache +arguments somewhere on the call. + +I'm not doing any floating point support here. + +*/ +long +gimme_arg(enum tof type, Process *proc, int arg_num, arg_type_info *info) { + long ret; + debug(2,"type %d arg %d",type,arg_num); + if (type == LT_TOF_FUNCTION || type == LT_TOF_SYSCALL){ + if(arg_num <4){ + ret=ptrace(PTRACE_PEEKUSER,proc->pid,off_a0+arg_num,0); + debug(2,"ret = %#lx",ret); + return ret; + } else { + // If we need this, I think we can look at [sp+16] for arg_num==4. + CP; + return 0; + } + } + if(arg_num>=0){ + fprintf(stderr,"args on return?"); + } + if(type == LT_TOF_FUNCTIONR) { + return ptrace(PTRACE_PEEKUSER,proc->pid,off_v0,0); + } + if (type == LT_TOF_SYSCALLR) { + unsigned a3=ptrace(PTRACE_PEEKUSER, proc->pid,off_a3,0); + unsigned v0=ptrace(PTRACE_PEEKUSER, proc->pid,off_v0,0); + if(!a3){ + return v0; + } + return -1; + } + fprintf(stderr, "gimme_arg called with wrong arguments\n"); + return 0; +} + +/** + \param type Type of call/return + \param proc Process to work with. + + Called by \c output_left(), which is called on a syscall or + function. + + The other architectures stub this out, but seems to be the place to + stash off the arguments on a call so we have them on the return. + +*/ +void +save_register_args(enum tof type, Process *proc) { +} + +/**@}*/ diff --git a/sysdeps/linux-gnu/mksignalent b/sysdeps/linux-gnu/mksignalent new file mode 100755 index 0000000..316d81f --- /dev/null +++ b/sysdeps/linux-gnu/mksignalent @@ -0,0 +1,33 @@ +#!/usr/bin/awk -f + +# hack expression to generate arch/signalent.h from +# It reads from stdin and writes to stdout + +BEGIN { + max=0; +} + +{ + if (($1 ~ /^#define$/) && (!SIGNAL[$3]) && ($2 ~ /^SIG[A-Z]/) \ + && ($2 !~ /^SIGRTMIN$/) && ($2 !~ /^SIGRTMAX$/) && ($2 !~ /^SIGSTKSZ$/) \ + && ($3>=0) && ($3<=1000)) { + SIGNAL[$3]=$2; + if ($3 > max) { + max=$3; + } + } +} + +END { + for(i=0; i<=max; i++) { + if (!SIGNAL[i]) { + SIGNAL[i] = "SIG_" i; + } + pad = 16 - length(SIGNAL[i]); + if (pad<1) { + pad=1; + } + printf("\t\"%s\",%*s/* %d */\n", SIGNAL[i], pad, "", i); + } +} + diff --git a/sysdeps/linux-gnu/mksyscallent b/sysdeps/linux-gnu/mksyscallent new file mode 100755 index 0000000..e0c3ec7 --- /dev/null +++ b/sysdeps/linux-gnu/mksyscallent @@ -0,0 +1,45 @@ +#!/usr/bin/awk -f + +# hack expression to generate arch/syscallent.h from +# It reads from stdin and writes to stdout +# It should work OK on i386,m68k,arm,ia64 +# It does NOT work in mips, s390 +# It is untested in other architectures + +BEGIN { + max=0; + FS="[ \t\n()+]+"; +} + +{ + #debug + #printf("/%s/%s/%s/%s/\n", $1, $2, $3, $4); + if (($1 ~ /^#define$/) && ($2 ~ /^__NR_/)) { + #ia64 syscalls are > 1000 (lower for x86 compat) + if (($3>=0) && ($3<=2000)) { + SYSCALL[$3]=substr($2,6); + if ($3 > max) { + max=$3; + } + } else if (($3 ~ /^__NR_SYSCALL_BASE$/) && ($4>=0) && ($4<=1000)) { + SYSCALL[$4]=substr($2,6); + if ($4 > max) { + max=$4; + } + } + } +} + +END { + for(i=0; i<=max; i++) { + if (!SYSCALL[i]) { + SYSCALL[i] = i; + } + pad = 32 - length(SYSCALL[i]); + if (pad<1) { + pad=1; + } + printf("\t\"%s\",%*s/* %d */\n", SYSCALL[i], pad, "", i); + } +} + diff --git a/sysdeps/linux-gnu/mksyscallent_s390 b/sysdeps/linux-gnu/mksyscallent_s390 new file mode 100644 index 0000000..73416d9 --- /dev/null +++ b/sysdeps/linux-gnu/mksyscallent_s390 @@ -0,0 +1,38 @@ +#!/usr/bin/perl +# +# Generate syscall table for s390/s390x +# +# Use this on arch/s390/kernel/syscall.s after removing the first few +# nonsyscall lines. +# +# cat syscall.s | mksyscallent_s390 > syscalls31.h +# cat syscall.s | mksyscallent_s390 -x > syscalls64.h +# + +use Getopt::Std; +use integer; +getopts('x'); +$i = 0; +$s390x = 0; +$opt_x and $s390x = 1; + +while (<>) { + chomp; + + if ($s390x==1) { + s/^SYSCALL\([^,]*,//; + } else { + s/^SYSCALL\(//; + } + + s/,.*//; + s/^sys_//; + s/^s390[x]*_//; + s/_glue$//; + s/^ni_syscall.*/$i/i; + $len = 32 - length(); + $tab = $len / 8; + $space = $len % 8; + print " \"$_\"," ," " x $space , "\t" x $tab, " \/* $i \*\/\n"; + $i++; +} diff --git a/sysdeps/linux-gnu/ppc/Makefile b/sysdeps/linux-gnu/ppc/Makefile new file mode 100644 index 0000000..60d7531 --- /dev/null +++ b/sysdeps/linux-gnu/ppc/Makefile @@ -0,0 +1,10 @@ +OBJ = trace.o regs.o plt.o + +all: arch.o + +arch.o: $(OBJ) + $(CC) -nostdlib -r -o arch.o $(OBJ) + +clean: + $(RM) $(OBJ) arch.o + diff --git a/sysdeps/linux-gnu/ppc/arch.h b/sysdeps/linux-gnu/ppc/arch.h new file mode 100644 index 0000000..711b4a3 --- /dev/null +++ b/sysdeps/linux-gnu/ppc/arch.h @@ -0,0 +1,24 @@ +#define BREAKPOINT_VALUE { 0x7f, 0xe0, 0x00, 0x08 } +#define BREAKPOINT_LENGTH 4 +#define DECR_PC_AFTER_BREAK 0 + +#define LT_ELFCLASS ELFCLASS32 +#define LT_ELF_MACHINE EM_PPC + +#ifdef __powerpc64__ // Says 'ltrace' is 64 bits, says nothing about target. +#define LT_ELFCLASS2 ELFCLASS64 +#define LT_ELF_MACHINE2 EM_PPC64 +#define ARCH_SUPPORTS_OPD +#endif + +#define PLT_REINITALISATION_BP "_start" + +/* Start of arch-specific functions. */ +#define ARCH_HAVE_UMOVELONG + +#define PPC_NOP { 0x60, 0x00, 0x00, 0x00 } +#define PPC_NOP_LENGTH 4 + +#if (PPC_NOP_LENGTH != BREAKPOINT_LENGTH) +#error "Length of the breakpoint value not equal to the length of a nop instruction" +#endif diff --git a/sysdeps/linux-gnu/ppc/plt.c b/sysdeps/linux-gnu/ppc/plt.c new file mode 100644 index 0000000..31830fb --- /dev/null +++ b/sysdeps/linux-gnu/ppc/plt.c @@ -0,0 +1,54 @@ +#include +#include "common.h" + +GElf_Addr +arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela * rela) { + return rela->r_offset; +} + +void * +sym2addr(Process *proc, struct library_symbol *sym) { + void *addr = sym->enter_addr; + long pt_ret; + + debug(3, 0); + + if (sym->plt_type != LS_TOPLT_POINT) { + return addr; + } + + if (proc->pid == 0) { + return 0; + } + + if (options.debug >= 3) { + xinfdump(proc->pid, (void *)(((long)addr-32)&0xfffffff0), + sizeof(void*)*8); + } + + // On a PowerPC-64 system, a plt is three 64-bit words: the first is the + // 64-bit address of the routine. Before the PLT has been initialized, + // this will be 0x0. In fact, the symbol table won't have the plt's + // address even. Ater the PLT has been initialized, but before it has + // been resolved, the first word will be the address of the function in + // the dynamic linker that will reslove the PLT. After the PLT is + // resolved, this will will be the address of the routine whose symbol + // is in the symbol table. + + // On a PowerPC-32 system, there are two types of PLTs: secure (new) and + // non-secure (old). For the secure case, the PLT is simply a pointer + // and we can treat it much as we do for the PowerPC-64 case. For the + // non-secure case, the PLT is executable code and we can put the + // break-point right in the PLT. + + pt_ret = ptrace(PTRACE_PEEKTEXT, proc->pid, addr, 0); + + if (proc->mask_32bit) { + // Assume big-endian. + addr = (void *)((pt_ret >> 32) & 0xffffffff); + } else { + addr = (void *)pt_ret; + } + + return addr; +} diff --git a/sysdeps/linux-gnu/ppc/ptrace.h b/sysdeps/linux-gnu/ppc/ptrace.h new file mode 100644 index 0000000..c3cbcb6 --- /dev/null +++ b/sysdeps/linux-gnu/ppc/ptrace.h @@ -0,0 +1 @@ +#include diff --git a/sysdeps/linux-gnu/ppc/regs.c b/sysdeps/linux-gnu/ppc/regs.c new file mode 100644 index 0000000..eca58ff --- /dev/null +++ b/sysdeps/linux-gnu/ppc/regs.c @@ -0,0 +1,47 @@ +#include "config.h" + +#include +#include +#include + +#include "common.h" + +#if (!defined(PTRACE_PEEKUSER) && defined(PTRACE_PEEKUSR)) +# define PTRACE_PEEKUSER PTRACE_PEEKUSR +#endif + +#if (!defined(PTRACE_POKEUSER) && defined(PTRACE_POKEUSR)) +# define PTRACE_POKEUSER PTRACE_POKEUSR +#endif + +void * +get_instruction_pointer(Process *proc) { + return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, sizeof(long)*PT_NIP, 0); +} + +void +set_instruction_pointer(Process *proc, void *addr) { + ptrace(PTRACE_POKEUSER, proc->pid, sizeof(long)*PT_NIP, addr); +} + +void * +get_stack_pointer(Process *proc) { + return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, sizeof(long)*PT_R1, 0); +} + +void * +get_return_addr(Process *proc, void *stack_pointer) { + return (void *)ptrace(PTRACE_PEEKUSER, proc->pid, sizeof(long)*PT_LNK, 0); +} + +void +set_return_addr(Process *proc, void *addr) { + ptrace(PTRACE_POKEUSER, proc->pid, sizeof(long)*PT_LNK, addr); +} + +/* Grab the value of CTR registers. */ +void * +get_count_register (Process *proc) { + return (void *) ptrace (PTRACE_PEEKUSER, proc->pid, + sizeof (long) * PT_CTR, 0); +} diff --git a/sysdeps/linux-gnu/ppc/signalent.h b/sysdeps/linux-gnu/ppc/signalent.h new file mode 100644 index 0000000..d58a36c --- /dev/null +++ b/sysdeps/linux-gnu/ppc/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 */ + "SIGSYS", /* 31 */ diff --git a/sysdeps/linux-gnu/ppc/syscallent.h b/sysdeps/linux-gnu/ppc/syscallent.h new file mode 100644 index 0000000..5ce5739 --- /dev/null +++ b/sysdeps/linux-gnu/ppc/syscallent.h @@ -0,0 +1,272 @@ +"0", /* 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 */ + "lchown", /* 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 */ + "umount2", /* 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 */ + "setresuid", /* 164 */ + "getresuid", /* 165 */ + "query_module", /* 166 */ + "poll", /* 167 */ + "nfsservctl", /* 168 */ + "setresgid", /* 169 */ + "getresgid", /* 170 */ + "prctl", /* 171 */ + "rt_sigreturn", /* 172 */ + "rt_sigaction", /* 173 */ + "rt_sigprocmask", /* 174 */ + "rt_sigpending", /* 175 */ + "rt_sigtimedwait", /* 176 */ + "rt_sigqueueinfo", /* 177 */ + "rt_sigsuspend", /* 178 */ + "pread", /* 179 */ + "pwrite", /* 180 */ + "chown", /* 181 */ + "getcwd", /* 182 */ + "capget", /* 183 */ + "capset", /* 184 */ + "sigaltstack", /* 185 */ + "sendfile", /* 186 */ + "getpmsg", /* 187 */ + "putpmsg", /* 188 */ + "vfork", /* 189 */ + "ugetrlimit", /* 190 */ + "readahead", /* 191 */ + "mmap2", /* 192 */ + "truncate64", /* 193 */ + "ftruncate64", /* 194 */ + "stat64", /* 195 */ + "lstat64", /* 196 */ + "fstat64", /* 197 */ + "pciconfig_read", /* 198 */ + "pciconfig_write", /* 199 */ + "pciconfig_iobase", /* 200 */ + "multiplexer", /* 201 */ + "getdents64", /* 202 */ + "pivot_root", /* 203 */ + "fcntl64", /* 204 */ + "madvise", /* 205 */ + "mincore", /* 206 */ + "gettid", /* 207 */ + "tkill", /* 208 */ + "setxattr", /* 209 */ + "lsetxattr", /* 210 */ + "fsetxattr", /* 211 */ + "getxattr", /* 212 */ + "lgetxattr", /* 213 */ + "fgetxattr", /* 214 */ + "listxattr", /* 215 */ + "llistxattr", /* 216 */ + "flistxattr", /* 217 */ + "removexattr", /* 218 */ + "lremovexattr", /* 219 */ + "fremovexattr", /* 220 */ + "futex", /* 221 */ + "sched_setaffinity", /* 222 */ + "sched_getaffinity", /* 223 */ + "224", /* 224 */ + "tuxcall", /* 225 */ + "sendfile64", /* 226 */ + "io_setup", /* 227 */ + "io_destroy", /* 228 */ + "io_getevents", /* 229 */ + "io_submit", /* 230 */ + "io_cancel", /* 231 */ + "set_tid_address", /* 232 */ + "fadvise64", /* 233 */ + "exit_group", /* 234 */ + "lookup_dcookie", /* 235 */ + "epoll_create", /* 236 */ + "epoll_ctl", /* 237 */ + "epoll_wait", /* 238 */ + "remap_file_pages", /* 239 */ + "timer_create", /* 240 */ + "timer_settime", /* 241 */ + "timer_gettime", /* 242 */ + "timer_getoverrun", /* 243 */ + "timer_delete", /* 244 */ + "clock_settime", /* 245 */ + "clock_gettime", /* 246 */ + "clock_getres", /* 247 */ + "clock_nanosleep", /* 248 */ + "swapcontext", /* 249 */ + "tgkill", /* 250 */ + "utimes", /* 251 */ + "statfs64", /* 252 */ + "fstatfs64", /* 253 */ + "fadvise64_64", /* 254 */ + "rtas", /* 255 */ + "mq_open", /* 262 */ + "mq_unlink", /* 263 */ + "mq_timedsend", /* 264 */ + "mq_timedreceive", /* 265 */ + "mq_notify", /* 266 */ + "mq_getsetattr", /* 267 */ + "kexec_load", /* 268 */ + "add_key", /* 269 */ + "request_key", /* 270 */ + "keyctl", /* 271 */ + "waitid", /* 272 */ + "ioprio_set", /* 273 */ + "ioprio_get", /* 274 */ + "inotify_init", /* 275 */ + "inotify_add_watch", /* 276 */ + "inotify_rm_watch", /* 277 */ diff --git a/sysdeps/linux-gnu/ppc/trace.c b/sysdeps/linux-gnu/ppc/trace.c new file mode 100644 index 0000000..81fb71d --- /dev/null +++ b/sysdeps/linux-gnu/ppc/trace.c @@ -0,0 +1,155 @@ +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" + +#if (!defined(PTRACE_PEEKUSER) && defined(PTRACE_PEEKUSR)) +# define PTRACE_PEEKUSER PTRACE_PEEKUSR +#endif + +#if (!defined(PTRACE_POKEUSER) && defined(PTRACE_POKEUSR)) +# define PTRACE_POKEUSER PTRACE_POKEUSR +#endif + +void +get_arch_dep(Process *proc) { +#ifdef __powerpc64__ + if (proc->arch_ptr) + return; + proc->mask_32bit = (proc->e_machine == EM_PPC); + proc->arch_ptr = (void *)1; +#endif +} + +/* Returns 1 if syscall, 2 if sysret, 0 otherwise. */ +#define SYSCALL_INSN 0x44000002 + +unsigned int greg = 3; +unsigned int freg = 1; +unsigned int vreg = 2; + +int +syscall_p(Process *proc, int status, int *sysnum) { + if (WIFSTOPPED(status) + && WSTOPSIG(status) == (SIGTRAP | proc->tracesysgood)) { + long pc = (long)get_instruction_pointer(proc); + int insn = + (int)ptrace(PTRACE_PEEKTEXT, proc->pid, pc - sizeof(long), + 0); + + if (insn == SYSCALL_INSN) { + *sysnum = + (int)ptrace(PTRACE_PEEKUSER, proc->pid, + sizeof(long) * PT_R0, 0); + if (proc->callstack_depth > 0 && + proc->callstack[proc->callstack_depth - 1].is_syscall && + proc->callstack[proc->callstack_depth - 1].c_un.syscall == *sysnum) { + return 2; + } + return 1; + } + } + return 0; +} + +/* Grab functions arguments based on the PPC64 ABI. */ +long +gimme_arg(enum tof type, Process *proc, int arg_num, arg_type_info *info) { + long data; + + if (type == LT_TOF_FUNCTIONR) { + if (info->type == ARGTYPE_FLOAT || info->type == ARGTYPE_DOUBLE) + return ptrace (PTRACE_PEEKUSER, proc->pid, + sizeof (long) * (PT_FPR0 + 1), 0); + else + return ptrace (PTRACE_PEEKUSER, proc->pid, + sizeof (long) * PT_R3, 0); + } + + /* Check if we're entering a new function call to list parameters. If + so, initialize the register control variables to keep track of where + the parameters were stored. */ + if (type == LT_TOF_FUNCTION && arg_num == 0) { + /* Initialize the set of registrers for parameter passing. */ + greg = 3; + freg = 1; + vreg = 2; + } + + if (info->type == ARGTYPE_FLOAT || info->type == ARGTYPE_DOUBLE) { + if (freg <= 13 || (proc->mask_32bit && freg <= 8)) { + data = ptrace (PTRACE_PEEKUSER, proc->pid, + sizeof (long) * (PT_FPR0 + freg), 0); + + if (info->type == ARGTYPE_FLOAT) { + /* float values passed in FP registers are automatically + promoted to double. We need to convert it back to float + before printing. */ + union { long val; float fval; double dval; } cvt; + cvt.val = data; + cvt.fval = (float) cvt.dval; + data = cvt.val; + } + + freg++; + greg++; + + return data; + } + } + else if (greg <= 10) { + data = ptrace (PTRACE_PEEKUSER, proc->pid, + sizeof (long) * greg, 0); + greg++; + + return data; + } + else + return ptrace (PTRACE_PEEKDATA, proc->pid, + proc->stack_pointer + sizeof (long) * + (arg_num - 8), 0); + + return 0; +} + +void +save_register_args(enum tof type, Process *proc) { +} + +/* Read a single long from the process's memory address 'addr'. */ +int +arch_umovelong (Process *proc, void *addr, long *result, arg_type_info *info) { + long pointed_to; + + errno = 0; + + pointed_to = ptrace (PTRACE_PEEKTEXT, proc->pid, addr, 0); + + if (pointed_to == -1 && errno) + return -errno; + + /* Since int's are 4-bytes (long is 8-bytes) in length for ppc64, we + need to shift the long values returned by ptrace to end up with + the correct value. */ + + if (info) { + if (info->type == ARGTYPE_INT || (proc->mask_32bit && (info->type == ARGTYPE_POINTER + || info->type == ARGTYPE_STRING))) { + pointed_to = pointed_to >> 32; + + /* Make sure we have nothing in the upper word so we can + do a explicit cast from long to int later in the code. */ + pointed_to &= 0x00000000ffffffff; + } + } + + *result = pointed_to; + return 0; +} diff --git a/sysdeps/linux-gnu/proc.c b/sysdeps/linux-gnu/proc.c new file mode 100644 index 0000000..4251c1d --- /dev/null +++ b/sysdeps/linux-gnu/proc.c @@ -0,0 +1,36 @@ +#include "config.h" + +#include +#include +#include +#include +#include + +/* /proc/pid doesn't exist just after the fork, and sometimes `ltrace' + * couldn't open it to find the executable. So it may be necessary to + * have a bit delay + */ + +#define MAX_DELAY 100000 /* 100000 microseconds = 0.1 seconds */ + +/* + * Returns a (malloc'd) file name corresponding to a running pid + */ +char * +pid2name(pid_t pid) { + char proc_exe[1024]; + + if (!kill(pid, 0)) { + int delay = 0; + + sprintf(proc_exe, "/proc/%d/exe", pid); + + while (delay < MAX_DELAY) { + if (!access(proc_exe, F_OK)) { + return strdup(proc_exe); + } + delay += 1000; /* 1 milisecond */ + } + } + return NULL; +} diff --git a/sysdeps/linux-gnu/s390/Makefile b/sysdeps/linux-gnu/s390/Makefile new file mode 100644 index 0000000..cea1b45 --- /dev/null +++ b/sysdeps/linux-gnu/s390/Makefile @@ -0,0 +1,13 @@ +# +# S/390 version +# Copyright (C) 2001 IBM Poughkeepsie, IBM Corporation +# +OBJ = trace.o regs.o plt.o + +all: arch.o + +arch.o: $(OBJ) + $(CC) -nostdlib -r -o arch.o $(OBJ) + +clean: + $(RM) $(OBJ) arch.o diff --git a/sysdeps/linux-gnu/s390/arch.h b/sysdeps/linux-gnu/s390/arch.h new file mode 100644 index 0000000..03690b8 --- /dev/null +++ b/sysdeps/linux-gnu/s390/arch.h @@ -0,0 +1,18 @@ +/* +** S/390 version +** (C) Copyright 2001 IBM Poughkeepsie, IBM Corporation +*/ + +#define BREAKPOINT_VALUE { 0x00, 0x01 } +#define BREAKPOINT_LENGTH 2 +#define DECR_PC_AFTER_BREAK 2 + +#ifdef __s390x__ +#define LT_ELFCLASS ELFCLASS64 +#define LT_ELF_MACHINE EM_S390 +#define LT_ELFCLASS2 ELFCLASS32 +#define LT_ELF_MACHINE2 EM_S390 +#else +#define LT_ELFCLASS ELFCLASS32 +#define LT_ELF_MACHINE EM_S390 +#endif diff --git a/sysdeps/linux-gnu/s390/plt.c b/sysdeps/linux-gnu/s390/plt.c new file mode 100644 index 0000000..85a1dd1 --- /dev/null +++ b/sysdeps/linux-gnu/s390/plt.c @@ -0,0 +1,12 @@ +#include +#include "common.h" + +GElf_Addr +arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela * rela) { + return lte->plt_addr + (ndx + 1) * 32; +} + +void * +sym2addr(Process *proc, struct library_symbol *sym) { + return sym->enter_addr; +} diff --git a/sysdeps/linux-gnu/s390/ptrace.h b/sysdeps/linux-gnu/s390/ptrace.h new file mode 100644 index 0000000..c3cbcb6 --- /dev/null +++ b/sysdeps/linux-gnu/s390/ptrace.h @@ -0,0 +1 @@ +#include diff --git a/sysdeps/linux-gnu/s390/regs.c b/sysdeps/linux-gnu/s390/regs.c new file mode 100644 index 0000000..169893e --- /dev/null +++ b/sysdeps/linux-gnu/s390/regs.c @@ -0,0 +1,75 @@ +/* +** S/390 version +** Copyright (C) 2001 IBM Poughkeepsie, IBM Corporation +*/ + +#include "config.h" + +#include +#include +#include + +#include "common.h" + +#if (!defined(PTRACE_PEEKUSER) && defined(PTRACE_PEEKUSR)) +# define PTRACE_PEEKUSER PTRACE_PEEKUSR +#endif + +#if (!defined(PTRACE_POKEUSER) && defined(PTRACE_POKEUSR)) +# define PTRACE_POKEUSER PTRACE_POKEUSR +#endif + +#ifdef __s390x__ +#define PSW_MASK 0xffffffffffffffff +#define PSW_MASK31 0x7fffffff +#else +#define PSW_MASK 0x7fffffff +#endif + +void * +get_instruction_pointer(Process *proc) { + long ret = ptrace(PTRACE_PEEKUSER, proc->pid, PT_PSWADDR, 0) & PSW_MASK; +#ifdef __s390x__ + if (proc->mask_32bit) + ret &= PSW_MASK31; +#endif + return (void *)ret; +} + +void +set_instruction_pointer(Process *proc, void *addr) { +#ifdef __s390x__ + if (proc->mask_32bit) + addr = (void *)((long)addr & PSW_MASK31); +#endif + ptrace(PTRACE_POKEUSER, proc->pid, PT_PSWADDR, addr); +} + +void * +get_stack_pointer(Process *proc) { + long ret = ptrace(PTRACE_PEEKUSER, proc->pid, PT_GPR15, 0) & PSW_MASK; +#ifdef __s390x__ + if (proc->mask_32bit) + ret &= PSW_MASK31; +#endif + return (void *)ret; +} + +void * +get_return_addr(Process *proc, void *stack_pointer) { + long ret = ptrace(PTRACE_PEEKUSER, proc->pid, PT_GPR14, 0) & PSW_MASK; +#ifdef __s390x__ + if (proc->mask_32bit) + ret &= PSW_MASK31; +#endif + return (void *)ret; +} + +void +set_return_addr(Process *proc, void *addr) { +#ifdef __s390x__ + if (proc->mask_32bit) + addr = (void *)((long)addr & PSW_MASK31); +#endif + ptrace(PTRACE_POKEUSER, proc->pid, PT_GPR14, addr); +} diff --git a/sysdeps/linux-gnu/s390/signalent.h b/sysdeps/linux-gnu/s390/signalent.h new file mode 100644 index 0000000..35b74f1 --- /dev/null +++ b/sysdeps/linux-gnu/s390/signalent.h @@ -0,0 +1,33 @@ +"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 */ + "SIGRTMIN", /* 32 */ diff --git a/sysdeps/linux-gnu/s390/signalent1.h b/sysdeps/linux-gnu/s390/signalent1.h new file mode 100644 index 0000000..b5b6ca8 --- /dev/null +++ b/sysdeps/linux-gnu/s390/signalent1.h @@ -0,0 +1 @@ +#include "s390/signalent.h" diff --git a/sysdeps/linux-gnu/s390/syscallent.h b/sysdeps/linux-gnu/s390/syscallent.h new file mode 100644 index 0000000..5a35d93 --- /dev/null +++ b/sysdeps/linux-gnu/s390/syscallent.h @@ -0,0 +1,5 @@ +#ifdef __s390x__ +#include "s390/syscalls64.h" +#else +#include "s390/syscalls31.h" +#endif diff --git a/sysdeps/linux-gnu/s390/syscallent1.h b/sysdeps/linux-gnu/s390/syscallent1.h new file mode 100644 index 0000000..c9fdc81 --- /dev/null +++ b/sysdeps/linux-gnu/s390/syscallent1.h @@ -0,0 +1 @@ +#include "s390/syscalls31.h" diff --git a/sysdeps/linux-gnu/s390/syscalls31.h b/sysdeps/linux-gnu/s390/syscalls31.h new file mode 100644 index 0000000..42631eb --- /dev/null +++ b/sysdeps/linux-gnu/s390/syscalls31.h @@ -0,0 +1,310 @@ + "0", /* 0 */ + "exit", /* 1 */ + "fork", /* 2 */ + "read", /* 3 */ + "write", /* 4 */ + "open", /* 5 */ + "close", /* 6 */ + "restart_syscall", /* 7 */ + "creat", /* 8 */ + "link", /* 9 */ + "unlink", /* 10 */ + "execve", /* 11 */ + "chdir", /* 12 */ + "time", /* 13 */ + "mknod", /* 14 */ + "chmod", /* 15 */ + "lchown16", /* 16 */ + "17", /* 17 */ + "18", /* 18 */ + "lseek", /* 19 */ + "getpid", /* 20 */ + "mount", /* 21 */ + "oldumount", /* 22 */ + "setuid16", /* 23 */ + "getuid16", /* 24 */ + "stime", /* 25 */ + "ptrace", /* 26 */ + "alarm", /* 27 */ + "28", /* 28 */ + "pause", /* 29 */ + "utime", /* 30 */ + "31", /* 31 */ + "32", /* 32 */ + "access", /* 33 */ + "nice", /* 34 */ + "35", /* 35 */ + "sync", /* 36 */ + "kill", /* 37 */ + "rename", /* 38 */ + "mkdir", /* 39 */ + "rmdir", /* 40 */ + "dup", /* 41 */ + "pipe", /* 42 */ + "times", /* 43 */ + "44", /* 44 */ + "brk", /* 45 */ + "setgid16", /* 46 */ + "getgid16", /* 47 */ + "signal", /* 48 */ + "geteuid16", /* 49 */ + "getegid16", /* 50 */ + "acct", /* 51 */ + "umount", /* 52 */ + "53", /* 53 */ + "ioctl", /* 54 */ + "fcntl", /* 55 */ + "56", /* 56 */ + "setpgid", /* 57 */ + "58", /* 58 */ + "59", /* 59 */ + "umask", /* 60 */ + "chroot", /* 61 */ + "ustat", /* 62 */ + "dup2", /* 63 */ + "getppid", /* 64 */ + "getpgrp", /* 65 */ + "setsid", /* 66 */ + "sigaction", /* 67 */ + "68", /* 68 */ + "69", /* 69 */ + "setreuid16", /* 70 */ + "setregid16", /* 71 */ + "sigsuspend", /* 72 */ + "sigpending", /* 73 */ + "sethostname", /* 74 */ + "setrlimit", /* 75 */ + "old_getrlimit", /* 76 */ + "getrusage", /* 77 */ + "gettimeofday", /* 78 */ + "settimeofday", /* 79 */ + "getgroups16", /* 80 */ + "setgroups16", /* 81 */ + "82", /* 82 */ + "symlink", /* 83 */ + "84", /* 84 */ + "readlink", /* 85 */ + "uselib", /* 86 */ + "swapon", /* 87 */ + "reboot", /* 88 */ + "89", /* 89 */ + "old_mmap", /* 90 */ + "munmap", /* 91 */ + "truncate", /* 92 */ + "ftruncate", /* 93 */ + "fchmod", /* 94 */ + "fchown16", /* 95 */ + "getpriority", /* 96 */ + "setpriority", /* 97 */ + "98", /* 98 */ + "statfs", /* 99 */ + "fstatfs", /* 100 */ + "101", /* 101 */ + "socketcall", /* 102 */ + "syslog", /* 103 */ + "setitimer", /* 104 */ + "getitimer", /* 105 */ + "newstat", /* 106 */ + "newlstat", /* 107 */ + "newfstat", /* 108 */ + "109", /* 109 */ + "lookup_dcookie", /* 110 */ + "vhangup", /* 111 */ + "112", /* 112 */ + "113", /* 113 */ + "wait4", /* 114 */ + "swapoff", /* 115 */ + "sysinfo", /* 116 */ + "ipc", /* 117 */ + "fsync", /* 118 */ + "sigreturn", /* 119 */ + "clone", /* 120 */ + "setdomainname", /* 121 */ + "newuname", /* 122 */ + "123", /* 123 */ + "adjtimex", /* 124 */ + "mprotect", /* 125 */ + "sigprocmask", /* 126 */ + "127", /* 127 */ + "init_module", /* 128 */ + "delete_module", /* 129 */ + "130", /* 130 */ + "quotactl", /* 131 */ + "getpgid", /* 132 */ + "fchdir", /* 133 */ + "bdflush", /* 134 */ + "sysfs", /* 135 */ + "personality", /* 136 */ + "137", /* 137 */ + "setfsuid16", /* 138 */ + "setfsgid16", /* 139 */ + "llseek", /* 140 */ + "getdents", /* 141 */ + "select", /* 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 */ + "setresuid16", /* 164 */ + "getresuid16", /* 165 */ + "166", /* 166 */ + "167", /* 167 */ + "poll", /* 168 */ + "nfsservctl", /* 169 */ + "setresgid16", /* 170 */ + "getresgid16", /* 171 */ + "prctl", /* 172 */ + "rt_sigreturn", /* 173 */ + "rt_sigaction", /* 174 */ + "rt_sigprocmask", /* 175 */ + "rt_sigpending", /* 176 */ + "rt_sigtimedwait", /* 177 */ + "rt_sigqueueinfo", /* 178 */ + "rt_sigsuspend", /* 179 */ + "pread64", /* 180 */ + "pwrite64", /* 181 */ + "chown16", /* 182 */ + "getcwd", /* 183 */ + "capget", /* 184 */ + "capset", /* 185 */ + "sigaltstack", /* 186 */ + "sendfile", /* 187 */ + "188", /* 188 */ + "189", /* 189 */ + "vfork", /* 190 */ + "getrlimit", /* 191 */ + "mmap2", /* 192 */ + "truncate64", /* 193 */ + "ftruncate64", /* 194 */ + "stat64", /* 195 */ + "lstat64", /* 196 */ + "fstat64", /* 197 */ + "lchown", /* 198 */ + "getuid", /* 199 */ + "getgid", /* 200 */ + "geteuid", /* 201 */ + "getegid", /* 202 */ + "setreuid", /* 203 */ + "setregid", /* 204 */ + "getgroups", /* 205 */ + "setgroups", /* 206 */ + "fchown", /* 207 */ + "setresuid", /* 208 */ + "getresuid", /* 209 */ + "setresgid", /* 210 */ + "getresgid", /* 211 */ + "chown", /* 212 */ + "setuid", /* 213 */ + "setgid", /* 214 */ + "setfsuid", /* 215 */ + "setfsgid", /* 216 */ + "pivot_root", /* 217 */ + "mincore", /* 218 */ + "madvise", /* 219 */ + "getdents64", /* 220 */ + "fcntl64", /* 221 */ + "readahead", /* 222 */ + "sendfile64", /* 223 */ + "setxattr", /* 224 */ + "lsetxattr", /* 225 */ + "fsetxattr", /* 226 */ + "getxattr", /* 227 */ + "lgetxattr", /* 228 */ + "fgetxattr", /* 229 */ + "listxattr", /* 230 */ + "llistxattr", /* 231 */ + "flistxattr", /* 232 */ + "removexattr", /* 233 */ + "lremovexattr", /* 234 */ + "fremovexattr", /* 235 */ + "gettid", /* 236 */ + "tkill", /* 237 */ + "futex", /* 238 */ + "sched_setaffinity", /* 239 */ + "sched_getaffinity", /* 240 */ + "tgkill", /* 241 */ + "242", /* 242 */ + "io_setup", /* 243 */ + "io_destroy", /* 244 */ + "io_getevents", /* 245 */ + "io_submit", /* 246 */ + "io_cancel", /* 247 */ + "exit_group", /* 248 */ + "epoll_create", /* 249 */ + "epoll_ctl", /* 250 */ + "epoll_wait", /* 251 */ + "set_tid_address", /* 252 */ + "fadvise64", /* 253 */ + "timer_create", /* 254 */ + "timer_settime", /* 255 */ + "timer_gettime", /* 256 */ + "timer_getoverrun", /* 257 */ + "timer_delete", /* 258 */ + "clock_settime", /* 259 */ + "clock_gettime", /* 260 */ + "clock_getres", /* 261 */ + "clock_nanosleep", /* 262 */ + "263", /* 263 */ + "fadvise64_64", /* 264 */ + "statfs64", /* 265 */ + "fstatfs64", /* 266 */ + "remap_file_pages", /* 267 */ + "268", /* 268 */ + "269", /* 269 */ + "270", /* 270 */ + "mq_open", /* 271 */ + "mq_unlink", /* 272 */ + "mq_timedsend", /* 273 */ + "mq_timedreceive", /* 274 */ + "mq_notify", /* 275 */ + "mq_getsetattr", /* 276 */ + "kexec_load", /* 277 */ + "add_key", /* 278 */ + "request_key", /* 279 */ + "keyctl", /* 280 */ + "waitid", /* 281 */ + "ioprio_set", /* 282 */ + "ioprio_get", /* 283 */ + "inotify_init", /* 284 */ + "inotify_add_watch", /* 285 */ + "inotify_rm_watch", /* 286 */ + "287", /* 287 */ + "openat", /* 288 */ + "mkdirat", /* 289 */ + "mknodat", /* 290 */ + "fchownat", /* 291 */ + "futimesat", /* 292 */ + "fstatat64", /* 293 */ + "unlinkat", /* 294 */ + "renameat", /* 295 */ + "linkat", /* 296 */ + "symlinkat", /* 297 */ + "readlinkat", /* 298 */ + "fchmodat", /* 299 */ + "faccessat", /* 300 */ + "pselect6", /* 301 */ + "ppoll", /* 302 */ + "unshare", /* 303 */ + "set_robust_list", /* 304 */ + "get_robust_list", /* 305 */ + "splice", /* 306 */ + "sync_file_range", /* 307 */ + "tee", /* 308 */ + "vmsplice", /* 309 */ diff --git a/sysdeps/linux-gnu/s390/syscalls64.h b/sysdeps/linux-gnu/s390/syscalls64.h new file mode 100644 index 0000000..97be52c --- /dev/null +++ b/sysdeps/linux-gnu/s390/syscalls64.h @@ -0,0 +1,310 @@ + "0", /* 0 */ + "exit", /* 1 */ + "fork", /* 2 */ + "read", /* 3 */ + "write", /* 4 */ + "open", /* 5 */ + "close", /* 6 */ + "restart_syscall", /* 7 */ + "creat", /* 8 */ + "link", /* 9 */ + "unlink", /* 10 */ + "execve", /* 11 */ + "chdir", /* 12 */ + "13", /* 13 */ + "mknod", /* 14 */ + "chmod", /* 15 */ + "16", /* 16 */ + "17", /* 17 */ + "18", /* 18 */ + "lseek", /* 19 */ + "getpid", /* 20 */ + "mount", /* 21 */ + "oldumount", /* 22 */ + "23", /* 23 */ + "24", /* 24 */ + "25", /* 25 */ + "ptrace", /* 26 */ + "alarm", /* 27 */ + "28", /* 28 */ + "pause", /* 29 */ + "utime", /* 30 */ + "31", /* 31 */ + "32", /* 32 */ + "access", /* 33 */ + "nice", /* 34 */ + "35", /* 35 */ + "sync", /* 36 */ + "kill", /* 37 */ + "rename", /* 38 */ + "mkdir", /* 39 */ + "rmdir", /* 40 */ + "dup", /* 41 */ + "pipe", /* 42 */ + "times", /* 43 */ + "44", /* 44 */ + "brk", /* 45 */ + "46", /* 46 */ + "47", /* 47 */ + "signal", /* 48 */ + "49", /* 49 */ + "50", /* 50 */ + "acct", /* 51 */ + "umount", /* 52 */ + "53", /* 53 */ + "ioctl", /* 54 */ + "fcntl", /* 55 */ + "56", /* 56 */ + "setpgid", /* 57 */ + "58", /* 58 */ + "59", /* 59 */ + "umask", /* 60 */ + "chroot", /* 61 */ + "ustat", /* 62 */ + "dup2", /* 63 */ + "getppid", /* 64 */ + "getpgrp", /* 65 */ + "setsid", /* 66 */ + "sigaction", /* 67 */ + "68", /* 68 */ + "69", /* 69 */ + "70", /* 70 */ + "71", /* 71 */ + "sigsuspend", /* 72 */ + "sigpending", /* 73 */ + "sethostname", /* 74 */ + "setrlimit", /* 75 */ + "getrlimit", /* 76 */ + "getrusage", /* 77 */ + "gettimeofday", /* 78 */ + "settimeofday", /* 79 */ + "80", /* 80 */ + "81", /* 81 */ + "82", /* 82 */ + "symlink", /* 83 */ + "84", /* 84 */ + "readlink", /* 85 */ + "uselib", /* 86 */ + "swapon", /* 87 */ + "reboot", /* 88 */ + "89", /* 89 */ + "old_mmap", /* 90 */ + "munmap", /* 91 */ + "truncate", /* 92 */ + "ftruncate", /* 93 */ + "fchmod", /* 94 */ + "95", /* 95 */ + "getpriority", /* 96 */ + "setpriority", /* 97 */ + "98", /* 98 */ + "statfs", /* 99 */ + "fstatfs", /* 100 */ + "101", /* 101 */ + "socketcall", /* 102 */ + "syslog", /* 103 */ + "setitimer", /* 104 */ + "getitimer", /* 105 */ + "newstat", /* 106 */ + "newlstat", /* 107 */ + "newfstat", /* 108 */ + "109", /* 109 */ + "lookup_dcookie", /* 110 */ + "vhangup", /* 111 */ + "112", /* 112 */ + "113", /* 113 */ + "wait4", /* 114 */ + "swapoff", /* 115 */ + "sysinfo", /* 116 */ + "ipc", /* 117 */ + "fsync", /* 118 */ + "sigreturn", /* 119 */ + "clone", /* 120 */ + "setdomainname", /* 121 */ + "newuname", /* 122 */ + "123", /* 123 */ + "adjtimex", /* 124 */ + "mprotect", /* 125 */ + "sigprocmask", /* 126 */ + "127", /* 127 */ + "init_module", /* 128 */ + "delete_module", /* 129 */ + "130", /* 130 */ + "quotactl", /* 131 */ + "getpgid", /* 132 */ + "fchdir", /* 133 */ + "bdflush", /* 134 */ + "sysfs", /* 135 */ + "personality", /* 136 */ + "137", /* 137 */ + "138", /* 138 */ + "139", /* 139 */ + "llseek", /* 140 */ + "getdents", /* 141 */ + "select", /* 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 */ + "164", /* 164 */ + "165", /* 165 */ + "166", /* 166 */ + "167", /* 167 */ + "poll", /* 168 */ + "nfsservctl", /* 169 */ + "170", /* 170 */ + "171", /* 171 */ + "prctl", /* 172 */ + "rt_sigreturn", /* 173 */ + "rt_sigaction", /* 174 */ + "rt_sigprocmask", /* 175 */ + "rt_sigpending", /* 176 */ + "rt_sigtimedwait", /* 177 */ + "rt_sigqueueinfo", /* 178 */ + "rt_sigsuspend", /* 179 */ + "pread64", /* 180 */ + "pwrite64", /* 181 */ + "182", /* 182 */ + "getcwd", /* 183 */ + "capget", /* 184 */ + "capset", /* 185 */ + "sigaltstack", /* 186 */ + "sendfile64", /* 187 */ + "188", /* 188 */ + "189", /* 189 */ + "vfork", /* 190 */ + "getrlimit", /* 191 */ + "mmap2", /* 192 */ + "193", /* 193 */ + "194", /* 194 */ + "195", /* 195 */ + "196", /* 196 */ + "197", /* 197 */ + "lchown", /* 198 */ + "getuid", /* 199 */ + "getgid", /* 200 */ + "geteuid", /* 201 */ + "getegid", /* 202 */ + "setreuid", /* 203 */ + "setregid", /* 204 */ + "getgroups", /* 205 */ + "setgroups", /* 206 */ + "fchown", /* 207 */ + "setresuid", /* 208 */ + "getresuid", /* 209 */ + "setresgid", /* 210 */ + "getresgid", /* 211 */ + "chown", /* 212 */ + "setuid", /* 213 */ + "setgid", /* 214 */ + "setfsuid", /* 215 */ + "setfsgid", /* 216 */ + "pivot_root", /* 217 */ + "mincore", /* 218 */ + "madvise", /* 219 */ + "getdents64", /* 220 */ + "221", /* 221 */ + "readahead", /* 222 */ + "223", /* 223 */ + "setxattr", /* 224 */ + "lsetxattr", /* 225 */ + "fsetxattr", /* 226 */ + "getxattr", /* 227 */ + "lgetxattr", /* 228 */ + "fgetxattr", /* 229 */ + "listxattr", /* 230 */ + "llistxattr", /* 231 */ + "flistxattr", /* 232 */ + "removexattr", /* 233 */ + "lremovexattr", /* 234 */ + "fremovexattr", /* 235 */ + "gettid", /* 236 */ + "tkill", /* 237 */ + "futex", /* 238 */ + "sched_setaffinity", /* 239 */ + "sched_getaffinity", /* 240 */ + "tgkill", /* 241 */ + "242", /* 242 */ + "io_setup", /* 243 */ + "io_destroy", /* 244 */ + "io_getevents", /* 245 */ + "io_submit", /* 246 */ + "io_cancel", /* 247 */ + "exit_group", /* 248 */ + "epoll_create", /* 249 */ + "epoll_ctl", /* 250 */ + "epoll_wait", /* 251 */ + "set_tid_address", /* 252 */ + "fadvise64_64", /* 253 */ + "timer_create", /* 254 */ + "timer_settime", /* 255 */ + "timer_gettime", /* 256 */ + "timer_getoverrun", /* 257 */ + "timer_delete", /* 258 */ + "clock_settime", /* 259 */ + "clock_gettime", /* 260 */ + "clock_getres", /* 261 */ + "clock_nanosleep", /* 262 */ + "263", /* 263 */ + "264", /* 264 */ + "statfs64", /* 265 */ + "fstatfs64", /* 266 */ + "remap_file_pages", /* 267 */ + "268", /* 268 */ + "269", /* 269 */ + "270", /* 270 */ + "mq_open", /* 271 */ + "mq_unlink", /* 272 */ + "mq_timedsend", /* 273 */ + "mq_timedreceive", /* 274 */ + "mq_notify", /* 275 */ + "mq_getsetattr", /* 276 */ + "kexec_load", /* 277 */ + "add_key", /* 278 */ + "request_key", /* 279 */ + "keyctl", /* 280 */ + "waitid", /* 281 */ + "ioprio_set", /* 282 */ + "ioprio_get", /* 283 */ + "inotify_init", /* 284 */ + "inotify_add_watch", /* 285 */ + "inotify_rm_watch", /* 286 */ + "287", /* 287 */ + "openat", /* 288 */ + "mkdirat", /* 289 */ + "mknodat", /* 290 */ + "fchownat", /* 291 */ + "futimesat", /* 292 */ + "newfstatat", /* 293 */ + "unlinkat", /* 294 */ + "renameat", /* 295 */ + "linkat", /* 296 */ + "symlinkat", /* 297 */ + "readlinkat", /* 298 */ + "fchmodat", /* 299 */ + "faccessat", /* 300 */ + "pselect6", /* 301 */ + "ppoll", /* 302 */ + "unshare", /* 303 */ + "set_robust_list", /* 304 */ + "get_robust_list", /* 305 */ + "splice", /* 306 */ + "sync_file_range", /* 307 */ + "tee", /* 308 */ + "vmsplice", /* 309 */ diff --git a/sysdeps/linux-gnu/s390/trace.c b/sysdeps/linux-gnu/s390/trace.c new file mode 100644 index 0000000..9df2437 --- /dev/null +++ b/sysdeps/linux-gnu/s390/trace.c @@ -0,0 +1,198 @@ +/* +** S390 specific part of trace.c +** +** Other routines are in ../trace.c and need to be combined +** at link time with this code. +** +** Copyright (C) 2001,2005 IBM Corp. +*/ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "common.h" + +#if (!defined(PTRACE_PEEKUSER) && defined(PTRACE_PEEKUSR)) +# define PTRACE_PEEKUSER PTRACE_PEEKUSR +#endif + +#if (!defined(PTRACE_POKEUSER) && defined(PTRACE_POKEUSR)) +# define PTRACE_POKEUSER PTRACE_POKEUSR +#endif + +void +get_arch_dep(Process *proc) { +#ifdef __s390x__ + unsigned long psw; + + if (proc->arch_ptr) + return; + + psw = ptrace(PTRACE_PEEKUSER, proc->pid, PT_PSWMASK, 0); + + if ((psw & 0x000000180000000) == 0x000000080000000) { + proc->mask_32bit = 1; + proc->personality = 1; + } + + proc->arch_ptr = (void *)1; +#endif +} + +/* Returns 1 if syscall, 2 if sysret, 0 otherwise. + */ +int +syscall_p(Process *proc, int status, int *sysnum) { + long pc, opcode, offset_reg, scno, tmp; + void *svc_addr; + int gpr_offset[16] = { PT_GPR0, PT_GPR1, PT_ORIGGPR2, PT_GPR3, + PT_GPR4, PT_GPR5, PT_GPR6, PT_GPR7, + PT_GPR8, PT_GPR9, PT_GPR10, PT_GPR11, + PT_GPR12, PT_GPR13, PT_GPR14, PT_GPR15 + }; + + if (WIFSTOPPED(status) + && WSTOPSIG(status) == (SIGTRAP | proc->tracesysgood)) { + + /* + * If we have PTRACE_O_TRACESYSGOOD and we have the new style + * of passing the system call number to user space via PT_GPR2 + * then the task is quite easy. + */ + + *sysnum = ptrace(PTRACE_PEEKUSER, proc->pid, PT_GPR2, 0); + + if (proc->tracesysgood) { + /* System call was encountered... */ + if (proc->callstack_depth > 0 && + proc->callstack[proc->callstack_depth - + 1].is_syscall) { + /* syscall exit */ + *sysnum = + proc->callstack[proc->callstack_depth - + 1].c_un.syscall; + return 2; + } else { + /* syscall enter */ + if (*sysnum != -ENOSYS) + return 1; + } + } + + /* + * At least one of the two requirements mentioned above is not + * met. Therefore the fun part starts here: + * We try to do some instruction decoding without even knowing + * the instruction code length of the last instruction executed. + * Needs to be done to get the system call number or to decide + * if we reached a breakpoint or even checking for a completely + * unrelated instruction. + * Just a heuristic that most of the time appears to work... + */ + + pc = ptrace(PTRACE_PEEKUSER, proc->pid, PT_PSWADDR, 0); + opcode = ptrace(PTRACE_PEEKTEXT, proc->pid, + (char *)(pc - sizeof(long)), 0); + + if ((opcode & 0xffff) == 0x0001) { + /* Breakpoint */ + return 0; + } else if ((opcode & 0xff00) == 0x0a00) { + /* SVC opcode */ + scno = opcode & 0xff; + } else if ((opcode & 0xff000000) == 0x44000000) { + /* Instruction decoding of EXECUTE... */ + svc_addr = (void *)(opcode & 0xfff); + + offset_reg = (opcode & 0x000f0000) >> 16; + if (offset_reg) + svc_addr += ptrace(PTRACE_PEEKUSER, proc->pid, + gpr_offset[offset_reg], 0); + + offset_reg = (opcode & 0x0000f000) >> 12; + if (offset_reg) + svc_addr += ptrace(PTRACE_PEEKUSER, proc->pid, + gpr_offset[offset_reg], 0); + + scno = ptrace(PTRACE_PEEKTEXT, proc->pid, svc_addr, 0); +#ifdef __s390x__ + scno >>= 48; +#else + scno >>= 16; +#endif + if ((scno & 0xff00) != 0x0a000) + return 0; + + tmp = 0; + offset_reg = (opcode & 0x00f00000) >> 20; + if (offset_reg) + tmp = ptrace(PTRACE_PEEKUSER, proc->pid, + gpr_offset[offset_reg], 0); + + scno = (scno | tmp) & 0xff; + } else { + /* No opcode related to syscall handling */ + return 0; + } + + if (scno == 0) + scno = ptrace(PTRACE_PEEKUSER, proc->pid, PT_GPR1, 0); + + *sysnum = scno; + + /* System call was encountered... */ + if (proc->callstack_depth > 0 && + proc->callstack[proc->callstack_depth - 1].is_syscall) { + return 2; + } else { + return 1; + } + } + /* Unknown status... */ + return 0; +} + +long +gimme_arg(enum tof type, Process *proc, int arg_num, arg_type_info *info) { + long ret; + + switch (arg_num) { + case -1: /* return value */ + ret = ptrace(PTRACE_PEEKUSER, proc->pid, PT_GPR2, 0); + break; + case 0: + ret = ptrace(PTRACE_PEEKUSER, proc->pid, PT_ORIGGPR2, 0); + break; + case 1: + ret = ptrace(PTRACE_PEEKUSER, proc->pid, PT_GPR3, 0); + break; + case 2: + ret = ptrace(PTRACE_PEEKUSER, proc->pid, PT_GPR4, 0); + break; + case 3: + ret = ptrace(PTRACE_PEEKUSER, proc->pid, PT_GPR5, 0); + break; + case 4: + ret = ptrace(PTRACE_PEEKUSER, proc->pid, PT_GPR6, 0); + break; + default: + fprintf(stderr, "gimme_arg called with wrong arguments\n"); + exit(2); + } +#ifdef __s390x__ + if (proc->mask_32bit) + ret &= 0xffffffff; +#endif + return ret; +} + +void +save_register_args(enum tof type, Process *proc) { +} diff --git a/sysdeps/linux-gnu/sparc/Makefile b/sysdeps/linux-gnu/sparc/Makefile new file mode 100644 index 0000000..b3914e5 --- /dev/null +++ b/sysdeps/linux-gnu/sparc/Makefile @@ -0,0 +1,9 @@ +OBJ = regs.o trace.o plt.o + +all: arch.o + +arch.o: $(OBJ) + $(CC) -nostdlib -r -o arch.o $(OBJ) + +clean: + $(RM) $(OBJ) arch.o diff --git a/sysdeps/linux-gnu/sparc/arch.h b/sysdeps/linux-gnu/sparc/arch.h new file mode 100644 index 0000000..75251b8 --- /dev/null +++ b/sysdeps/linux-gnu/sparc/arch.h @@ -0,0 +1,8 @@ +#define BREAKPOINT_VALUE {0x91, 0xd0, 0x20, 0x01} +#define BREAKPOINT_LENGTH 4 +#define DECR_PC_AFTER_BREAK 0 + +#define LT_ELFCLASS ELFCLASS32 +#define LT_ELF_MACHINE EM_SPARC +#define LT_ELFCLASS2 ELFCLASS32 +#define LT_ELF_MACHINE2 EM_SPARC32PLUS diff --git a/sysdeps/linux-gnu/sparc/plt.c b/sysdeps/linux-gnu/sparc/plt.c new file mode 100644 index 0000000..f9e6d80 --- /dev/null +++ b/sysdeps/linux-gnu/sparc/plt.c @@ -0,0 +1,12 @@ +#include +#include "common.h" + +GElf_Addr +arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela * rela) { + return rela->r_offset + 4; +} + +void * +sym2addr(Process *proc, struct library_symbol *sym) { + return sym->enter_addr; +} diff --git a/sysdeps/linux-gnu/sparc/ptrace.h b/sysdeps/linux-gnu/sparc/ptrace.h new file mode 100644 index 0000000..bbaf01a --- /dev/null +++ b/sysdeps/linux-gnu/sparc/ptrace.h @@ -0,0 +1,21 @@ +#undef PTRACE_GETREGS +#undef PTRACE_SETREGS +#undef PTRACE_GETFPREGS +#undef PTRACE_SETFPREGS +#include +#ifndef PTRACE_SUNDETACH +#define PTRACE_SUNDETACH 11 +#endif +#undef PT_DETACH +#undef PTRACE_DETACH +#define PT_DETACH PTRACE_SUNDETACH +#define PTRACE_DETACH PTRACE_SUNDETACH + +#include + +typedef struct { + int valid; + struct pt_regs regs; + unsigned int func_arg[6]; + unsigned int sysc_arg[6]; +} proc_archdep; diff --git a/sysdeps/linux-gnu/sparc/regs.c b/sysdeps/linux-gnu/sparc/regs.c new file mode 100644 index 0000000..49d2729 --- /dev/null +++ b/sysdeps/linux-gnu/sparc/regs.c @@ -0,0 +1,49 @@ +#include "config.h" + +#include +#include "ptrace.h" +#include "common.h" + +void * +get_instruction_pointer(Process *proc) { + proc_archdep *a = (proc_archdep *) (proc->arch_ptr); + if (a->valid) + return (void *)a->regs.pc; + return (void *)-1; +} + +void +set_instruction_pointer(Process *proc, void *addr) { + proc_archdep *a = (proc_archdep *) (proc->arch_ptr); + if (a->valid) + a->regs.pc = (long)addr; +} + +void * +get_stack_pointer(Process *proc) { + proc_archdep *a = (proc_archdep *) (proc->arch_ptr); + if (a->valid) + return (void *)a->regs.u_regs[UREG_I5]; + return (void *)-1; +} + +void * +get_return_addr(Process *proc, void *stack_pointer) { + proc_archdep *a = (proc_archdep *) (proc->arch_ptr); + unsigned int t; + if (!a->valid) + return (void *)-1; + /* Work around structure returns */ + t = ptrace(PTRACE_PEEKTEXT, proc->pid, a->regs.u_regs[UREG_I6] + 8, 0); + if (t < 0x400000) + return (void *)a->regs.u_regs[UREG_I6] + 12; + return (void *)a->regs.u_regs[UREG_I6] + 8; +} + +void +set_return_addr(Process *proc, void *addr) { + proc_archdep *a = (proc_archdep *) (proc->arch_ptr); + if (!a->valid) + return; + ptrace(PTRACE_POKETEXT, proc->pid, a->regs.u_regs[UREG_I6] + 8, addr); +} diff --git a/sysdeps/linux-gnu/sparc/signalent.h b/sysdeps/linux-gnu/sparc/signalent.h new file mode 100644 index 0000000..d30f69e --- /dev/null +++ b/sysdeps/linux-gnu/sparc/signalent.h @@ -0,0 +1,32 @@ +"SIG_0", /* 0 */ + "SIGHUP", /* 1 */ + "SIGINT", /* 2 */ + "SIGQUIT", /* 3 */ + "SIGILL", /* 4 */ + "SIGTRAP", /* 5 */ + "SIGABRT", /* 6 */ + "SIGEMT", /* 7 */ + "SIGFPE", /* 8 */ + "SIGKILL", /* 9 */ + "SIGBUS", /* 10 */ + "SIGSEGV", /* 11 */ + "SIGSYS", /* 12 */ + "SIGPIPE", /* 13 */ + "SIGALRM", /* 14 */ + "SIGTERM", /* 15 */ + "SIGURG", /* 16 */ + "SIGSTOP", /* 17 */ + "SIGTSTP", /* 18 */ + "SIGCONT", /* 19 */ + "SIGCHLD", /* 20 */ + "SIGTTIN", /* 21 */ + "SIGTTOU", /* 22 */ + "SIGIO", /* 23 */ + "SIGXCPU", /* 24 */ + "SIGXFSZ", /* 25 */ + "SIGVTALRM", /* 26 */ + "SIGPROF", /* 27 */ + "SIGWINCH", /* 28 */ + "SIGLOST", /* 29 */ + "SIGUSR1", /* 30 */ + "SIGUSR2", /* 31 */ diff --git a/sysdeps/linux-gnu/sparc/syscallent.h b/sysdeps/linux-gnu/sparc/syscallent.h new file mode 100644 index 0000000..96eeec9 --- /dev/null +++ b/sysdeps/linux-gnu/sparc/syscallent.h @@ -0,0 +1,284 @@ +"0", /* 0 */ + "exit", /* 1 */ + "fork", /* 2 */ + "read", /* 3 */ + "write", /* 4 */ + "open", /* 5 */ + "close", /* 6 */ + "wait4", /* 7 */ + "creat", /* 8 */ + "link", /* 9 */ + "unlink", /* 10 */ + "execv", /* 11 */ + "chdir", /* 12 */ + "chown", /* 13 */ + "mknod", /* 14 */ + "chmod", /* 15 */ + "lchown", /* 16 */ + "brk", /* 17 */ + "perfctr", /* 18 */ + "lseek", /* 19 */ + "getpid", /* 20 */ + "capget", /* 21 */ + "capset", /* 22 */ + "setuid", /* 23 */ + "getuid", /* 24 */ + "25", /* 25 */ + "ptrace", /* 26 */ + "alarm", /* 27 */ + "sigaltstack", /* 28 */ + "pause", /* 29 */ + "utime", /* 30 */ + "lchown32", /* 31 */ + "fchown32", /* 32 */ + "access", /* 33 */ + "nice", /* 34 */ + "chown32", /* 35 */ + "sync", /* 36 */ + "kill", /* 37 */ + "stat", /* 38 */ + "sendfile", /* 39 */ + "lstat", /* 40 */ + "dup", /* 41 */ + "pipe", /* 42 */ + "times", /* 43 */ + "getuid32", /* 44 */ + "umount2", /* 45 */ + "setgid", /* 46 */ + "getgid", /* 47 */ + "signal", /* 48 */ + "geteuid", /* 49 */ + "getegid", /* 50 */ + "acct", /* 51 */ + "memory_ordering", /* 52 */ + "getgid32", /* 53 */ + "ioctl", /* 54 */ + "reboot", /* 55 */ + "mmap2", /* 56 */ + "symlink", /* 57 */ + "readlink", /* 58 */ + "execve", /* 59 */ + "umask", /* 60 */ + "chroot", /* 61 */ + "fstat", /* 62 */ + "fstat64", /* 63 */ + "getpagesize", /* 64 */ + "msync", /* 65 */ + "vfork", /* 66 */ + "pread64", /* 67 */ + "pwrite64", /* 68 */ + "geteuid32", /* 69 */ + "getegid32", /* 70 */ + "mmap", /* 71 */ + "setreuid32", /* 72 */ + "munmap", /* 73 */ + "mprotect", /* 74 */ + "madvise", /* 75 */ + "vhangup", /* 76 */ + "truncate64", /* 77 */ + "mincore", /* 78 */ + "getgroups", /* 79 */ + "setgroups", /* 80 */ + "getpgrp", /* 81 */ + "setgroups32", /* 82 */ + "setitimer", /* 83 */ + "ftruncate64", /* 84 */ + "swapon", /* 85 */ + "getitimer", /* 86 */ + "setuid32", /* 87 */ + "sethostname", /* 88 */ + "setgid32", /* 89 */ + "dup2", /* 90 */ + "setfsuid32", /* 91 */ + "fcntl", /* 92 */ + "select", /* 93 */ + "setfsgid32", /* 94 */ + "fsync", /* 95 */ + "setpriority", /* 96 */ + "socket", /* 97 */ + "connect", /* 98 */ + "accept", /* 99 */ + "getpriority", /* 100 */ + "rt_sigreturn", /* 101 */ + "rt_sigaction", /* 102 */ + "rt_sigprocmask", /* 103 */ + "rt_sigpending", /* 104 */ + "rt_sigtimedwait", /* 105 */ + "rt_sigqueueinfo", /* 106 */ + "rt_sigsuspend", /* 107 */ + "setresuid32", /* 108 */ + "getresuid32", /* 109 */ + "setresgid32", /* 110 */ + "getresgid32", /* 111 */ + "setregid32", /* 112 */ + "recvmsg", /* 113 */ + "sendmsg", /* 114 */ + "getgroups32", /* 115 */ + "gettimeofday", /* 116 */ + "getrusage", /* 117 */ + "getsockopt", /* 118 */ + "getcwd", /* 119 */ + "readv", /* 120 */ + "writev", /* 121 */ + "settimeofday", /* 122 */ + "fchown", /* 123 */ + "fchmod", /* 124 */ + "recvfrom", /* 125 */ + "setreuid", /* 126 */ + "setregid", /* 127 */ + "rename", /* 128 */ + "truncate", /* 129 */ + "ftruncate", /* 130 */ + "flock", /* 131 */ + "lstat64", /* 132 */ + "sendto", /* 133 */ + "shutdown", /* 134 */ + "socketpair", /* 135 */ + "mkdir", /* 136 */ + "rmdir", /* 137 */ + "utimes", /* 138 */ + "stat64", /* 139 */ + "sendfile64", /* 140 */ + "getpeername", /* 141 */ + "futex", /* 142 */ + "gettid", /* 143 */ + "getrlimit", /* 144 */ + "setrlimit", /* 145 */ + "pivot_root", /* 146 */ + "prctl", /* 147 */ + "pciconfig_read", /* 148 */ + "pciconfig_write", /* 149 */ + "getsockname", /* 150 */ + "inotify_init", /* 151 */ + "inotify_add_watch", /* 152 */ + "poll", /* 153 */ + "getdents64", /* 154 */ + "fcntl64", /* 155 */ + "inotify_rm_watch", /* 156 */ + "statfs", /* 157 */ + "fstatfs", /* 158 */ + "umount", /* 159 */ + "sched_set_affinity", /* 160 */ + "sched_get_affinity", /* 161 */ + "getdomainname", /* 162 */ + "setdomainname", /* 163 */ + "utrap_install", /* 164 */ + "quotactl", /* 165 */ + "set_tid_address", /* 166 */ + "mount", /* 167 */ + "ustat", /* 168 */ + "setxattr", /* 169 */ + "lsetxattr", /* 170 */ + "fsetxattr", /* 171 */ + "getxattr", /* 172 */ + "lgetxattr", /* 173 */ + "getdents", /* 174 */ + "setsid", /* 175 */ + "fchdir", /* 176 */ + "fgetxattr", /* 177 */ + "listxattr", /* 178 */ + "llistxattr", /* 179 */ + "flistxattr", /* 180 */ + "removexattr", /* 181 */ + "lremovexattr", /* 182 */ + "sigpending", /* 183 */ + "query_module", /* 184 */ + "setpgid", /* 185 */ + "fremovexattr", /* 186 */ + "tkill", /* 187 */ + "exit_group", /* 188 */ + "uname", /* 189 */ + "init_module", /* 190 */ + "personality", /* 191 */ + "remap_file_pages", /* 192 */ + "epoll_create", /* 193 */ + "epoll_ctl", /* 194 */ + "epoll_wait", /* 195 */ + "ioprio_set", /* 196 */ + "getppid", /* 197 */ + "sigaction", /* 198 */ + "sgetmask", /* 199 */ + "ssetmask", /* 200 */ + "sigsuspend", /* 201 */ + "oldlstat", /* 202 */ + "uselib", /* 203 */ + "readdir", /* 204 */ + "readahead", /* 205 */ + "socketcall", /* 206 */ + "syslog", /* 207 */ + "lookup_dcookie", /* 208 */ + "fadvise64", /* 209 */ + "fadvise64_64", /* 210 */ + "tgkill", /* 211 */ + "waitpid", /* 212 */ + "swapoff", /* 213 */ + "sysinfo", /* 214 */ + "ipc", /* 215 */ + "sigreturn", /* 216 */ + "clone", /* 217 */ + "ioprio_get", /* 218 */ + "adjtimex", /* 219 */ + "sigprocmask", /* 220 */ + "create_module", /* 221 */ + "delete_module", /* 222 */ + "get_kernel_syms", /* 223 */ + "getpgid", /* 224 */ + "bdflush", /* 225 */ + "sysfs", /* 226 */ + "afs_syscall", /* 227 */ + "setfsuid", /* 228 */ + "setfsgid", /* 229 */ + "_newselect", /* 230 */ + "time", /* 231 */ + "232", /* 232 */ + "stime", /* 233 */ + "statfs64", /* 234 */ + "fstatfs64", /* 235 */ + "_llseek", /* 236 */ + "mlock", /* 237 */ + "munlock", /* 238 */ + "mlockall", /* 239 */ + "munlockall", /* 240 */ + "sched_setparam", /* 241 */ + "sched_getparam", /* 242 */ + "sched_setscheduler", /* 243 */ + "sched_getscheduler", /* 244 */ + "sched_yield", /* 245 */ + "sched_get_priority_max", /* 246 */ + "sched_get_priority_min", /* 247 */ + "sched_rr_get_interval", /* 248 */ + "nanosleep", /* 249 */ + "mremap", /* 250 */ + "_sysctl", /* 251 */ + "getsid", /* 252 */ + "fdatasync", /* 253 */ + "nfsservctl", /* 254 */ + "aplib", /* 255 */ + "clock_settime", /* 256 */ + "clock_gettime", /* 257 */ + "clock_getres", /* 258 */ + "clock_nanosleep", /* 259 */ + "sched_getaffinity", /* 260 */ + "sched_setaffinity", /* 261 */ + "timer_settime", /* 262 */ + "timer_gettime", /* 263 */ + "timer_getoverrun", /* 264 */ + "timer_delete", /* 265 */ + "timer_create", /* 266 */ + "vserver", /* 267 */ + "io_setup", /* 268 */ + "io_destroy", /* 269 */ + "io_submit", /* 270 */ + "io_cancel", /* 271 */ + "io_getevents", /* 272 */ + "mq_open", /* 273 */ + "mq_unlink", /* 274 */ + "mq_timedsend", /* 275 */ + "mq_timedreceive", /* 276 */ + "mq_notify", /* 277 */ + "mq_getsetattr", /* 278 */ + "waitid", /* 279 */ + "setaltroot", /* 280 */ + "add_key", /* 281 */ + "request_key", /* 282 */ + "keyctl", /* 283 */ diff --git a/sysdeps/linux-gnu/sparc/trace.c b/sysdeps/linux-gnu/sparc/trace.c new file mode 100644 index 0000000..7f05b55 --- /dev/null +++ b/sysdeps/linux-gnu/sparc/trace.c @@ -0,0 +1,81 @@ +#include "config.h" + +#include +#include +#include +#include +#include +#include "ptrace.h" +#include "common.h" + +void +get_arch_dep(Process *proc) { + proc_archdep *a; + if (!proc->arch_ptr) + proc->arch_ptr = (void *)malloc(sizeof(proc_archdep)); + a = (proc_archdep *) (proc->arch_ptr); + a->valid = (ptrace(PTRACE_GETREGS, proc->pid, &a->regs, 0) >= 0); +} + +/* Returns syscall number if `pid' stopped because of a syscall. + * Returns -1 otherwise + */ +int +syscall_p(Process *proc, int status, int *sysnum) { + if (WIFSTOPPED(status) + && WSTOPSIG(status) == (SIGTRAP | proc->tracesysgood)) { + void *ip = get_instruction_pointer(proc); + unsigned int insn; + if (ip == (void *)-1) + return 0; + insn = ptrace(PTRACE_PEEKTEXT, proc->pid, ip, 0); + if ((insn & 0xc1f8007f) == 0x81d00010) { + *sysnum = ((proc_archdep *) proc->arch_ptr)->regs.u_regs[UREG_G0]; + if (proc->callstack_depth > 0 && + proc->callstack[proc->callstack_depth - 1].is_syscall && + proc->callstack[proc->callstack_depth - 1].c_un.syscall == *sysnum) { + return 2; + } else if (*sysnum >= 0) { + return 1; + } + } + } + return 0; +} + +long +gimme_arg(enum tof type, Process *proc, int arg_num, arg_type_info *info) { + proc_archdep *a = (proc_archdep *) proc->arch_ptr; + if (!a->valid) { + fprintf(stderr, "Could not get child registers\n"); + exit(1); + } + if (arg_num == -1) /* return value */ + return a->regs.u_regs[UREG_G7]; + + if (type == LT_TOF_FUNCTION || type == LT_TOF_SYSCALL || arg_num >= 6) { + if (arg_num < 6) + return ((int *)&a->regs.u_regs[UREG_G7])[arg_num]; + return ptrace(PTRACE_PEEKTEXT, proc->pid, + proc->stack_pointer + 64 * (arg_num + 1)); + } else if (type == LT_TOF_FUNCTIONR) + return a->func_arg[arg_num]; + else if (type == LT_TOF_SYSCALLR) + return a->sysc_arg[arg_num]; + else { + fprintf(stderr, "gimme_arg called with wrong arguments\n"); + exit(1); + } + return 0; +} + +void +save_register_args(enum tof type, Process *proc) { + proc_archdep *a = (proc_archdep *) proc->arch_ptr; + if (a->valid) { + if (type == LT_TOF_FUNCTION) + memcpy(a->func_arg, &a->regs.u_regs[UREG_G7], sizeof(a->func_arg)); + else + memcpy(a->sysc_arg, &a->regs.u_regs[UREG_G7], sizeof(a->sysc_arg)); + } +} diff --git a/sysdeps/linux-gnu/trace.c b/sysdeps/linux-gnu/trace.c new file mode 100644 index 0000000..df5b090 --- /dev/null +++ b/sysdeps/linux-gnu/trace.c @@ -0,0 +1,193 @@ +#include +#include +#include +#include +#include +#include +#include +#include "ptrace.h" +#include + +#include "common.h" + +/* If the system headers did not provide the constants, hard-code the normal + values. */ +#ifndef PTRACE_EVENT_FORK + +#define PTRACE_OLDSETOPTIONS 21 +#define PTRACE_SETOPTIONS 0x4200 +#define PTRACE_GETEVENTMSG 0x4201 + +/* options set using PTRACE_SETOPTIONS */ +#define PTRACE_O_TRACESYSGOOD 0x00000001 +#define PTRACE_O_TRACEFORK 0x00000002 +#define PTRACE_O_TRACEVFORK 0x00000004 +#define PTRACE_O_TRACECLONE 0x00000008 +#define PTRACE_O_TRACEEXEC 0x00000010 +#define PTRACE_O_TRACEVFORKDONE 0x00000020 +#define PTRACE_O_TRACEEXIT 0x00000040 + +/* Wait extended result codes for the above trace options. */ +#define PTRACE_EVENT_FORK 1 +#define PTRACE_EVENT_VFORK 2 +#define PTRACE_EVENT_CLONE 3 +#define PTRACE_EVENT_EXEC 4 +#define PTRACE_EVENT_VFORK_DONE 5 +#define PTRACE_EVENT_EXIT 6 + +#endif /* PTRACE_EVENT_FORK */ + +#ifdef ARCH_HAVE_UMOVELONG +extern int arch_umovelong (Process *, void *, long *, arg_type_info *); +int +umovelong (Process *proc, void *addr, long *result, arg_type_info *info) { + return arch_umovelong (proc, addr, result, info); +} +#else +/* Read a single long from the process's memory address 'addr' */ +int +umovelong (Process *proc, void *addr, long *result, arg_type_info *info) { + long pointed_to; + + errno = 0; + pointed_to = ptrace (PTRACE_PEEKTEXT, proc->pid, addr, 0); + if (pointed_to == -1 && errno) + return -errno; + + *result = pointed_to; + return 0; +} +#endif + +void +trace_me(void) { + debug(DEBUG_PROCESS, "trace_me: pid=%d\n", getpid()); + if (ptrace(PTRACE_TRACEME, 0, 1, 0) < 0) { + perror("PTRACE_TRACEME"); + exit(1); + } +} + +int +trace_pid(pid_t pid) { + debug(DEBUG_PROCESS, "trace_pid: pid=%d\n", pid); + if (ptrace(PTRACE_ATTACH, pid, 1, 0) < 0) { + return -1; + } + + /* man ptrace: PTRACE_ATTACH attaches to the process specified + in pid. The child is sent a SIGSTOP, but will not + necessarily have stopped by the completion of this call; + use wait() to wait for the child to stop. */ + if (waitpid (pid, NULL, 0) != pid) { + perror ("trace_pid: waitpid"); + exit (1); + } + + return 0; +} + +void +trace_set_options(Process *proc, pid_t pid) { + if (proc->tracesysgood & 0x80) + return; + + debug(DEBUG_PROCESS, "trace_set_options: pid=%d\n", pid); + + long options = PTRACE_O_TRACESYSGOOD | PTRACE_O_TRACEFORK | + PTRACE_O_TRACEVFORK | PTRACE_O_TRACECLONE | + PTRACE_O_TRACEEXEC; + if (ptrace(PTRACE_SETOPTIONS, pid, 0, options) < 0 && + ptrace(PTRACE_OLDSETOPTIONS, pid, 0, options) < 0) { + perror("PTRACE_SETOPTIONS"); + return; + } + proc->tracesysgood |= 0x80; +} + +void +untrace_pid(pid_t pid) { + debug(DEBUG_PROCESS, "untrace_pid: pid=%d\n", pid); + ptrace(PTRACE_DETACH, pid, 1, 0); +} + +void +continue_after_signal(pid_t pid, int signum) { + Process *proc; + + debug(DEBUG_PROCESS, "continue_after_signal: pid=%d, signum=%d", pid, signum); + + proc = pid2proc(pid); + if (proc && proc->breakpoint_being_enabled) { +#if defined __sparc__ || defined __ia64___ + ptrace(PTRACE_SYSCALL, pid, 0, signum); +#else + ptrace(PTRACE_SINGLESTEP, pid, 0, signum); +#endif + } else { + ptrace(PTRACE_SYSCALL, pid, 0, signum); + } +} + +void +continue_process(pid_t pid) { + /* We always trace syscalls to control fork(), clone(), execve()... */ + + debug(DEBUG_PROCESS, "continue_process: pid=%d", pid); + + ptrace(PTRACE_SYSCALL, pid, 0, 0); +} + +void +continue_enabling_breakpoint(pid_t pid, Breakpoint *sbp) { + enable_breakpoint(pid, sbp); + continue_process(pid); +} + +void +continue_after_breakpoint(Process *proc, Breakpoint *sbp) { + if (sbp->enabled) + disable_breakpoint(proc->pid, sbp); + set_instruction_pointer(proc, sbp->addr); + if (sbp->enabled == 0) { + continue_process(proc->pid); + } else { + debug(DEBUG_PROCESS, "continue_after_breakpoint: pid=%d, addr=%p", proc->pid, sbp->addr); + proc->breakpoint_being_enabled = sbp; +#if defined __sparc__ || defined __ia64___ + /* we don't want to singlestep here */ + continue_process(proc->pid); +#else + ptrace(PTRACE_SINGLESTEP, proc->pid, 0, 0); +#endif + } +} + +/* Read a series of bytes starting at the process's memory address + 'addr' and continuing until a NUL ('\0') is seen or 'len' bytes + have been read. +*/ +int +umovestr(Process *proc, void *addr, int len, void *laddr) { + union { + long a; + char c[sizeof(long)]; + } a; + int i; + int offset = 0; + + while (offset < len) { + a.a = ptrace(PTRACE_PEEKTEXT, proc->pid, addr + offset, 0); + for (i = 0; i < sizeof(long); i++) { + if (a.c[i] && offset + (signed)i < len) { + *(char *)(laddr + offset + i) = a.c[i]; + } else { + *(char *)(laddr + offset + i) = '\0'; + return 0; + } + } + offset += sizeof(long); + } + *(char *)(laddr + offset) = '\0'; + return 0; +} diff --git a/sysdeps/linux-gnu/x86_64/Makefile b/sysdeps/linux-gnu/x86_64/Makefile new file mode 100644 index 0000000..0a19c97 --- /dev/null +++ b/sysdeps/linux-gnu/x86_64/Makefile @@ -0,0 +1,9 @@ +OBJ = trace.o regs.o plt.o + +all: arch.o + +arch.o: $(OBJ) + $(CC) -nostdlib -r -o arch.o $(OBJ) + +clean: + $(RM) $(OBJ) arch.o diff --git a/sysdeps/linux-gnu/x86_64/arch.h b/sysdeps/linux-gnu/x86_64/arch.h new file mode 100644 index 0000000..255395c --- /dev/null +++ b/sysdeps/linux-gnu/x86_64/arch.h @@ -0,0 +1,12 @@ +#define BREAKPOINT_VALUE {0xcc} +#define BREAKPOINT_LENGTH 1 +#define DECR_PC_AFTER_BREAK 1 + +#define LT_ELFCLASS ELFCLASS64 +#define LT_ELF_MACHINE EM_X86_64 +#define LT_ELFCLASS2 ELFCLASS32 +#define LT_ELF_MACHINE2 EM_386 + +/* __NR_fork, __NR_clone, __NR_clone2, __NR_vfork and __NR_execve + from asm-i386/unistd.h. */ +#define FORK_EXEC_SYSCALLS , { 2, 120, -1, 190, 11 } diff --git a/sysdeps/linux-gnu/x86_64/ffcheck.c b/sysdeps/linux-gnu/x86_64/ffcheck.c new file mode 100644 index 0000000..e69de29 diff --git a/sysdeps/linux-gnu/x86_64/plt.c b/sysdeps/linux-gnu/x86_64/plt.c new file mode 100644 index 0000000..b53ff44 --- /dev/null +++ b/sysdeps/linux-gnu/x86_64/plt.c @@ -0,0 +1,12 @@ +#include +#include "common.h" + +GElf_Addr +arch_plt_sym_val(struct ltelf *lte, size_t ndx, GElf_Rela * rela) { + return lte->plt_addr + (ndx + 1) * 16; +} + +void * +sym2addr(Process *proc, struct library_symbol *sym) { + return sym->enter_addr; +} diff --git a/sysdeps/linux-gnu/x86_64/ptrace.h b/sysdeps/linux-gnu/x86_64/ptrace.h new file mode 100644 index 0000000..c3cbcb6 --- /dev/null +++ b/sysdeps/linux-gnu/x86_64/ptrace.h @@ -0,0 +1 @@ +#include diff --git a/sysdeps/linux-gnu/x86_64/regs.c b/sysdeps/linux-gnu/x86_64/regs.c new file mode 100644 index 0000000..ed1f118 --- /dev/null +++ b/sysdeps/linux-gnu/x86_64/regs.c @@ -0,0 +1,54 @@ +#include "config.h" + +#include +#include +#include + +#include "common.h" + +#if (!defined(PTRACE_PEEKUSER) && defined(PTRACE_PEEKUSR)) +# define PTRACE_PEEKUSER PTRACE_PEEKUSR +#endif + +#if (!defined(PTRACE_POKEUSER) && defined(PTRACE_POKEUSR)) +# define PTRACE_POKEUSER PTRACE_POKEUSR +#endif + +void * +get_instruction_pointer(Process *proc) { + long int ret = ptrace(PTRACE_PEEKUSER, proc->pid, 8 * RIP, 0); + if (proc->mask_32bit) + ret &= 0xffffffff; + return (void *)ret; +} + +void +set_instruction_pointer(Process *proc, void *addr) { + if (proc->mask_32bit) + addr = (void *)((long int)addr & 0xffffffff); + ptrace(PTRACE_POKEUSER, proc->pid, 8 * RIP, addr); +} + +void * +get_stack_pointer(Process *proc) { + long int ret = ptrace(PTRACE_PEEKUSER, proc->pid, 8 * RSP, 0); + if (proc->mask_32bit) + ret &= 0xffffffff; + return (void *)ret; +} + +void * +get_return_addr(Process *proc, void *stack_pointer) { + unsigned long int ret; + ret = ptrace(PTRACE_PEEKTEXT, proc->pid, stack_pointer, 0); + if (proc->mask_32bit) + ret &= 0xffffffff; + return (void *)ret; +} + +void +set_return_addr(Process *proc, void *addr) { + if (proc->mask_32bit) + addr = (void *)((long int)addr & 0xffffffff); + ptrace(PTRACE_POKETEXT, proc->pid, proc->stack_pointer, addr); +} diff --git a/sysdeps/linux-gnu/x86_64/signalent.h b/sysdeps/linux-gnu/x86_64/signalent.h new file mode 100644 index 0000000..d58a36c --- /dev/null +++ b/sysdeps/linux-gnu/x86_64/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 */ + "SIGSYS", /* 31 */ diff --git a/sysdeps/linux-gnu/x86_64/signalent1.h b/sysdeps/linux-gnu/x86_64/signalent1.h new file mode 100644 index 0000000..5ead946 --- /dev/null +++ b/sysdeps/linux-gnu/x86_64/signalent1.h @@ -0,0 +1 @@ +#include "i386/signalent.h" diff --git a/sysdeps/linux-gnu/x86_64/syscallent.h b/sysdeps/linux-gnu/x86_64/syscallent.h new file mode 100644 index 0000000..5e5f88a --- /dev/null +++ b/sysdeps/linux-gnu/x86_64/syscallent.h @@ -0,0 +1,256 @@ +"read", /* 0 */ + "write", /* 1 */ + "open", /* 2 */ + "close", /* 3 */ + "stat", /* 4 */ + "fstat", /* 5 */ + "lstat", /* 6 */ + "poll", /* 7 */ + "lseek", /* 8 */ + "mmap", /* 9 */ + "mprotect", /* 10 */ + "munmap", /* 11 */ + "brk", /* 12 */ + "rt_sigaction", /* 13 */ + "rt_sigprocmask", /* 14 */ + "rt_sigreturn", /* 15 */ + "ioctl", /* 16 */ + "pread", /* 17 */ + "pwrite", /* 18 */ + "readv", /* 19 */ + "writev", /* 20 */ + "access", /* 21 */ + "pipe", /* 22 */ + "select", /* 23 */ + "sched_yield", /* 24 */ + "mremap", /* 25 */ + "msync", /* 26 */ + "mincore", /* 27 */ + "madvise", /* 28 */ + "shmget", /* 29 */ + "shmat", /* 30 */ + "shmctl", /* 31 */ + "dup", /* 32 */ + "dup2", /* 33 */ + "pause", /* 34 */ + "nanosleep", /* 35 */ + "getitimer", /* 36 */ + "alarm", /* 37 */ + "setitimer", /* 38 */ + "getpid", /* 39 */ + "sendfile", /* 40 */ + "socket", /* 41 */ + "connect", /* 42 */ + "accept", /* 43 */ + "sendto", /* 44 */ + "recvfrom", /* 45 */ + "sendmsg", /* 46 */ + "recvmsg", /* 47 */ + "shutdown", /* 48 */ + "bind", /* 49 */ + "listen", /* 50 */ + "getsockname", /* 51 */ + "getpeername", /* 52 */ + "socketpair", /* 53 */ + "setsockopt", /* 54 */ + "getsockopt", /* 55 */ + "clone", /* 56 */ + "fork", /* 57 */ + "vfork", /* 58 */ + "execve", /* 59 */ + "exit", /* 60 */ + "wait4", /* 61 */ + "kill", /* 62 */ + "uname", /* 63 */ + "semget", /* 64 */ + "semop", /* 65 */ + "semctl", /* 66 */ + "shmdt", /* 67 */ + "msgget", /* 68 */ + "msgsnd", /* 69 */ + "msgrcv", /* 70 */ + "msgctl", /* 71 */ + "fcntl", /* 72 */ + "flock", /* 73 */ + "fsync", /* 74 */ + "fdatasync", /* 75 */ + "truncate", /* 76 */ + "ftruncate", /* 77 */ + "getdents", /* 78 */ + "getcwd", /* 79 */ + "chdir", /* 80 */ + "fchdir", /* 81 */ + "rename", /* 82 */ + "mkdir", /* 83 */ + "rmdir", /* 84 */ + "creat", /* 85 */ + "link", /* 86 */ + "unlink", /* 87 */ + "symlink", /* 88 */ + "readlink", /* 89 */ + "chmod", /* 90 */ + "fchmod", /* 91 */ + "chown", /* 92 */ + "fchown", /* 93 */ + "lchown", /* 94 */ + "umask", /* 95 */ + "gettimeofday", /* 96 */ + "getrlimit", /* 97 */ + "getrusage", /* 98 */ + "sysinfo", /* 99 */ + "times", /* 100 */ + "ptrace", /* 101 */ + "getuid", /* 102 */ + "syslog", /* 103 */ + "getgid", /* 104 */ + "setuid", /* 105 */ + "setgid", /* 106 */ + "geteuid", /* 107 */ + "getegid", /* 108 */ + "setpgid", /* 109 */ + "getppid", /* 110 */ + "getpgrp", /* 111 */ + "setsid", /* 112 */ + "setreuid", /* 113 */ + "setregid", /* 114 */ + "getgroups", /* 115 */ + "setgroups", /* 116 */ + "setresuid", /* 117 */ + "getresuid", /* 118 */ + "setresgid", /* 119 */ + "getresgid", /* 120 */ + "getpgid", /* 121 */ + "setfsuid", /* 122 */ + "setfsgid", /* 123 */ + "getsid", /* 124 */ + "capget", /* 125 */ + "capset", /* 126 */ + "rt_sigpending", /* 127 */ + "rt_sigtimedwait", /* 128 */ + "rt_sigqueueinfo", /* 129 */ + "rt_sigsuspend", /* 130 */ + "sigaltstack", /* 131 */ + "utime", /* 132 */ + "mknod", /* 133 */ + "uselib", /* 134 */ + "personality", /* 135 */ + "ustat", /* 136 */ + "statfs", /* 137 */ + "fstatfs", /* 138 */ + "sysfs", /* 139 */ + "getpriority", /* 140 */ + "setpriority", /* 141 */ + "sched_setparam", /* 142 */ + "sched_getparam", /* 143 */ + "sched_setscheduler", /* 144 */ + "sched_getscheduler", /* 145 */ + "sched_get_priority_max", /* 146 */ + "sched_get_priority_min", /* 147 */ + "sched_rr_get_interval", /* 148 */ + "mlock", /* 149 */ + "munlock", /* 150 */ + "mlockall", /* 151 */ + "munlockall", /* 152 */ + "vhangup", /* 153 */ + "modify_ldt", /* 154 */ + "pivot_root", /* 155 */ + "_sysctl", /* 156 */ + "prctl", /* 157 */ + "arch_prctl", /* 158 */ + "adjtimex", /* 159 */ + "setrlimit", /* 160 */ + "chroot", /* 161 */ + "sync", /* 162 */ + "acct", /* 163 */ + "settimeofday", /* 164 */ + "mount", /* 165 */ + "umount2", /* 166 */ + "swapon", /* 167 */ + "swapoff", /* 168 */ + "reboot", /* 169 */ + "sethostname", /* 170 */ + "setdomainname", /* 171 */ + "iopl", /* 172 */ + "ioperm", /* 173 */ + "create_module", /* 174 */ + "init_module", /* 175 */ + "delete_module", /* 176 */ + "get_kernel_syms", /* 177 */ + "query_module", /* 178 */ + "quotactl", /* 179 */ + "nfsservctl", /* 180 */ + "getpmsg", /* 181 */ + "putpmsg", /* 182 */ + "afs_syscall", /* 183 */ + "tuxcall", /* 184 */ + "security", /* 185 */ + "gettid", /* 186 */ + "readahead", /* 187 */ + "setxattr", /* 188 */ + "lsetxattr", /* 189 */ + "fsetxattr", /* 190 */ + "getxattr", /* 191 */ + "lgetxattr", /* 192 */ + "fgetxattr", /* 193 */ + "listxattr", /* 194 */ + "llistxattr", /* 195 */ + "flistxattr", /* 196 */ + "removexattr", /* 197 */ + "lremovexattr", /* 198 */ + "fremovexattr", /* 199 */ + "tkill", /* 200 */ + "time", /* 201 */ + "futex", /* 202 */ + "sched_setaffinity", /* 203 */ + "sched_getaffinity", /* 204 */ + "set_thread_area", /* 205 */ + "io_setup", /* 206 */ + "io_destroy", /* 207 */ + "io_getevents", /* 208 */ + "io_submit", /* 209 */ + "io_cancel", /* 210 */ + "get_thread_area", /* 211 */ + "lookup_dcookie", /* 212 */ + "epoll_create", /* 213 */ + "epoll_ctl", /* 214 */ + "epoll_wait", /* 215 */ + "remap_file_pages", /* 216 */ + "getdents64", /* 217 */ + "set_tid_address", /* 218 */ + "restart_syscall", /* 219 */ + "semtimedop", /* 220 */ + "fadvise64", /* 221 */ + "timer_create", /* 222 */ + "timer_settime", /* 223 */ + "timer_gettime", /* 224 */ + "timer_getoverrun", /* 225 */ + "timer_delete", /* 226 */ + "clock_settime", /* 227 */ + "clock_gettime", /* 228 */ + "clock_getres", /* 229 */ + "clock_nanosleep", /* 230 */ + "exit_group", /* 231 */ + "epoll_wait", /* 232 */ + "epoll_ctl", /* 233 */ + "tgkill", /* 234 */ + "utimes", /* 235 */ + "vserver", /* 236 */ + "mbind", /* 237 */ + "set_mempolicy", /* 238 */ + "get_mempolicy", /* 239 */ + "mq_open", /* 240 */ + "mq_unlink", /* 241 */ + "mq_timedsend", /* 242 */ + "mq_timedreceive", /* 243 */ + "mq_notify", /* 244 */ + "mq_getsetattr", /* 245 */ + "kexec_load", /* 246 */ + "waitid", /* 247 */ + "add_key", /* 248 */ + "request_key", /* 249 */ + "keyctl", /* 250 */ + "ioprio_set", /* 251 */ + "ioprio_get", /* 252 */ + "inotify_init", /* 253 */ + "inotify_add_watch", /* 254 */ + "inotify_rm_watch", /* 255 */ diff --git a/sysdeps/linux-gnu/x86_64/syscallent1.h b/sysdeps/linux-gnu/x86_64/syscallent1.h new file mode 100644 index 0000000..d8dd9f7 --- /dev/null +++ b/sysdeps/linux-gnu/x86_64/syscallent1.h @@ -0,0 +1 @@ +#include "i386/syscallent.h" diff --git a/sysdeps/linux-gnu/x86_64/trace.c b/sysdeps/linux-gnu/x86_64/trace.c new file mode 100644 index 0000000..189734d --- /dev/null +++ b/sysdeps/linux-gnu/x86_64/trace.c @@ -0,0 +1,144 @@ +#include "config.h" + +#include +#include +#include +#include +#include +#include + +#include "common.h" + +#if (!defined(PTRACE_PEEKUSER) && defined(PTRACE_PEEKUSR)) +# define PTRACE_PEEKUSER PTRACE_PEEKUSR +#endif + +#if (!defined(PTRACE_POKEUSER) && defined(PTRACE_POKEUSR)) +# define PTRACE_POKEUSER PTRACE_POKEUSR +#endif + +void +get_arch_dep(Process *proc) { + unsigned long cs; + if (proc->arch_ptr) + return; + cs = ptrace(PTRACE_PEEKUSER, proc->pid, 8 * CS, 0); + if (cs == 0x23) { + proc->mask_32bit = 1; + proc->personality = 1; + } + proc->arch_ptr = (void *)1; +} + +/* Returns 1 if syscall, 2 if sysret, 0 otherwise. + */ +int +syscall_p(Process *proc, int status, int *sysnum) { + if (WIFSTOPPED(status) + && WSTOPSIG(status) == (SIGTRAP | proc->tracesysgood)) { + *sysnum = ptrace(PTRACE_PEEKUSER, proc->pid, 8 * ORIG_RAX, 0); + + if (proc->callstack_depth > 0 && + proc->callstack[proc->callstack_depth - 1].is_syscall && + proc->callstack[proc->callstack_depth - 1].c_un.syscall == *sysnum) { + return 2; + } + + if (*sysnum >= 0) { + return 1; + } + } + return 0; +} + +static unsigned int +gimme_arg32(enum tof type, Process *proc, int arg_num) { + if (arg_num == -1) { /* return value */ + return ptrace(PTRACE_PEEKUSER, proc->pid, 8 * RAX, 0); + } + + if (type == LT_TOF_FUNCTION || type == LT_TOF_FUNCTIONR) { + return ptrace(PTRACE_PEEKTEXT, proc->pid, + proc->stack_pointer + 4 * (arg_num + 1), 0); + } else if (type == LT_TOF_SYSCALL || type == LT_TOF_SYSCALLR) { + switch (arg_num) { + case 0: + return ptrace(PTRACE_PEEKUSER, proc->pid, 8 * RBX, 0); + case 1: + return ptrace(PTRACE_PEEKUSER, proc->pid, 8 * RCX, 0); + case 2: + return ptrace(PTRACE_PEEKUSER, proc->pid, 8 * RDX, 0); + case 3: + return ptrace(PTRACE_PEEKUSER, proc->pid, 8 * RSI, 0); + case 4: + return ptrace(PTRACE_PEEKUSER, proc->pid, 8 * RDI, 0); + case 5: + return ptrace(PTRACE_PEEKUSER, proc->pid, 8 * RBP, 0); + default: + fprintf(stderr, + "gimme_arg32 called with wrong arguments\n"); + exit(2); + } + } + fprintf(stderr, "gimme_arg called with wrong arguments\n"); + exit(1); +} + +long +gimme_arg(enum tof type, Process *proc, int arg_num, arg_type_info *info) { + if (proc->mask_32bit) + return (unsigned int)gimme_arg32(type, proc, arg_num); + + if (arg_num == -1) { /* return value */ + return ptrace(PTRACE_PEEKUSER, proc->pid, 8 * RAX, 0); + } + + if (type == LT_TOF_FUNCTION || type == LT_TOF_FUNCTIONR) { + switch (arg_num) { + case 0: + return ptrace(PTRACE_PEEKUSER, proc->pid, 8 * RDI, 0); + case 1: + return ptrace(PTRACE_PEEKUSER, proc->pid, 8 * RSI, 0); + case 2: + return ptrace(PTRACE_PEEKUSER, proc->pid, 8 * RDX, 0); + case 3: + return ptrace(PTRACE_PEEKUSER, proc->pid, 8 * RCX, 0); + case 4: + return ptrace(PTRACE_PEEKUSER, proc->pid, 8 * R8, 0); + case 5: + return ptrace(PTRACE_PEEKUSER, proc->pid, 8 * R9, 0); + default: + return ptrace(PTRACE_PEEKTEXT, proc->pid, + proc->stack_pointer + 8 * (arg_num - 6 + + 1), 0); + } + } else if (type == LT_TOF_SYSCALL || LT_TOF_SYSCALLR) { + switch (arg_num) { + case 0: + return ptrace(PTRACE_PEEKUSER, proc->pid, 8 * RDI, 0); + case 1: + return ptrace(PTRACE_PEEKUSER, proc->pid, 8 * RSI, 0); + case 2: + return ptrace(PTRACE_PEEKUSER, proc->pid, 8 * RDX, 0); + case 3: + return ptrace(PTRACE_PEEKUSER, proc->pid, 8 * R10, 0); + case 4: + return ptrace(PTRACE_PEEKUSER, proc->pid, 8 * R8, 0); + case 5: + return ptrace(PTRACE_PEEKUSER, proc->pid, 8 * R9, 0); + default: + fprintf(stderr, + "gimme_arg called with wrong arguments\n"); + exit(2); + } + } else { + fprintf(stderr, "gimme_arg called with wrong arguments\n"); + exit(1); + } + + return 0; +} + +void +save_register_args(enum tof type, Process *proc) { +} diff --git a/testsuite/Makefile b/testsuite/Makefile new file mode 100644 index 0000000..b78807e --- /dev/null +++ b/testsuite/Makefile @@ -0,0 +1,71 @@ +# Copyright (C) 1992 - 2001 Free Software Foundation, Inc. +# +# 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 +# the Free Software Foundation; either version 1, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# 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. +# + +AUTOMAKE_OPTIONS = dejagnu +EXPECT = expect +RUNTEST = runtest +CC = @CC@ + +srcdir = . +RUNTESTDEFAULTFLAGS = --srcdir $(srcdir) + +CLEANFILES = *.log *.sum site.bak setval.tmp site.exp + +SUBDIRS = ltrace.main ltrace.minor ltrace.torture + +#all: all-recursive + +.SUFFIXES: + +check-DEJAGNU: site.exp + EXPECT=$(EXPECT); export EXPECT; + @$(RUNTEST) $(RUNTESTDEFAULTFLAGS) $(RUNTESTFLAGS); + +site.exp: + @echo 'Making a new site.exp file...' + @echo '## these variables are automatically generated by make ##' >site.tmp + @echo '# Do not edit here. If you wish to override these values' >>site.tmp + @echo '# edit the last section' >>site.tmp + @echo 'set srcdir $(srcdir)' >>site.tmp + @echo "set objdir `pwd`" >>site.tmp + @echo '## All variables above are generated by configure. Do Not Edit ##' >>site.tmp + @test ! -f site.exp || \ + sed '1,/^## All variables above are.*##/ d' site.exp >> site.tmp + @-rm -f site.bak + @test ! -f site.exp || mv site.exp site.bak + @mv site.tmp site.exp + +check: check-DEJAGNU + +clean: + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making clean in $$subdir"; \ + (cd $$subdir && $(MAKE) clean ) done; + + -rm -f $(CLEANFILES) + +distclean: + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making clean in $$subdir"; \ + (cd $$subdir && $(MAKE) distclean ) done; + -rm -f $(CLEANFILES) + +.PHONY: $(RECURSIVE_TARGETS) check clean distclean realclean + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/testsuite/README b/testsuite/README new file mode 100644 index 0000000..63d2b3b --- /dev/null +++ b/testsuite/README @@ -0,0 +1,244 @@ + README for ltrace testsuite + 18, October, 2005 by Yao Qi + +This is the README file for ltrace testsuite. + +Quick Overview +============== + + This testsuite is based on the dejagnu framework, which is again +dependent on Expect and Tcl. So all these three package (tcl, expect +and dejagnu) should be installed on your system before running these +tests. + + After unpacking file ltrace-0.3.36.tar.gz: + + tar -zxvfm ltrace-0.3.36.tar.gz + + you'll find a directory named ltrace-0.3.36, which contains: + + debian etc testsuite sysdeps + +you can first build this package, then run the testsuite in the +following steps: + + 1 cd ltrace-0.3.36 + + 2 Confiugre ltrace for 32-bit mode or 64-bit mode. + ./configure + OR CC='gcc -m64' ./configure + + 3 Build ltace + make + + 4 Run all the test in default mode. + make check + + The default is to test the ltrace just built, using the default +compiler options. You can control this by adding a symbol to 'make check': + + To test the shipped ltrace tool (as opposed to the just built by "make") + + --tool_exec=/usr/bin/ltrace + + To change compiler switches for the target test cases + + CFLAGS_FOR_TARGET=-m64 + + To change the target compiler (instead of shipped gcc) + + CC_FOR_TARGET=/opt/gcc-4.0/bin/gcc + + + You can run all the tests in different mode respectively as follows, + + (1) ./run-my-tests.sh -m32 + OR make check + + (test ltrace in build tree and compile test cases in 32-bit mode) + + (2) ./run-my-tests.sh -m64 + OR make check RUNTESTFLAGS="CFLAGS_FOR_TARGET=-m64" + + (test ltrace in build tree and compile test cases in 64-bit mode) + + (3) ./run-my-tests.sh -m32 /usr/bin/ltrace + OR make check RUNTESTFLAGS="--tool_exec=/usr/bin/ltrace" + + (test shipped ltrace and compile test cases in 32-bit mode) + + (4) ./run-my-tests.sh -m64 /usr/bin/ltrace + OR make check RUNTESTFLAGS="--tool_exec=/usr/bin/ltrace CFLAGS_FOR_TARGET=-m64" + + (run shipped ltrace and compile test cases in 64-bit mode) + + (5) cd testsuite; make test + + (run ltrace in build tree and compile test cases same as ltrace itself) + + + (6) make check RUNTESTFLAGS="--tool_exec=/usr/bin/ltrace CFLAGS_FOR_TARGET=-m64 CC_FOR_TARGET=/opt/gcc-4.0/bin/gcc" + + (run shipped ltrace and compile test cases in 64 bit mode by /opt/gcc-4.0/bin/gcc) +Ltrace Testsuite +================ + + This testsuite for ltrace is a DejaGNU based testsuite that can +either be used to test your newly built ltrace, or for regression +testing a ltrace with local modifications. + + Running the testsuite requires the prior installation of DejaGNU. +The directory ftp://sources.redhat.com/pub/dejagnu/ will contain a +recent snapshot. Once DejaGNU is installed or built and add the +location of runtest into $PATH, you can run the tests in one of the +four ways it mentioned in Quick Overview. The DejaGNU framework could +be built in following steps: + + 1 Uppack these three packages. + tar zxvf dejagnu-1.4.4.tar.gz + tar zxvf tcl8.4.9-src.tar.gz + tar zxvf expect-5.43.0.tar.gz + + 2 Build them and install. + cd dejagnu-1.4.4 + ./configure + make + make install + cd .. + + cd tcl8.4.9/unix + ./configure + make + make install + cd .. + + cd expect-5.43 + ./configure + make + make install + cd .. + + See the DejaGNU documentation and dejagnu-1.4.4/README for further +details. + + +Componets in ltrace testsuite +============================= + + This testsuite include all the source code you need for ltrace +test in a single directory, which is "ltrace-0.3.36/testsuite". +This directory includes the following files and sub-directories: + +`config/unix.exp` + configuration file for dejagnu-based test. + +`lib/ltrace.exp` + some basic functions used in all the test cases. + +`ltrace.main/` + some basic tests for major fetures of ltrace. + + (1) ltrace.main/main.exp does tests on tracing a function +implemented in a shared library. + + (2) ltrace.main/main-internal.exp does tests on tracing a function +implemented in main executable. + + (3) ltrace.main/signals.exp do test on tracing user-defined signals +sent by program to itself. + + (4) ltrace.main/system_calls.exp do test on tracing all the system +calls in program. + +`ltrace.minor/` + some tests for minor fetures of ltrace. + + (1) ltrace.minor/attach-process.exp do test on attching a process. + + (2) ltrace.minor/count-record.exp do test on counting time and +calls. + + (3) ltrace.minor/demangle.exp do test on demangling the C++ symbols. + + (4) ltrace.minor/time-record-T.exp do test on showing the time spent +inside each call. + + (5) ltrace.minor/time-record-tt.exp + (6) ltrace.minor/time-record-ttt.exp do test on printing absolute +timestamps in different format. + + (7) ltrace.minor/trace-clone.exp do test on following clone to child +process. + + (8) ltrace.minor/trace-fork.exp do test on following fork to child +process. + +`ltrace.torture/` + some tests in extreme condations. + + (1) ltrace.torture/signals.exp do test on tracing flooded signals +send to program itself. + +Trouble shootings +================= + + (1) Running ltrace with -u option requires the superuser privilege. +You must make sure you are root or have already got root's password. + + (2) Check the *.ltrace files in each ltrace.* directories if there are +some FAILs in the output. They are informative. + + (3) Add --verbose option in RUNTESTFLAGS when 'make check' if you want +to see more details of these tests. + +Test case extension +=================== + + Current testsuite is quite basic. The framework of testsuite is +extendable and scalealbe, so you can add new testcases into it easily. +I will describe how to do that in different ways. + + (1) Add new test case in an existed testcase directory. + + It is simple. Just add a foo.exp script and a relevant foo.c if +necessary. The dejagnu framework can run that script automatically when +you run "make check". The executable and object file would be generate +in the test, please add them in 'clean' entry in Makefile.in to ensure +that they could be cleaned up automatically when run 'make clean'. + + (2) Add new test case in a new testcase directory. + + It is a little complicated. Fisrt create a new directory in +testsuite/ with the same pattern as others, for example ltrace.bar, +and then create a Makefile.in, an Expect script foo.exp, and relative +foo.c if necessary. Then modify the configure.ac in ltrace-0.3.36/, +and add "testsuite/ltrace.bar/Makefile" into macro AC_OUTPUT, +testsuite/ltrace.bar/Makefile will be generated when you configure +this package. + + Adding Makefile.in in the new directroy is just to remove +intermediate files and log files automatically later, such as foo.ltrace, +object files and executables. For example, if you want to remove A.ltrace, +B.ltrace, A and B at the time of cleanup, you can write Makefile.in +like this: + + clean: + -rm -f A B + -rm -f *.o + -rm -f *.ltrace + distclean: clean + -rm -f Makefile + + At last add the new directory 'ltrace.bar' into the macro SUBDIRS +in testsuite/Makefile.in. + + Rerun the autoconf and ./configure in ./ltrace-0.3.36, the Makefile +will be updated. + + + +^L +(this is for editing this file with GNU emacs) +Local Variables: +mode: text +End: diff --git a/testsuite/config/unix.exp b/testsuite/config/unix.exp new file mode 100644 index 0000000..29d28a2 --- /dev/null +++ b/testsuite/config/unix.exp @@ -0,0 +1 @@ +load_lib ltrace.exp diff --git a/testsuite/lib/compiler.c b/testsuite/lib/compiler.c new file mode 100644 index 0000000..e6b1ec6 --- /dev/null +++ b/testsuite/lib/compiler.c @@ -0,0 +1,58 @@ +/* This test file is part of GDB, the GNU debugger. + + Copyright 1995, 1997, 1999, 2003, 2004 Free Software Foundation, Inc. + + 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + +/* Sometimes the behavior of a test depends upon the compiler used to + compile the test program. A test script can call get_compiler_info + to figure out the compiler version and test_compiler_info to test it. + + get_compiler_info runs the preprocessor on this file and then eval's + the result. This sets various symbols for use by test_compiler_info. + + TODO: make compiler_info a local variable for get_compiler_info and + test_compiler_info. + + TODO: all clients should use test_compiler_info and should not + use gcc_compiled, hp_cc_compiler, or hp_aCC_compiler. + + */ + +/* Note the semicolon at the end of this line. Older versions of + hp c++ have a bug in string preprocessing: if the last token on a + line is a string, then the preprocessor concatenates the next line + onto the current line and eats the newline! That messes up TCL of + course. That happens with HP aC++ A.03.13, but it no longer happens + with HP aC++ A.03.45. */ + +set compiler_info "unknown" ; + +#if defined (__GNUC__) +#if defined (__GNUC_PATCHLEVEL__) +/* Only GCC versions >= 3.0 define the __GNUC_PATCHLEVEL__ macro. */ +set compiler_info [join {gcc __GNUC__ __GNUC_MINOR__ __GNUC_PATCHLEVEL__} -] +#else +set compiler_info [join {gcc __GNUC__ __GNUC_MINOR__ "unknown"} -] +#endif +#endif + +#if defined (__xlc__) +/* IBM'x xlc compiler. NOTE: __xlc__ expands to a double quoted string of four + numbers seperated by '.'s: currently "7.0.0.0" */ +set need_a_set [regsub -all {\.} [join {xlc __xlc__} -] - compiler_info] +#endif diff --git a/testsuite/lib/compiler.cc b/testsuite/lib/compiler.cc new file mode 100644 index 0000000..7068462 --- /dev/null +++ b/testsuite/lib/compiler.cc @@ -0,0 +1,45 @@ +/* This test file is part of GDB, the GNU debugger. + + Copyright 1995, 1999, 2003, 2004 Free Software Foundation, Inc. + + 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 + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + */ + +/* This file is exactly like compiler.c. I could just use compiler.c if + I could be sure that every C++ compiler accepted extensions of ".c". */ + +/* Note the semicolon at the end of this line. Older versions of + hp c++ have a bug in string preprocessing: if the last token on a + line is a string, then the preprocessor concatenates the next line + onto the current line and eats the newline! That messes up TCL of + course. That happens with HP aC++ A.03.13, but it no longer happens + with HP aC++ A.03.45. */ + +set compiler_info "unknown" ; + +#if defined (__GNUC__) +#if defined (__GNUC_PATCHLEVEL__) +/* Only GCC versions >= 3.0 define the __GNUC_PATCHLEVEL__ macro. */ +set compiler_info [join {gcc __GNUC__ __GNUC_MINOR__ __GNUC_PATCHLEVEL__} -] +#else +set compiler_info [join {gcc __GNUC__ __GNUC_MINOR__ "unknown"} -] +#endif +#endif + +#if defined (__xlC__) +/* xlC++ version like 800 */ +set compiler_info [join {xlc++ __IBMCPP__} -] +#endif diff --git a/testsuite/lib/ltrace.exp b/testsuite/lib/ltrace.exp new file mode 100644 index 0000000..b56d50d --- /dev/null +++ b/testsuite/lib/ltrace.exp @@ -0,0 +1,279 @@ +# This file was written by Yao Qi. (qiyao@cn.ibm.com) + +# Generic ltrace test subroutines that should work for any target. If these +# need to be modified for any target, it can be done with a variable +# or by passing arguments. + + +global LTRACE +if [info exists TOOL_EXECUTABLE] { + set LTRACE $TOOL_EXECUTABLE +} else { + set LTRACE $objdir/../ltrace +} + +global LTRACE_OPTIONS +set LTRACE_OPTIONS ""; + +# ltrace_compile SOURCE DEST TYPE OPTIONS +# +# Compile PUT(program under test) by native compiler. ltrace_compile runs +# the right compiler, and TCL captures the output, and I evaluate the output. +# +# SOURCE is the name of program under test, with full directory. +# DEST is the name of output of compilation, with full directory. +# TYPE is an enum-like variable to affect the format or result of compiler +# output. Values: +# executable if output is an executable. +# object if output is an object. +# OPTIONS is option to compiler in this compilation. +proc ltrace_compile {source dest type options} { + global LTRACE_TESTCASE_OPTIONS; + + # Add platform-specific options if a shared library was specified using + # "shlib=librarypath" in OPTIONS. + set new_options "" + set shlib_found 0 + + foreach opt $options { + if [regexp {^shlib=(.*)} $opt dummy_var shlib_name] { + if [test_compiler_info "xlc*"] { + # IBM xlc compiler doesn't accept shared library named other + # than .so: use "-Wl," to bypass this + lappend source "-Wl,$shlib_name" + } else { + lappend source $shlib_name + } + + if {$shlib_found == 0} { + set shlib_found 1 + + if { ([test_compiler_info "gcc-*"]&& ([istarget "powerpc*-*-aix*"]|| [istarget "rs6000*-*-aix*"] ))} { + lappend options "additional_flags=-L${objdir}/${subdir}" + } elseif { [istarget "mips-sgi-irix*"] } { + lappend options "additional_flags=-rpath ${objdir}/${subdir}" + } + } + + } else { + lappend new_options $opt + } + } + #end of for loop + set options $new_options + # dump some information for debug purpose. + verbose "options are $options" + verbose "source is $source $dest $type $options" + + set result [target_compile $source $dest $type $options]; + verbose "result is $result" + regsub "\[\r\n\]*$" "$result" "" result; + regsub "^\[\r\n\]*" "$result" "" result; + if { $result != "" && [lsearch $options quiet] == -1} { + clone_output "compile failed for ltrace test, $result" + } + return $result; +} + +proc get_compiler_info {binfile args} { + # For compiler.c and compiler.cc + global srcdir + + # I am going to play with the log to keep noise out. + global outdir + global tool + + # These come from compiler.c or compiler.cc + global compiler_info + + # Legacy global data symbols. + #global gcc_compiled + + # Choose which file to preprocess. + set ifile "${srcdir}/lib/compiler.c" + if { [llength $args] > 0 && [lindex $args 0] == "c++" } { + set ifile "${srcdir}/lib/compiler.cc" + } + + # Run $ifile through the right preprocessor. + # Toggle ltrace.log to keep the compiler output out of the log. + #log_file + set cppout [ ltrace_compile "${ifile}" "" preprocess [list "$args" quiet] ] + #log_file -a "$outdir/$tool.log" + + # Eval the output. + set unknown 0 + foreach cppline [ split "$cppout" "\n" ] { + if { [ regexp "^#" "$cppline" ] } { + # line marker + } elseif { [ regexp "^\[\n\r\t \]*$" "$cppline" ] } { + # blank line + } elseif { [ regexp "^\[\n\r\t \]*set\[\n\r\t \]" "$cppline" ] } { + # eval this line + verbose "get_compiler_info: $cppline" 2 + eval "$cppline" + } else { + # unknown line + verbose "get_compiler_info: $cppline" + set unknown 1 + } + } + + # Reset to unknown compiler if any diagnostics happened. + if { $unknown } { + set compiler_info "unknown" + } + return 0 +} + +proc test_compiler_info { {compiler ""} } { + global compiler_info + verbose "compiler_info=$compiler_info" + # if no arg, return the compiler_info string + + if [string match "" $compiler] { + if [info exists compiler_info] { + return $compiler_info + } else { + perror "No compiler info found." + } + } + + return [string match $compiler $compiler_info] +} + +proc ltrace_compile_shlib {sources dest options} { + set obj_options $options + verbose "+++++++ [test_compiler_info]" + switch -glob [test_compiler_info] { + "xlc-*" { + lappend obj_options "additional_flags=-qpic" + } + "gcc-*" { + if { !([istarget "powerpc*-*-aix*"] + || [istarget "rs6000*-*-aix*"]) } { + lappend obj_options "additional_flags=-fpic" + } + } + "xlc++-*" { + lappend obj_options "additional_flags=-qpic" + } + + default { + fail "Bad compiler!" + } + } + + set outdir [file dirname $dest] + set objects "" + foreach source $sources { + set sourcebase [file tail $source] + if {[ltrace_compile $source "${outdir}/${sourcebase}.o" object $obj_options] != ""} { + return -1 + } + lappend objects ${outdir}/${sourcebase}.o + } + + set link_options $options + if { [test_compiler_info "xlc-*"] || [test_compiler_info "xlc++-*"]} { + lappend link_options "additional_flags=-qmkshrobj" + } else { + lappend link_options "additional_flags=-shared" + } + if {[ltrace_compile "${objects}" "${dest}" executable $link_options] != ""} { + return -1 + } +} + +# +# ltrace_options OPTIONS_LIST +# Pass ltrace commandline options. +# +proc ltrace_options { args } { + + global LTRACE_OPTIONS + set LTRACE_OPTIONS $args +} + +# +# ltrace_runtest LD_LIBRARY_PATH BIN FILE +# Trace the execution of BIN and return result. +# +# BIN is program-under-test. +# LD_LIBRARY_PATH is the env for program-under-test to run. +# FILE is to save the output from ltrace with default name $BIN.ltrace. +# Retrun output from ltrace. +# +proc ltrace_runtest { args } { + + global LTRACE + global LTRACE_OPTIONS + + verbose "LTRACE = $LTRACE" + + set LD_LIBRARY_PATH_ [lindex $args 0] + set BIN [lindex $args 1] + + # specify the output file, the default one is $BIN.ltrace + if [llength $args]==3 then { + set file [lindex $args 2] + } else { + set file $BIN.ltrace + } + # append this option to LTRACE_OPTIONS. + lappend LTRACE_OPTIONS "-o" + lappend LTRACE_OPTIONS "$file" + verbose "LTRACE_OPTIONS = $LTRACE_OPTIONS" + #ltrace the PUT. + catch "exec sh -c {export LD_LIBRARY_PATH=$LD_LIBRARY_PATH_; $LTRACE $LTRACE_OPTIONS $BIN;exit}" output + + # return output from ltrace. + return $output +} + +# +# ltrace_saveoutput OUTPUT FILE +# Save OUTPUT from ltrace to file FILE. +# OUTPUT is output from ltrace or return value of ltrace_runtest. +# FILE is file save output. +# +proc ltrace_saveoutput { args } { + + set output [lindex $args 0] + set file [lindex $args 1] + + set fd [open $file w] + puts $fd $output + close $fd +} + + +# +# ltrace_verify_output FILE_TO_SEARCH PATTERN MAX_LINE +# Verify the ltrace output by comparing the number of PATTERN in +# FILE_TO_SEARCH with INSTANCE_NO. Do not specify INSTANCE_NO if +# instance number is ignored in this test. +# Reutrn: +# 0 = number of PATTERN in FILE_TO_SEARCH inqual to INSTANCE_NO. +# 1 = number of PATTERN in FILE_TO_SEARCH qual to INSTANCE_NO. +# +proc ltrace_verify_output { file_to_search pattern {instance_no 0}} { + + # compute the number of PATTERN in FILE_TO_SEARCH by grep and wc. + catch "exec sh -c {grep \"$pattern\" $file_to_search | wc -l ;exit}" output + verbose "output = $output" + + if [ regexp "syntax error" $output ] then { + fail "Invalid regular expression $pattern" + } elseif { $instance_no == 0 } then { + if { $output == 0 } then { + fail "Fail to find $pattern in $file_to_search" + } else { + pass "$pattern in $file_to_search" + } + } elseif { $output >= $instance_no } then { + pass "$pattern in $file_to_search for $output times" + } else { + fail "$pattern in $file_to_search for $output times ,should be $instance_no" + } +} diff --git a/testsuite/ltrace.main/Makefile b/testsuite/ltrace.main/Makefile new file mode 100644 index 0000000..449214a --- /dev/null +++ b/testsuite/ltrace.main/Makefile @@ -0,0 +1,33 @@ +# Copyright (C) 1992 - 2001 Free Software Foundation, Inc. +# +# 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 +# the Free Software Foundation; either version 1, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# 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. +# + +CLEANFILES = *.log *.sum site.bak setval.tmp site.exp + +.SUFFIXES: +clean: + -rm -f main main-internal system_calls signals parameters + -rm -f *.o *.so + -rm -f *.ltrace + -rm -f $(CLEANFILES) +distclean: clean + + +.PHONY: $(RECURSIVE_TARGETS) check clean distclean realclean + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/testsuite/ltrace.main/main-internal-1.c b/testsuite/ltrace.main/main-internal-1.c new file mode 100644 index 0000000..2a5cd0c --- /dev/null +++ b/testsuite/ltrace.main/main-internal-1.c @@ -0,0 +1,8 @@ +#include + +void +display ( char* s ) +{ + printf("%s\n",s); +} + diff --git a/testsuite/ltrace.main/main-internal.c b/testsuite/ltrace.main/main-internal.c new file mode 100644 index 0000000..7508d06 --- /dev/null +++ b/testsuite/ltrace.main/main-internal.c @@ -0,0 +1,19 @@ + /* Ltrace Test : main-internal.c. + Objectives : Verify that ltrace can trace call from main + executable within it. + This file was written by Yao Qi . */ +#include + +extern void display ( char* ); + +#define DISPLAY_LOOP 12 + +int +main () +{ + int i; + printf ("should not show up if '-X display' is used.\n"); + for (i=0; i< DISPLAY_LOOP; i++) + display ("Function call within executable."); +} + diff --git a/testsuite/ltrace.main/main-internal.exp b/testsuite/ltrace.main/main-internal.exp new file mode 100644 index 0000000..f3f0015 --- /dev/null +++ b/testsuite/ltrace.main/main-internal.exp @@ -0,0 +1,33 @@ +# This file was written by Yao Qi . + +set testfile "main-internal" +set srcfile ${testfile}.c +set binfile ${testfile} + +verbose "compiling source file now....." +# Build the shared libraries this test case needs. +if { [ ltrace_compile "${srcdir}/${subdir}/${testfile}.c ${srcdir}/${subdir}/${testfile}-1.c" "${srcdir}/${subdir}/${binfile}" executable {debug} ] != "" } { + send_user "Testcase compile failed, so all tests in this file will automatically fail.\n" +} + +# set options for ltrace. +ltrace_options "-x" "display" + +# Run PUT for ltarce. +set exec_output [ltrace_runtest $srcdir/$subdir $srcdir/$subdir/$binfile] + +# Check the output of this program. +verbose "ltrace runtest output: $exec_output\n" +if [regexp {ELF from incompatible architecture} $exec_output] { + fail "32-bit ltrace can not perform on 64-bit PUTs and rebuild ltrace in 64 bit mode!" + return +} elseif [ regexp {Couldn't do static plt2addr} $exec_output ] { + fail "Couldn't do static plt2addr!" + return +} elseif [regexp {Couldn't get .hash data from} $exec_output ] { + fail "Couldn't get .hash data!" + return +} + +set pattern "display" +ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern 12 diff --git a/testsuite/ltrace.main/main-lib.c b/testsuite/ltrace.main/main-lib.c new file mode 100644 index 0000000..5fd53b3 --- /dev/null +++ b/testsuite/ltrace.main/main-lib.c @@ -0,0 +1,7 @@ +#include + +void +print(char* s) +{ + printf("%s\n",s); +} diff --git a/testsuite/ltrace.main/main.c b/testsuite/ltrace.main/main.c new file mode 100644 index 0000000..0f270bf --- /dev/null +++ b/testsuite/ltrace.main/main.c @@ -0,0 +1,21 @@ +/* Ltrace Test : main.c. + Objectives : Verify that ltrace can trace call a library function + from main executable. + + This file was written by Yao Qi . */ + +extern void print ( char* ); + +#define PRINT_LOOP 10 + +int +main () +{ + int i; + + for (i=0; i. + +set testfile "main" +set srcfile ${testfile}.c +set binfile ${testfile} +set libfile "main-lib" +set libsrc $srcdir/$subdir/$libfile.c +set lib_sl $srcdir/$subdir/lib$testfile.so + + +if [get_compiler_info $binfile] { + return -1 +} + +verbose "compiling source file now....." +if { [ltrace_compile_shlib $libsrc $lib_sl debug ] != "" + || [ltrace_compile $srcdir/$subdir/$srcfile $srcdir/$subdir/$binfile executable [list debug shlib=$lib_sl] ] != ""} { + send_user "Testcase compile failed, so all tests in this file will automatically fail.\n" +} + +# set options for ltrace. +ltrace_options "-l" "$srcdir/$subdir/libmain.so" + +# Run PUT for ltarce. +set exec_output [ltrace_runtest $srcdir/$subdir $srcdir/$subdir/$binfile] + +# Check the output of this program. +verbose "ltrace runtest output: $exec_output\n" +if [regexp {ELF from incompatible architecture} $exec_output] { + fail "32-bit ltrace can not perform on 64-bit PUTs and rebuild ltrace in 64 bit mode!" + return +} elseif [ regexp {Couldn't get .hash data} $exec_output ] { + fail "Couldn't get .hash data!" + return +} + +# Verify the output by checking numbers of print in main.ltrace. +set pattern "print" +ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern 10 diff --git a/testsuite/ltrace.main/parameters-lib.c b/testsuite/ltrace.main/parameters-lib.c new file mode 100644 index 0000000..26e4c3b --- /dev/null +++ b/testsuite/ltrace.main/parameters-lib.c @@ -0,0 +1,117 @@ +#include +#include + +void func_ignore(int a, int b, int c) +{ + printf("%d\n", a + b + c); +} + +void func_intptr(int *i) +{ + printf("%d\n", *i); +} + +void func_intptr_ret(int *i) +{ + *i = 42; +} + +int func_strlen(char* p) +{ + strcpy(p, "Hello world"); + return strlen(p); +} + +void func_strfixed(char* p) +{ + strcpy(p, "Hello world"); +} + +void func_ppp(int*** ppp) +{ + printf("%d\n", ***ppp); +} + +void func_stringp(char** sP) +{ + printf("%s\n", *sP); +} + +void func_enum(int x) +{ + printf("enum: %d\n", x); +} + +void func_short(short x1, short x2) +{ + printf("short: %hd %hd\n", x1, x2); +} + +void func_ushort(unsigned short x1, unsigned short x2) +{ + printf("ushort: %hu %hu\n", x1, x2); +} + +void func_float(float f1, float f2) +{ + printf("%f %f\n", f1, f2); +} + +void func_typedef(int x) +{ + printf("typedef'd enum: %d\n", x); +} + +void func_arrayi(int* a, int N) +{ + int i; + printf("array[int]: "); + for (i = 0; i < N; i++) + printf("%d ", a[i]); + printf("\n"); +} + +void func_arrayf(float* a, int N) +{ + int i; + printf("array[float]: "); + for (i = 0; i < N; i++) + printf("%f ", a[i]); + printf("\n"); +} + +struct test_struct { + int simple; + int alen; + int slen; + struct { int a; int b; }* array; + struct { int a; int b; } seq[3]; + char* str; + char* outer_str; +}; + +void func_struct(struct test_struct* x) +{ + char buf[100]; + int i; + + printf("struct: "); + + printf("%d, [", x->simple); + for (i = 0; i < x->alen; i++) { + printf("%d/%d", x->array[i].a, x->array[i].b); + if (i < x->alen - 1) + printf(" "); + } + printf("] ["); + for (i = 0; i < 3; i++) { + printf("%d/%d", x->seq[i].a, x->seq[i].b); + if (i < 2) + printf(" "); + } + printf("] "); + + strncpy(buf, x->str, x->slen); + buf[x->slen] = '\0'; + printf("%s\n", buf); +} diff --git a/testsuite/ltrace.main/parameters.c b/testsuite/ltrace.main/parameters.c new file mode 100644 index 0000000..dd63612 --- /dev/null +++ b/testsuite/ltrace.main/parameters.c @@ -0,0 +1,120 @@ +/* Ltrace Test : parameters.c. + Objectives : Verify that Ltrace can handle all the different + parameter types + + This file was written by Steve Fink . */ + +#include +#include +#include +#include +#include +#include +#include + +void func_intptr(int *i); +void func_intptr_ret(int *i); +int func_strlen(char*); +void func_strfixed(char*); +void func_ppp(int***); +void func_stringp(char**); +void func_short(short, short); +void func_ushort(unsigned short, unsigned short); +void func_float(float, float); +void func_arrayi(int*, int); +void func_arrayf(float*, int); +void func_struct(void*); + +typedef enum { + RED, + GREEN, + BLUE, + CHARTREUSE, + PETUNIA +} color_t; +void func_enum(color_t); +void func_typedef(color_t); + +int +main () +{ + int x = 17; + int *xP, **xPP; + char buf[200]; + char *s; + int *ai; + float *af; + + func_intptr(&x); + + func_intptr_ret(&x); + + func_strlen(buf); + printf("%s\n", buf); + + func_strfixed(buf); + printf("%s\n", buf); + + x = 80; + xP = &x; + xPP = &xP; + func_ppp(&xPP); + + s = (char*) malloc(100); + strcpy(s, "Dude"); + func_stringp(&s); + + func_enum(BLUE); + + func_short(-8, -9); + func_ushort(33, 34); + func_float(3.4, -3.4); + + func_typedef(BLUE); + + ai = (int*) calloc(sizeof(int), 8); + for (x = 0; x < 8; x++) + ai[x] = 10 + x; + func_arrayi(ai, 8); + func_arrayi(ai, 2); + + af = (float*) calloc(sizeof(float), 8); + for (x = 0; x < 8; x++) + af[x] = 10.1 + x; + func_arrayf(af, 8); + func_arrayf(af, 2); + + { + struct { + int simple; + int alen; + int slen; + struct { int a; int b; }* array; + struct { int a; int b; } seq[3]; + char* str; + } x; + + x.simple = 89; + + x.alen = 2; + x.array = malloc(800); + x.array[0].a = 1; + x.array[0].b = 10; + x.array[1].a = 3; + x.array[1].b = 30; + + x.seq[0].a = 4; + x.seq[0].b = 40; + x.seq[1].a = 5; + x.seq[1].b = 50; + x.seq[2].a = 6; + x.seq[2].b = 60; + + x.slen = 3; + x.str = "123junk"; + + func_struct(&x); + } + + return 0; +} diff --git a/testsuite/ltrace.main/parameters.conf b/testsuite/ltrace.main/parameters.conf new file mode 100644 index 0000000..33c1a1e --- /dev/null +++ b/testsuite/ltrace.main/parameters.conf @@ -0,0 +1,15 @@ +void func_intptr(int*) +void func_intptr_ret(+int*) +int func_strlen(+string[retval]) +void func_strfixed(string[4]) +void func_ppp(int***) +void func_stringp(string*) +void func_enum(enum (RED=0,GREEN=1,BLUE=2,CHARTREUSE=3,PETUNIA=4)) +void func_short(short,short) +void func_ushort(ushort, ushort) +void func_float(float,float) +typedef color = enum (RED=0,GREEN=1,BLUE=2,CHARTREUSE=3,PETUNIA=4) +void func_typedef(color) +void func_arrayi(array(int,arg2)*,void) +void func_arrayf(array(float,arg2)*,void) +void func_struct(struct(int,int,int,array(struct(int,int),elt2)*,array(struct(int,int),3),string[elt3])*) diff --git a/testsuite/ltrace.main/parameters.exp b/testsuite/ltrace.main/parameters.exp new file mode 100644 index 0000000..bb55e03 --- /dev/null +++ b/testsuite/ltrace.main/parameters.exp @@ -0,0 +1,72 @@ +# This file was written by Steve Fink . +# Based on main.c by Yao Qi . + +set testfile "parameters" +set srcfile ${testfile}.c +set binfile ${testfile} +set libfile "parameters-lib" +set libsrc $srcdir/$subdir/$libfile.c +set lib_sl $srcdir/$subdir/lib$testfile.so + + +if [get_compiler_info $binfile] { + return -1 +} + +verbose "compiling source file now....." +if { [ltrace_compile_shlib $libsrc $lib_sl debug ] != "" + || [ltrace_compile $srcdir/$subdir/$srcfile $srcdir/$subdir/$binfile executable [list debug shlib=$lib_sl] ] != ""} { + send_user "Testcase compile failed, so all tests in this file will automatically fail.\n" +} + +# set options for ltrace. +ltrace_options "-l" "$srcdir/$subdir/libparameters.so" "-F" "$srcdir/$subdir/parameters.conf" + +# Run PUT for ltarce. +set exec_output [ltrace_runtest $srcdir/$subdir $srcdir/$subdir/$binfile] + +# Check the output of this program. +verbose "ltrace runtest output: $exec_output\n" +if [regexp {ELF from incompatible architecture} $exec_output] { + fail "32-bit ltrace can not perform on 64-bit PUTs and rebuild ltrace in 64 bit mode!" + return +} elseif [ regexp {Couldn't get .hash data} $exec_output ] { + fail "Couldn't get .hash data!" + return +} + +# Verify the output +set pattern "func_intptr(17)" +ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern 1 +set pattern "func_intptr_ret(42)" +ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern 1 +set pattern "func_strlen(\\\"Hello world\\\") *= *11" +ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern 1 +set pattern "func_strfixed(\\\"Hell\\\")" +ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern 1 +set pattern "func_ppp(80)" +ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern 1 +set pattern "func_stringp(\\\"Dude\\\")" +ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern 1 +set pattern "func_enum(BLUE)" +ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern 1 +set pattern "func_short(-8, -9)" +ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern 1 +set pattern "func_ushort(33, 34)" +ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern 1 +set pattern "func_float(3.40*, -3.40*)" +ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern 1 +set pattern "func_typedef(BLUE)" +ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern 1 +set pattern "func_arrayi(. 10, 11, 12, 13\\.\\.\\. ., )" +ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern 1 +set pattern "func_arrayi(. 10, 11 ., )" +ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern 1 +set pattern "func_arrayf(. 10.10*, 11.10*, 12.10*, 13.10*\\.\\.\\. ., )" +ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern 1 +set pattern "func_arrayf(. 10.10*, 11.10* ., )" +ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern 1 +set pattern "exited (status 0)" +ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern 1 +set pattern "func_struct({ 89, 2, 3, . { 1, 10 }, { 3, 30 } ., . { 4, 40 }, { 5, 50 }, { 6, 60 } ., \\\"123\\\" })" +ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern 1 diff --git a/testsuite/ltrace.main/signals.c b/testsuite/ltrace.main/signals.c new file mode 100644 index 0000000..a02e795 --- /dev/null +++ b/testsuite/ltrace.main/signals.c @@ -0,0 +1,48 @@ +/* Ltrace Test : signals.c. + Objectives : Verify that ltrace can trace user defined signal. + This file was written by Yao Qi . */ + +#include +#include +#include + +#define LOOP 7 + +void +handler(int signum,siginfo_t *info,void *act) +{ + /* Trace printf in signal handler. */ + printf("sival_int = %d\n",info->si_value.sival_int); +} + +int +main () +{ + struct sigaction act; + union sigval mysigval; + int i; + int sig; + pid_t pid; + + mysigval.sival_int=0; + + /* Use an user-defined signal 1. */ + sig = SIGUSR1; + pid=getpid(); + + sigemptyset(&act.sa_mask); + act.sa_sigaction=handler; + act.sa_flags=SA_SIGINFO; + + if(sigaction(sig,&act,NULL) < 0) + { + printf("install sigal error\n"); + } + + for(i=0; i. + +set testfile "signals" +set srcfile ${testfile}.c +set binfile ${testfile} + + +verbose "compiling source file now....." +# Build the shared libraries this test case needs. +if { [ ltrace_compile "${srcdir}/${subdir}/${testfile}.c" "${srcdir}/${subdir}/${binfile}" executable {debug} ] != "" } { + send_user "Testcase compile failed, so all tests in this file will automatically fail\n." +} + +# set options for ltrace. +ltrace_options "-L" + +# Run PUT for ltarce. +set exec_output [ltrace_runtest $srcdir/$subdir $srcdir/$subdir/$binfile] + +# Check the output of this program. +verbose "ltrace runtest output: $exec_output\n" +if [regexp {ELF from incompatible architecture} $exec_output] { + fail "32-bit ltrace can not perform on 64-bit PUTs and rebuild ltrace in 64 bit mode!" + return +} elseif [ regexp {Couldn't get .hash data} $exec_output ] { + fail "Couldn't get .hash data!" + return +} + +# Extract LOOP from source file. +set fd [ open $srcdir/$subdir/$srcfile r] +while { [gets $fd line] >= 0 } { + regexp {define LOOP.*([0-9]+)} $line match count +} +close $fd + +# Verify the output of ltrace by checking the number of SIGUSR1 in signal.ltrace +set pattern "SIGUSR1" +ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern $count diff --git a/testsuite/ltrace.main/system_calls.c b/testsuite/ltrace.main/system_calls.c new file mode 100644 index 0000000..7be3d04 --- /dev/null +++ b/testsuite/ltrace.main/system_calls.c @@ -0,0 +1,68 @@ +/* Ltrace Test : system_calls.c. + Objectives : Verify that Ltrace can trace all the system calls in + execution. + + You can add new system calls in it and add its verification in + system_calls correspondingly. + + This file was written by Yao Qi . */ + +#include +#include +#include +#include +#include + +void exit (int); + +#define BUF_SIZE 100 + +int +main () +{ + FILE* fp; + char s[]="system_calls"; + char buffer[BUF_SIZE]; + struct stat state; + + /* SYS_open. */ + fp = fopen ("system_calls.tmp", "w"); + if (fp == NULL) + { + printf("Can not create system_calls.tmp\n"); + exit (0); + } + /* SYS_write. */ + fwrite(s, sizeof(s), 1, fp); + /* SYS_lseek. */ + fseek (fp, 0, SEEK_CUR); + /* SYS_read. */ + fread(buffer, sizeof(s), 1, fp); + /* SYS_close. */ + fclose(fp); + + /* SYS_getcwd. */ + getcwd (buffer, BUF_SIZE); + /* SYS_chdir. */ + chdir ("."); + /* SYS_symlink. */ + symlink ("system_calls.tmp", "system_calls.link"); + /* SYS_unlink. */ + remove("system_calls.link"); + /* SYS_rename. */ + rename ("system_calls.tmp", "system_calls.tmp1"); + /* SYS_stat. */ + stat ("system_calls.tmp", &state); + /* SYS_access. */ + access ("system_calls.tmp", R_OK); + remove("system_calls.tmp1"); + + /* SYS_mkdir. */ + mkdir ("system_call_mkdir", 0777); + /* SYS_rmdir. */ + rmdir ("system_call_mkdir"); + + return 0; +} + + diff --git a/testsuite/ltrace.main/system_calls.exp b/testsuite/ltrace.main/system_calls.exp new file mode 100644 index 0000000..b274db5 --- /dev/null +++ b/testsuite/ltrace.main/system_calls.exp @@ -0,0 +1,67 @@ +# This file was written by Yao Qi . + +set testfile "system_calls" +set srcfile ${testfile}.c +set binfile ${testfile} + + +verbose "compiling source file now....." +# Build the shared libraries this test case needs. +if { [ ltrace_compile "${srcdir}/${subdir}/${testfile}.c" "${srcdir}/${subdir}/${binfile}" executable {debug} ] != "" } { + send_user "Testcase compile failed, so all tests in this file will automatically fail.\n" +} + +# set options for ltrace. +ltrace_options "-S" + +#Run PUT for ltarce. +set exec_output [ltrace_runtest $srcdir/$subdir $srcdir/$subdir/$binfile] + +#check the output of this program. +verbose "ltrace runtest output: $exec_output\n" + +if [regexp {ELF from incompatible architecture} $exec_output] { + fail "32-bit ltrace can not perform on 64-bit PUTs and rebuild ltrace in 64 bit mode!" + return +} elseif [ regexp {Couldn't get .hash data} $exec_output ] { + fail "Couldn't get .hash data!" + return +} + + +set pattern "SYS_munmap" +ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern 2 +set pattern "SYS_write" +ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern 1 +set pattern "SYS_unlink" +ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern 1 + +set pattern "SYS_brk" +ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern 1 +set pattern "SYS_open" +ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern 1 +set pattern "SYS_fstat" +ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern 1 +set pattern "SYS_mmap" +ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern 1 +set pattern "SYS_close" +ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern 1 + +set pattern "SYS_getcwd" +ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern 1 +set pattern "SYS_chdir" +ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern 1 +set pattern "SYS_symlink" +ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern 1 +set pattern "SYS_unlink" +ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern 1 +set pattern "SYS_stat" +ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern 1 +set pattern "SYS_access" +ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern 1 +set pattern "SYS_rename" +ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern 1 +set pattern "SYS_mkdir" +ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern 1 +set pattern "SYS_rmdir" +ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern 1 diff --git a/testsuite/ltrace.minor/Makefile b/testsuite/ltrace.minor/Makefile new file mode 100644 index 0000000..cd4914f --- /dev/null +++ b/testsuite/ltrace.minor/Makefile @@ -0,0 +1,36 @@ +# Copyright (C) 1992 - 2001 Free Software Foundation, Inc. +# +# 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 +# the Free Software Foundation; either version 1, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# 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. +# + +CLEANFILES = *.log *.sum site.bak setval.tmp site.exp + +.SUFFIXES: +clean: + -rm -f demangle trace-fork trace-clone trace-exec trace-exec1 + -rm -f time-record-tt time-record-ttt time-record-T + -rm -f attach-process count-record + -rm -f print-instruction-pointer + -rm -f *.o *.so + -rm -f *.ltrace + -rm -f $(CLEANFILES) +distclean: clean + + +.PHONY: $(RECURSIVE_TARGETS) check clean distclean realclean + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/testsuite/ltrace.minor/attach-process.c b/testsuite/ltrace.minor/attach-process.c new file mode 100644 index 0000000..4c00bce --- /dev/null +++ b/testsuite/ltrace.minor/attach-process.c @@ -0,0 +1,16 @@ +/* Ltrace Test : attach-process.c. + Objectives : Verify that ltrace can attach to a running process + by its PID. + + This file was written by Yao Qi . */ + +#include +#include + +int +main () +{ + sleep (5); + sleep (1); + return 0; +} diff --git a/testsuite/ltrace.minor/attach-process.exp b/testsuite/ltrace.minor/attach-process.exp new file mode 100644 index 0000000..ab5460e --- /dev/null +++ b/testsuite/ltrace.minor/attach-process.exp @@ -0,0 +1,38 @@ +# This file was written by Yao Qi . + +set testfile "attach-process" +set srcfile ${testfile}.c +set binfile ${testfile} + +verbose "compiling source file now....." +# Build the shared libraries this test case needs. +if { [ ltrace_compile "${srcdir}/${subdir}/${testfile}.c" "${srcdir}/${subdir}/${binfile}" executable {debug} ] != "" } { + send_user "Testcase compile failed, so all tests in this file will automatically fail.\n" +} + +# Run the program and get PID of it. +catch "exec $srcdir/$subdir/$binfile &" output + +# get PID from ps output. +regexp {([0-9]+)} $output match PID +verbose "PID = $PID" + +# Run PUT for ltrace. +global LTRACE +catch "exec $LTRACE -S -p $PID -o ${srcdir}/${subdir}/${testfile}.ltrace" exec_output + +# Check the output of this program. +verbose "ltrace runtest output: $exec_output\n" +if [regexp {ELF from incompatible architecture} $exec_output] { + fail "32-bit ltrace can not perform on 64-bit PUTs and rebuild ltrace in 64 bit mode!" + return +} elseif [ regexp {Couldn't get .hash data} $exec_output ] { + fail "Couldn't get .hash data!" + return +} + +# Verify the output in attach-process.ltrace by checking the number +# of sleep. +set pattern "sleep" +ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern 1 + diff --git a/testsuite/ltrace.minor/count-record.c b/testsuite/ltrace.minor/count-record.c new file mode 100644 index 0000000..3b609ad --- /dev/null +++ b/testsuite/ltrace.minor/count-record.c @@ -0,0 +1,51 @@ +/* Ltrace Test : count-record.c. + Objectives : Verify that Ltrace can count all the system calls in + execution and report a summary on exit. + + This file was written by Yao Qi . */ + +#include +#include +#include +#include +#include + +void exit (int); + +#define BUF_SIZE 100 + +/* Do as many operations as possible to record these calls. */ +int +main () +{ + FILE* fp; + char s[]="system_calls"; + char buffer[BUF_SIZE]; + struct stat state; + + fp = fopen ("system_calls.tmp", "w"); + if (fp == NULL) + { + printf("Can not create system_calls.tmp\n"); + exit (0); + } + + fwrite(s, sizeof(s), 1, fp); + fseek (fp, 0, SEEK_CUR); + fread(buffer, sizeof(s), 1, fp); + fclose(fp); + + getcwd (buffer, BUF_SIZE); + chdir ("."); + symlink ("system_calls.tmp", "system_calls.link"); + remove("system_calls.link"); + rename ("system_calls.tmp", "system_calls.tmp1"); + stat ("system_calls.tmp", &state); + access ("system_calls.tmp", R_OK); + remove("system_calls.tmp1"); + + mkdir ("system_call_mkdir", 0777); + rmdir ("system_call_mkdir"); + + return 0; +} diff --git a/testsuite/ltrace.minor/count-record.exp b/testsuite/ltrace.minor/count-record.exp new file mode 100644 index 0000000..f8c4923 --- /dev/null +++ b/testsuite/ltrace.minor/count-record.exp @@ -0,0 +1,77 @@ +# This file was written by Yao Qi . + +set testfile "count-record" +set srcfile ${testfile}.c +set binfile ${testfile} + +verbose "compiling source file now....." +# Build the shared libraries this test case needs. +if { [ ltrace_compile "${srcdir}/${subdir}/${testfile}.c" "${srcdir}/${subdir}/${binfile}" executable {debug} ] != "" } { + send_user "Testcase compile failed, so all tests in this file will automatically fail.\n" +} + +# set options for ltrace. +ltrace_options "-c" + +# Run PUT for ltrace. +set exec_output [ltrace_runtest $srcdir/$subdir $srcdir/$subdir/$binfile] + +# Check the output of this program. +verbose "ltrace runtest output: $exec_output\n" +if [regexp {ELF from incompatible architecture} $exec_output] { + fail "32-bit ltrace can not perform on 64-bit PUTs and rebuild ltrace in 64 bit mode!" + return +} elseif [ regexp {Couldn't get .hash data} $exec_output ] { + fail "Couldn't get .hash data!" + return +} + + +ltrace_saveoutput $exec_output $srcdir/$subdir/$binfile.ltrace + +# +# This is a sample output and Verify the forth and fifth column. +# +# 13.31 0.001051 1051 1 rmdir +# 12.81 0.001012 1012 1 fopen +# 10.32 0.000815 407 2 remove +# 9.56 0.000755 755 1 mkdir +# 7.86 0.000621 621 1 fseek +# 6.86 0.000542 542 1 fwrite +# 6.60 0.000521 521 1 fclose +# 6.03 0.000476 476 1 rename +# 5.61 0.000443 443 1 symlink +# 5.05 0.000399 399 1 chdir +# 4.80 0.000379 379 1 access +# 4.00 0.000316 316 1 __xstat +# 3.81 0.000301 301 1 getcwd +# 3.39 0.000268 268 1 fread +# + +set pattern " 1 rmdir" +ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern +set pattern " 1 fopen" +ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern +set pattern " 2 remove" +ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern +set pattern " 1 mkdir" +ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern +set pattern " 1 fseek" +ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern +set pattern " 1 fwrite" +ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern +set pattern " 1 fclose" +ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern +set pattern " 1 rename" +ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern +set pattern " 1 symlink" +ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern +set pattern " 1 chdir" +ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern +set pattern " 1 access" +ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern +set pattern " 1 getcwd" +ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern +set pattern " 1 fread" +ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern + diff --git a/testsuite/ltrace.minor/demangle-lib.cpp b/testsuite/ltrace.minor/demangle-lib.cpp new file mode 100644 index 0000000..01ab18d --- /dev/null +++ b/testsuite/ltrace.minor/demangle-lib.cpp @@ -0,0 +1,97 @@ +#include +#include + +#include"demangle.h" + +/* Number of arguments */ +int Fi_i(int bar) { return 0; } +int Fi_s(short bar) {return 0; } +int Fii_i(int bar, int goo) { return 0; } +int Fiii_i(int bar, int goo, int hoo) { return 0; } +int Fie_i(int bar, ...) { return 0; } + +/* Return types */ +void Fv_v(void) { ; } +char Fv_c(void) { return 0; } +signed char Fv_Sc(void) { return 0; } +unsigned char Fv_Uc(void) { return 0; } +short Fv_s(void) { return 0; } +unsigned short Fv_Us(void) { return 0; } +int Fv_i(void) { return 0; } +const int Fv_Ci(void) { return 0; } +unsigned int Fv_Ui(void) { return 0; } +volatile int Fv_Vi(void) { return 0; } +long Fv_l(void) { return 0; } +unsigned long Fv_Ul(void) { return 0; } +float Fv_f(void) { return 0; } +double Fv_g(void) { return 0; } +long double Fv_Lg(void) { return 0; } + +/* Pointers */ +void *Fv_Pv(void) { return 0; } +void **Fv_PPv(void) { return 0; } + +/* References */ +int& Fv_Ri(void) { static int x; return x; } + +/* Argument types */ +int FPi_i(int *a) { return 0; } +int FA10_i_i(int a[10]) { return 0; } +int Fc_i(char bar) { return 0; } +int Ff_i(float bar) { return 0; } +int Fg_i(double bar) { return 0; } + +/* Function pointers */ +typedef int (*x)(int); +typedef int (*y)(short); + +int Fx_i(x fnptr) { return 0; } +int Fxx_i(x fnptr, x fnptr2) { return 0; } +int Fxxx_i(x fnptr, x fnptr2, + x fnptr3) { return 0; } +int Fxxi_i(x fnptr, x fnptr2, + x fnptr3, int i) { return 0; } +int Fxix_i(x fnptr, int i, + x fnptr3) { return 0; } +int Fxyxy_i(x fnptr, y fnptr2, + x fnptr3, y fnptr4) { return 0; } + +/* Class methods */ +class myclass; +myclass::myclass(void) { myint = 0; } +myclass::myclass(int x) { myint = x; } +myclass::~myclass() { ; } + +int myclass::Fi_i(int bar) { return myint; } +int myclass::Fis_i(int bar) { return bar; } + +void* myclass::operator new(size_t size) +{ + void* p = malloc(size);return p; +} +void myclass::operator delete(void *p) {free(p);} + +myclass myclass::operator++() { return myclass(++myint); } +myclass myclass::operator++(int) { return myclass(myint++); } + +/* Binary */ +myclass myclass::operator+(int x) { return myclass(myint + x); } + +/* Assignment */ +myclass& myclass::operator=(const myclass& from) +{ + myint = from.myint; + return *this; +} + +/* test clashes */ +class nested; + +nested::nested(void) { ; } +nested::~nested() { ; } +int nested::Fi_i(int bar) { return bar; } + +void Fmyclass_v(myclass m) { ; } +void Fmxmx_v(myclass arg1, x arg2, + myclass arg3, x arg4) { ; } + diff --git a/testsuite/ltrace.minor/demangle.cpp b/testsuite/ltrace.minor/demangle.cpp new file mode 100644 index 0000000..14cc9f6 --- /dev/null +++ b/testsuite/ltrace.minor/demangle.cpp @@ -0,0 +1,121 @@ +/* Ltrace Test : demangle.cpp + Objectives : Verify that ltrace can demangle C++ symbols. + + This file was written by Yao Qi . */ + +#include +#include"demangle.h" + +/* Number of arguments */ +extern int Fi_i(int); +extern int Fi_s (short); +extern int Fii_i(int , int); +extern int Fiii_i(int, int, int); +extern int Fie_i(int bar, ...); + +/* Return types */ +extern void Fv_v(void); +extern char Fv_c(void); +extern signed char Fv_Sc(void); +extern unsigned char Fv_Uc(void); +extern short Fv_s(void); +extern unsigned short Fv_Us(void); +extern int Fv_i(void); +extern const int Fv_Ci(void); +extern unsigned int Fv_Ui(void); +extern volatile int Fv_Vi(void); +extern long Fv_l(void); +extern unsigned long Fv_Ul(void); +extern float Fv_f(void) ; +extern double Fv_g(void); +extern long double Fv_Lg(void); + + +/* Pointers */ +extern void * Fv_Pv(void); +extern void ** Fv_PPv(void); + +/* References */ +extern int& Fv_Ri(void); + +/* Argument types */ +extern int FPi_i(int *a); +extern int FA10_i_i(int a[10]) ; +extern int Fc_i(char bar); +extern int Ff_i(float bar); +extern int Fg_i(double bar); + +/* Function pointers */ +typedef int (*x)(int); +typedef int (*y)(short); + +extern int Fx_i(x); +extern int Fxx_i(x fnptr, x fnptr2); +extern int Fxxx_i(x fnptr, x fnptr2, x fnptr3); +extern int Fxxi_i(x fnptr, x fnptr2, x fnptr3, int i); +extern int Fxix_i(x fnptr, int i, x fnptr3); +extern int Fxyxy_i(x fnptr, y fnptr2, x fnptr3, y fnptr4); + + +extern void Fmyclass_v(myclass m); +extern void Fmxmx_v(myclass arg1, x arg2, myclass arg3, x arg4); + +int main () +{ + int i; + + i = Fi_i (0); + i = Fii_i (0,0); + i = Fiii_i (0,0,0); + i = Fie_i (0); + + Fv_v (); + Fv_c (); + Fv_Sc (); + Fv_Uc (); + Fv_s (); + Fv_Us (); + Fv_i (); + Fv_Ci (); + Fv_Ui (); + Fv_Vi (); + Fv_l (); + Fv_Ul (); + Fv_f (); + Fv_g (); + Fv_Lg (); + + Fv_Pv (); + Fv_PPv (); + + Fv_Ri (); + + FPi_i (&i); + FA10_i_i (&i); + Fc_i ('a'); + Ff_i (1.1f); + Fg_i (1.1); + + Fx_i (Fi_i); + Fxx_i (Fi_i, Fi_i); + Fxxx_i (Fi_i, Fi_i, Fi_i); + Fxxi_i (Fi_i, Fi_i, Fi_i, 0); + Fxyxy_i (Fi_i, Fi_s, Fi_i, Fi_s); + + myclass a,c; + myclass* b; + + a.Fi_i (0); + a.Fis_i (0); + a++; + c = a + 2; + + nested n; + n.Fi_i (0); + + b = (myclass*) new myclass(0); + delete (b); + Fmyclass_v (a); + + return 0; +} diff --git a/testsuite/ltrace.minor/demangle.exp b/testsuite/ltrace.minor/demangle.exp new file mode 100644 index 0000000..5077ac0 --- /dev/null +++ b/testsuite/ltrace.minor/demangle.exp @@ -0,0 +1,63 @@ +# This file was written by Yao Qi . + +set testfile "demangle" +set srcfile ${testfile}.cpp +set binfile ${testfile} +set libfile "demangle-lib" +set libsrc $srcdir/$subdir/$libfile.cpp +set lib_sl $srcdir/$subdir/lib$testfile.so + +verbose "compiling source file now....." +if [get_compiler_info $binfile "c++"] { + return -1 +} + +verbose "compiling source file now....." +if { [ltrace_compile_shlib $libsrc $lib_sl [list debug c++]] != "" + || [ltrace_compile $srcdir/$subdir/$srcfile $srcdir/$subdir/$binfile executable [list debug shlib=$lib_sl c++] ] != ""} { + send_user "Testcase compile failed, so all tests in this file will automatically fail.\n" +} + +# set options for ltrace. +ltrace_options "-C" + +# Run PUT for ltrace. +set exec_output [ltrace_runtest $srcdir/$subdir $srcdir/$subdir/$binfile] + +# Check the output of this program. +verbose "ltrace runtest output: $exec_output\n" +if [regexp {ELF from incompatible architecture} $exec_output] { + fail "32-bit ltrace can not perform on 64-bit PUTs and rebuild ltrace in 64 bit mode!" + return +} elseif [ regexp {Couldn't get .hash data} $exec_output ] { + fail "Couldn't get .hash data!" + return +} + +# read function declarations from demangle.cpp and verify them in demangle.ltrace. +set fd [ open $srcdir/$subdir/$srcfile r] +while { [gets $fd line] >= 0 } { + if [regexp {extern (double|float|void|char|int|short|long|void \*|void \*\*) ([^ ])\(} $line match type fun] { + ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $fun + } +} +close $fd + +#read member fucntions of classs from demangle-lib.cpp and verify them in demagle.ltrace. +set fd [ open $srcdir/$subdir/$testfile-lib.cpp r] +while { [gets $fd line] >= 0 } { + if [ regexp {((myclass|nested)::[^\(]*)\(} $line match fun] { + # For Debug purpose. + verbose "fun = $fun" + # Extract new/delete for remove extra SPACE in $fun, for example, + # $fun = "myclass::operator delete" will confuse ltrace_verify_output if it + # was an argument to it. + if [regexp {(new|delete)} $fun match sub_fun] { + ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $sub_fun + } else { + # Verify class member functions without SPACE. + ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $fun + } + } +} +close $fd diff --git a/testsuite/ltrace.minor/demangle.h b/testsuite/ltrace.minor/demangle.h new file mode 100644 index 0000000..02aa156 --- /dev/null +++ b/testsuite/ltrace.minor/demangle.h @@ -0,0 +1,36 @@ + +class myclass { + int myint; + public: + myclass(int x); + myclass(void); + ~myclass(); + static int Fis_i(int bar); + int Fi_i(int bar); + /* Overloaded operators */ + void* operator new(size_t); + void operator delete(void *); + /* Unary operation. */ + myclass operator++();// Preincrement + myclass operator++(int);// Postincrement + + /* Binary operation. */ + myclass operator+(int); + + /* Assignment */ + myclass& operator=(const myclass& from); + /* Nested classes */ + class nested { + public: + nested(); + ~nested(); + int Fi_i(int bar); + }; +}; + +class nested { + public: + nested(); + ~nested(); + int Fi_i(int bar); +}; diff --git a/testsuite/ltrace.minor/print-instruction-pointer.c b/testsuite/ltrace.minor/print-instruction-pointer.c new file mode 100644 index 0000000..37b8441 --- /dev/null +++ b/testsuite/ltrace.minor/print-instruction-pointer.c @@ -0,0 +1,11 @@ +#include + +int main () +{ + int i=0; + printf("%d\n",i); + i=1; + printf("%d\n",i); + + return 0; +} diff --git a/testsuite/ltrace.minor/print-instruction-pointer.exp b/testsuite/ltrace.minor/print-instruction-pointer.exp new file mode 100644 index 0000000..87cc8f7 --- /dev/null +++ b/testsuite/ltrace.minor/print-instruction-pointer.exp @@ -0,0 +1,42 @@ +# This file was written by Yao Qi . + +set testfile "print-instruction-pointer" +set srcfile ${testfile}.c +set binfile ${testfile} + + +verbose "compiling source file now....." +# Build the shared libraries this test case needs. +if { [ltrace_compile "${srcdir}/${subdir}/${srcfile}" "${srcdir}/${subdir}/${binfile}" executable {debug} ] != "" } { + send_user "Testcase compile failed, so all tests in this file will automatically fail.\n" +} + +# set options for ltrace. +ltrace_options "-i" +# Run PUT for ltrace. +set exec_output [ltrace_runtest $srcdir/$subdir $srcdir/$subdir/$binfile] + +# Check the output of this program. +verbose "ltrace runtest output: $exec_output\n" +if [regexp {ELF from incompatible architecture} $exec_output] { + fail "32-bit ltrace can not perform on 64-bit PUTs and rebuild ltrace in 64 bit mode!" + return +} elseif [ regexp {Couldn't get .hash data} $exec_output ] { + fail "Couldn't get .hash data!" + return +} + +# Get the addrss by objdump and sed. +catch "exec sh -c {objdump -d $srcdir/$subdir/$binfile | sed -n '/^\[0-9a-fA-F\]\[0-9a-fA-F\]*
/,/^\[0-9a-fA-F\]\[0-9a-fA-F\]* . + +set testfile "time-record" +set srcfile ${testfile}.c +set binfile ${testfile}-T + +verbose "compiling source file now....." +# Build the shared libraries this test case needs. +if { [ ltrace_compile "${srcdir}/${subdir}/${testfile}.c" "${srcdir}/${subdir}/${binfile}" executable {debug} ] != "" } { + send_user "Testcase compile failed, so all tests in this file will automatically fail.\n" +} + +# set options for ltrace. +ltrace_options "-T" + +# Run PUT for ltrace. +set exec_output [ltrace_runtest $srcdir/$subdir $srcdir/$subdir/$binfile] +verbose "ltrace runtest output: $exec_output\n" + +# Check the output of this program. +if [regexp {ELF from incompatible architecture} $exec_output] { + fail "32-bit ltrace can not perform on 64-bit PUTs and rebuild ltrace in 64 bit mode!" + return +} elseif [ regexp {Couldn't get .hash data} $exec_output ] { + fail "Couldn't get .hash data!" + return +} + +# Get the time of nanosleep in C source file. +set fd [ open $srcdir/$subdir/$srcfile r] +while { [gets $fd line] >= 0 } { + if [ regexp {define NANOSLEEP_COUNT ([0-9]+)} $line match nanosleep_usec] then { + break + } +} +close $fd + + +# Verify the time for calling sleep. +set fd [ open $srcdir/$subdir/$binfile.ltrace r] +set FOUND 0 +while { [gets $fd line] >= 0 } { + # match the line with sleep and extract the spent time in sleep and sleep argument. + if [ regexp {sleep\(([0-9]+).*<([0-9]+\.[0-9]+)>} $line match sleep_sec sec ] then { + verbose "sleep_sec = $sleep_sec, sec = $sec" + + if { $sec >= $sleep_sec } then { + pass "Correct Time spent inside call." + } else { + fail "Spent $sec inside call, but PUT call sleep($sleep_sec)!" + } + set FOUND 1 + break + } +} +close $fd + +if {$FOUND != 1} then { + fail "Fail to find call sleep!" +} + +# Verify the time for calling nanosleep. +set FOUND 0 +set fd [ open $srcdir/$subdir/$binfile.ltrace r] +while { [gets $fd line] >= 0 } { + # match the line with nanosleep and extract spent time and nanosleep argument. + if [ regexp {nanosleep.*<([0-9]+\.[0-9]+)>} $line match usec] then { + verbose "nanosleep_usec = $nanosleep_usec, usec = $usec" + + if { $usec * 1000 >= $nanosleep_usec} then { + pass "Correct Time spent inside call." + } else { + fail "Spent $usec inside call, but PUT call nanosleep($nanosleep_usec)!" + } + set FOUND 1 + break + } +} + +if { $FOUND != 1} then { + fail "Fail to find nanosleep" +} +close $fd + diff --git a/testsuite/ltrace.minor/time-record-tt.exp b/testsuite/ltrace.minor/time-record-tt.exp new file mode 100644 index 0000000..332704a --- /dev/null +++ b/testsuite/ltrace.minor/time-record-tt.exp @@ -0,0 +1,107 @@ +# This file was written by Yao Qi . + +set testfile "time-record" +set srcfile ${testfile}.c +set binfile ${testfile}-tt + +verbose "compiling source file now....." +# Build the shared libraries this test case needs. +if { [ ltrace_compile "${srcdir}/${subdir}/${testfile}.c" "${srcdir}/${subdir}/${binfile}" executable {debug} ] != "" } { + send_user "Testcase compile failed, so all tests in this file will automatically fail.\n" +} + +# Set options for ltrace. +ltrace_options "-tt" + +# Run PUT for ltrace. +set exec_output [ltrace_runtest $srcdir/$subdir $srcdir/$subdir/$binfile] + +# Check the output of this program. +verbose "ltrace runtest output: $exec_output\n" +if [regexp {ELF from incompatible architecture} $exec_output] { + fail "32-bit ltrace can not perform on 64-bit PUTs and rebuild ltrace in 64 bit mode!" + return +} elseif [ regexp {Couldn't get .hash data} $exec_output ] { + fail "Couldn't get .hash data!" + return +} + +# Verify the time for calling sleep. +set fd [ open $srcdir/$subdir/$binfile.ltrace r] +set FOUND 0 +while { [gets $fd line] >= 0 } { + # match the line with sleep and extract the strat time and sleep argument. + if [ regexp {[0-9]+:([0-9]+):([0-9]+)\.[0-9]+ sleep\(([0-9]+)} $line match start_min start_sec sleep_sec] then { + # Remove extra zero. + regexp {0([1-9])} $start_min match start_min + regexp {0([1-9])} $start_sec match start_sec + + verbose "start_sec = $start_sec, sleep_sec = $sleep_sec" + # get a new line for the end time of sleep + gets $fd line + regexp {[0-9]+:([0-9]+):([0-9]+)} $line match end_min end_sec + verbose "end_sec = $end_sec" + + # Remove extra zero. + regexp {0([1-9])} $end_min match end_min + regexp {0([1-9])} $end_sec match end_sec + + if { (($end_min - $start_min)*60 + $end_sec - $start_sec)== $sleep_sec } then { + pass "Correct Timestamp." + } else { + fail "Start at $start_sec, End at $end_sec, but PUT call sleep($sleep_sec)!" + } + set FOUND 1 + break + } +} +close $fd + +if {$FOUND != 1} then { + fail "Fail to find call sleep!" +} + +# Get the time of sleep and nanosleep in C source file. +set fd [ open $srcdir/$subdir/$srcfile r] +while { [gets $fd line] >= 0 } { + if [ regexp {define NANOSLEEP_COUNT ([0-9]+)} $line match nanosleep_usec] then { + break + } +} +close $fd + +# Verify the time for calling nanosleep. +set FOUND 0 +set fd [ open $srcdir/$subdir/$binfile.ltrace r] +while { [gets $fd line] >= 0 } { + # match the line with sleep and extract the strat time and sleep argument. + if [ regexp {[0-9]+:[0-9]+:([0-9]+)\.([0-9][0-9][0-9]).* nanosleep} $line match start_sec start_usec ] then { + # Remove extra zeros. + regexp {0([1-9])} $start_sec match start_sec + regexp {0*([1-9][0-9]*)} $start_usec match start_usec + + verbose "start_sec = $start_sec, start_usec = $start_usec, sleep_usec = $nanosleep_usec" + # get a new line for the end time of sleep + gets $fd line + regexp {[0-9]+:[0-9]+:([0-9]+)\.([0-9][0-9][0-9])} $line match end_sec end_usec + + # Remove extra zeros. + regexp {0([1-9])} $end_sec match end_sec + regexp {0*([1-9][0-9]*)} $end_usec match end_usec + + verbose "end_sec = $end_sec, end_usec = $end_usec" + if { (($end_sec - $start_sec)*1000 + $end_usec - $start_usec) >= $nanosleep_usec} then { + pass "Correct Timestamp." + } else { + fail "Start at $start_usec, End at $end_usec, but PUT call nanosleep($nanosleep_usec)!" + } + set FOUND 1 + break + } +} + +if { $FOUND != 1} then { + fail "Fail to find nanosleep" +} +close $fd + diff --git a/testsuite/ltrace.minor/time-record-ttt.exp b/testsuite/ltrace.minor/time-record-ttt.exp new file mode 100644 index 0000000..2aee9d3 --- /dev/null +++ b/testsuite/ltrace.minor/time-record-ttt.exp @@ -0,0 +1,112 @@ +# This file was written by Yao Qi . + +set testfile "time-record" +set srcfile ${testfile}.c +set binfile ${testfile}-ttt + +verbose "compiling source file now....." +# Build the shared libraries this test case needs. +if { [ ltrace_compile "${srcdir}/${subdir}/${testfile}.c" "${srcdir}/${subdir}/${binfile}" executable {debug} ] != "" } { + send_user "Testcase compile failed, so all tests in this file will automatically fail.\n" +} + +# Set options for ltrace. +ltrace_options "-ttt" + +# Run PUT for ltrace. +set exec_output [ltrace_runtest $srcdir/$subdir $srcdir/$subdir/$binfile] + + +# Check the output of this program. +verbose "ltrace runtest output: $exec_output\n" +if [regexp {ELF from incompatible architecture} $exec_output] { + fail "32-bit ltrace can not perform on 64-bit PUTs and rebuild ltrace in 64 bit mode!" + return +} elseif [ regexp {Couldn't get .hash data} $exec_output ] { + fail "Couldn't get .hash data!" + return +} + +# Verify the time for calling sleep. +set fd [ open $srcdir/$subdir/$binfile.ltrace r] +set FOUND 0 +while { [gets $fd line] >= 0 } { + # match the line with sleep and extract the strat time and sleep argument. + if [ regexp {([0-9]+)\.([0-9][0-9][0-9]).* sleep\(([0-9]+)} $line match start_sec start_usec sleep_sec] then { + + # Remove extra zeros. + regexp {0*([1-9][0-9]*)} $start_sec match start_sec + regexp {0*([1-9][0-9]*)} $start_usec match start_usec + + verbose "start_sec = $start_sec, start_usec = $start_usec,sleep_sec = $sleep_sec" + # get a new line for the end time of sleep + gets $fd line + regexp {([0-9]+)\.([0-9][0-9][0-9])} $line match end_sec end_usec + verbose "end_sec = $end_sec, end_usec=$end_usec" + + # Remove extra zeros. + regexp {0*([1-9][0-9]*)} $end_sec match end_sec + regexp {0*([1-9][0-9]*)} $end_usec match end_usec + + if { $end_sec - $start_sec >= $sleep_sec } then { + pass "Correct Timestamp." + } else { + fail "Start at $start_sec, End at $end_sec, but PUT call sleep($sleep_sec)!" + } + set FOUND 1 + break + } +} + +close $fd + +if {$FOUND != 1} then { + fail "Fail to find call sleep!" +} + + +# Get the time of nanosleep in C source file. +set fd [ open $srcdir/$subdir/$srcfile r] +while { [gets $fd line] >= 0 } { + if [ regexp {define NANOSLEEP_COUNT ([0-9]+)} $line match nanosleep_usec] then { + break + } +} +close $fd + +# Verify the time for calling nanosleep. +set FOUND 0 +set fd [ open $srcdir/$subdir/$binfile.ltrace r] +while { [gets $fd line] >= 0 } { + # match the line with sleep and extract the strat time and sleep argument. + if [ regexp {([0-9]+)\.([0-9][0-9][0-9]).* nanosleep} $line match start_sec start_usec ] then { + + # Remove extra zeros. + regexp {0*([1-9][0-9]*)} $start_sec match start_sec + regexp {0*([1-9][0-9]*)} $start_usec match start_usec + + verbose "start_sec = $start_sec, start_usec = $start_usec, nanosleep_usec = $nanosleep_usec" + # get a new line for the end time of sleep + gets $fd line + regexp {([0-9]+)\.([0-9][0-9][0-9])} $line match end_sec end_usec + + # Remove extra zeros. + regexp {0*([1-9][0-9]*)} $end_sec match end_sec + regexp {0*([1-9][0-9]*)} $end_usec match end_usec + + verbose "end_sec = $end_sec, end_usec = $end_usec" + if { ($end_sec - $start_sec)*1000 + $end_usec - $start_usec >= $nanosleep_usec} then { + pass "Correct Timestamp." + } else { + fail "Start at $start_usec, End at $end_usec, but PUT call nanosleep($nanosleep_usec)!" + } + set FOUND 1 + break + } +} + +if { $FOUND != 1} then { + fail "Fail to find nanosleep" +} +close $fd + diff --git a/testsuite/ltrace.minor/time-record.c b/testsuite/ltrace.minor/time-record.c new file mode 100644 index 0000000..a66b838 --- /dev/null +++ b/testsuite/ltrace.minor/time-record.c @@ -0,0 +1,23 @@ +/* Ltrace Test : time-record.c. + Objectives : Verify that Ltrace can record timestamp and spent + time inside each call. + + This file was written by Yao Qi . */ +#include +#include + +#define SLEEP_COUNT 2 +#define NANOSLEEP_COUNT 50 + +int +main () +{ + struct timespec request, remain; + request.tv_sec = 0; + request.tv_nsec = NANOSLEEP_COUNT * 1000000; + + sleep (SLEEP_COUNT); + nanosleep (&request, NULL); + + return 0; +} diff --git a/testsuite/ltrace.minor/trace-clone.c b/testsuite/ltrace.minor/trace-clone.c new file mode 100644 index 0000000..a1ccb22 --- /dev/null +++ b/testsuite/ltrace.minor/trace-clone.c @@ -0,0 +1,38 @@ +/* Ltrace Test : trace-clone.c. + Objectives : Verify that ltrace can trace to child process after + clone called. + + This file was written by Yao Qi . */ + +#include +#include +#include +#include + +int child () +{ + sleep(1); + return 0; +} + +typedef int (* myfunc)(); + +#define STACK_SIZE 1024 + +int main () +{ + pid_t pid; + static char stack[STACK_SIZE]; +#ifdef __ia64__ + pid = __clone2((myfunc)&child, stack, STACK_SIZE, CLONE_FS, NULL); +#else + pid = clone((myfunc)&child, stack + STACK_SIZE, CLONE_FS, NULL); +#endif + if (pid < 0) + { + perror("clone called failed"); + exit (1); + } + + return 0; +} diff --git a/testsuite/ltrace.minor/trace-clone.exp b/testsuite/ltrace.minor/trace-clone.exp new file mode 100644 index 0000000..bda036f --- /dev/null +++ b/testsuite/ltrace.minor/trace-clone.exp @@ -0,0 +1,44 @@ +# This file was written by Yao Qi . + +set testfile "trace-clone" +set srcfile ${testfile}.c +set binfile ${testfile} + + +verbose "compiling source file now....." +# Build the shared libraries this test case needs. +if { [ ltrace_compile "${srcdir}/${subdir}/${testfile}.c" "${srcdir}/${subdir}/${binfile}" executable {debug} ] != "" } { + send_user "Testcase compile failed, so all tests in this file will automatically fail.\n" +} +global LTRACE + +#Run PUT for ltrace. +spawn $LTRACE -f $srcdir/$subdir/$binfile +set timeout 4 +expect timeout { + fail "Time out! Maybe caused by ltrace segment fault or improper timeout value here!" + return +} + +catch "exec $LTRACE -f $srcdir/$subdir/$binfile" exec_output +# Save the output +ltrace_saveoutput "${exec_output}" ${srcdir}/${subdir}/${testfile}.ltrace + +#check the output of this program. +verbose "ltrace runtest output: $exec_output\n" +if [regexp {ELF from incompatible architecture} $exec_output] { + fail "32-bit ltrace can not perform on 64-bit PUTs and rebuild ltrace in 64 bit mode!" + return +} elseif [ regexp {Operation not permitted} $exec_output ] { + fail "Operation not permitted, see testrun.log for details!" + return +} elseif [ regexp {killed by SIGKILL} $exec_output ] { + fail "killed by SIGKILL!" + return +} + + + +set pattern "clone" +ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern 1 + diff --git a/testsuite/ltrace.minor/trace-exec.c b/testsuite/ltrace.minor/trace-exec.c new file mode 100644 index 0000000..e798cde --- /dev/null +++ b/testsuite/ltrace.minor/trace-exec.c @@ -0,0 +1,8 @@ +#include +#include + +int main (int argc, char ** argv) +{ + execl (argv[1], argv[1], NULL); + abort (); +} diff --git a/testsuite/ltrace.minor/trace-exec.exp b/testsuite/ltrace.minor/trace-exec.exp new file mode 100644 index 0000000..c9de6f3 --- /dev/null +++ b/testsuite/ltrace.minor/trace-exec.exp @@ -0,0 +1,45 @@ +set testfile "trace-exec" +set srcfile ${testfile}.c +set binfile ${testfile} + +verbose "compiling first source file now....." +if { [ ltrace_compile "${srcdir}/${subdir}/${testfile}.c" "${srcdir}/${subdir}/${binfile}" executable {debug} ] != "" } { + send_user "Testcase compile failed, so all tests in this file will automatically fail.\n" +} + +verbose "compiling second source file now....." +if { [ ltrace_compile "${srcdir}/${subdir}/${testfile}1.c" "${srcdir}/${subdir}/${binfile}1" executable {debug} ] != "" } { + send_user "Testcase compile failed, so all tests in this file will automatically fail.\n" +} + +global LTRACE +set exec_output "" + +#Run PUT for ltrace. +spawn $LTRACE $srcdir/$subdir/$testfile $srcdir/$subdir/${testfile}1 +set timeout 4 +expect timeout { + fail "Time out! Maybe caused by ltrace segment fault or improper timeout value here!" + return +} + +catch "exec $LTRACE $srcdir/$subdir/$testfile $srcdir/$subdir/${testfile}1" exec_output + +#check the output of this program. +verbose "ltrace runtest output: $exec_output\n" +if [regexp {ELF from incompatible architecture} $exec_output] { + fail "32-bit ltrace can not perform on 64-bit PUTs and rebuild ltrace in 64 bit mode!" + return +} elseif [ regexp {Couldn't get .hash data} $exec_output ] { + fail "Couldn't get .hash data!" + return +} + +ltrace_saveoutput "${exec_output}" ${srcdir}/${subdir}/${testfile}.ltrace + +# execl from first binary +ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace {"^execl"} 1 +# puts from second binary +ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace {"^puts"} 1 +# assume glibc and see we really trace both binaries +ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace {"^__libc_start_main"} 2 diff --git a/testsuite/ltrace.minor/trace-exec1.c b/testsuite/ltrace.minor/trace-exec1.c new file mode 100644 index 0000000..e234fa0 --- /dev/null +++ b/testsuite/ltrace.minor/trace-exec1.c @@ -0,0 +1,6 @@ +#include +int main (void) +{ + puts("Hello, World."); + return 0; +} diff --git a/testsuite/ltrace.minor/trace-fork.c b/testsuite/ltrace.minor/trace-fork.c new file mode 100644 index 0000000..a2d8a56 --- /dev/null +++ b/testsuite/ltrace.minor/trace-fork.c @@ -0,0 +1,33 @@ +/* Ltrace Test : trace-fork.c + Objectives : Verify that ltrace can trace to child process after + fork called. + + This file was written by Yao Qi . */ + +#include +#include + +void +child () +{ + printf("Fork Child\n"); + sleep(1); +} + +int +main () +{ + pid_t pid; + pid = fork (); + + if (pid == -1) + printf("fork failed!\n"); + else if (pid == 0) + child(); + else + { + printf("My child pid is %d\n",pid); + wait(); + } + return 0; +} diff --git a/testsuite/ltrace.minor/trace-fork.exp b/testsuite/ltrace.minor/trace-fork.exp new file mode 100644 index 0000000..5f30061 --- /dev/null +++ b/testsuite/ltrace.minor/trace-fork.exp @@ -0,0 +1,40 @@ +# This file was written by Yao Qi . + +set testfile "trace-fork" +set srcfile ${testfile}.c +set binfile ${testfile} + + +verbose "compiling source file now....." +# Build the shared libraries this test case needs. +if { [ ltrace_compile "${srcdir}/${subdir}/${testfile}.c" "${srcdir}/${subdir}/${binfile}" executable {debug} ] != "" } { + send_user "Testcase compile failed, so all tests in this file will automatically fail.\n" +} +global LTRACE +set exec_output "" + +#Run PUT for ltrace. +spawn $LTRACE -f $srcdir/$subdir/$binfile +set timeout 4 +expect timeout { + fail "Time out! Maybe caused by ltrace segment fault or improper timeout value here!" + return +} + +catch "exec $LTRACE -f $srcdir/$subdir/$binfile" exec_output + +#check the output of this program. +verbose "ltrace runtest output: $exec_output\n" +if [regexp {ELF from incompatible architecture} $exec_output] { + fail "32-bit ltrace can not perform on 64-bit PUTs and rebuild ltrace in 64 bit mode!" + return +} elseif [ regexp {Couldn't get .hash data} $exec_output ] { + fail "Couldn't get .hash data!" + return +} + +ltrace_saveoutput "${exec_output}" ${srcdir}/${subdir}/${testfile}.ltrace + +set pattern "fork" +ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern 1 + diff --git a/testsuite/ltrace.torture/Makefile b/testsuite/ltrace.torture/Makefile new file mode 100644 index 0000000..bb4baa0 --- /dev/null +++ b/testsuite/ltrace.torture/Makefile @@ -0,0 +1,33 @@ +# Copyright (C) 1992 - 2001 Free Software Foundation, Inc. +# +# 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 +# the Free Software Foundation; either version 1, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# 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. +# + +CLEANFILES = *.log *.sum site.bak setval.tmp site.exp + +.SUFFIXES: +clean: + -rm -f signals + -rm -f *.o *.so + -rm -f *.ltrace + -rm -f $(CLEANFILES) +distclean: clean + + +.PHONY: $(RECURSIVE_TARGETS) check clean distclean realclean + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/testsuite/ltrace.torture/ia64-sigill.exp b/testsuite/ltrace.torture/ia64-sigill.exp new file mode 100644 index 0000000..c4cf5a2 --- /dev/null +++ b/testsuite/ltrace.torture/ia64-sigill.exp @@ -0,0 +1,33 @@ +# This file was written by Yao Qi . + +set testfile "ia64-sigill" +set srcfile ${testfile}.s +set binfile ${testfile} + +if { [istarget ia64-*] } then { + verbose "compiling source file now....." + # Build the shared libraries this test case needs. + if { [ ltrace_compile "${srcdir}/${subdir}/${testfile}.s" "${srcdir}/${subdir}/${binfile}" executable {debug} ] != "" } { + send_user "Testcase compile failed, so all tests in this file will automatically fail\n." + } + + # Run PUT for ltarce. + set exec_output [ltrace_runtest $srcdir/$subdir $srcdir/$subdir/$binfile] + + # Check the output of this program. + verbose "ltrace runtest output: $exec_output\n" + if [regexp {ELF from incompatible architecture} $exec_output] { + fail "32-bit ltrace can not perform on 64-bit PUTs and rebuild ltrace in 64 bit mode!" + return + } elseif [ regexp {Couldn't get .hash data} $exec_output ] { + fail "Couldn't get .hash data!" + return + } + + catch "exec sh -c {grep SIGILL ${srcdir}/${subdir}/${testfile}.ltrace | wc -l ;exit}" output + if { $output == 0 } then { + pass "ltrace did interpret SIGILL as breakpoint." + } else { + fail "ltrace failed to interpret SIGILL as breakpoint." + } +} diff --git a/testsuite/ltrace.torture/ia64-sigill.s b/testsuite/ltrace.torture/ia64-sigill.s new file mode 100644 index 0000000..dccb674 --- /dev/null +++ b/testsuite/ltrace.torture/ia64-sigill.s @@ -0,0 +1,43 @@ + .file "pokus.c" + .pred.safe_across_calls p1-p5,p16-p63 + .section .rodata + .align 8 +.LC0: + stringz "" + .text + .align 16 + .global main# + .proc main# +main: + .prologue 14, 32 + .save ar.pfs, r33 + alloc r33 = ar.pfs, 0, 4, 1, 0 + .vframe r34 + mov r34 = r12 + mov r35 = r1 + .save rp, r32 + mov r32 = b0 + .body + addl r36 = @ltoffx(.LC0), r1 + ;; + ld8.mov r36 = [r36], .LC0 + br.call.sptk.many b0 = printf# + nop.b 0x0 + nop.b 0x1 + nop.b 0x2 + nop.b 0x0 + nop.b 0x1 + nop.b 0x2 + mov r1 = r35 + addl r14 = 234, r0 + ;; + mov r8 = r14 + mov ar.pfs = r33 + mov b0 = r32 + .restore sp + mov r12 = r34 + br.ret.sptk.many b0 + ;; + .endp main# + .section .note.GNU-stack,"",@progbits + .ident "GCC: (GNU) 3.4.6 20060404 (Red Hat 3.4.6-3)" diff --git a/testsuite/ltrace.torture/signals.c b/testsuite/ltrace.torture/signals.c new file mode 100644 index 0000000..439aba1 --- /dev/null +++ b/testsuite/ltrace.torture/signals.c @@ -0,0 +1,44 @@ +/* Ltrace Test : signals.c. + Objectives : Verify that ltrace can trace user defined signal. + This file was written by Yao Qi . */ + +#include +#include +#include + +#define LOOP 20 + +void +handler(int signum,siginfo_t *info,void *act) +{ +} + +int +main () +{ + struct sigaction act; + union sigval mysigval; + int i; + int sig; + pid_t pid; + + mysigval.sival_int=0; + sig = 10; + pid=getpid(); + + sigemptyset(&act.sa_mask); + act.sa_sigaction=handler; + act.sa_flags=SA_SIGINFO; + + if(sigaction(sig,&act,NULL) < 0) + { + printf("install sigal error\n"); + } + + for(i=0; i< LOOP; i++) + { + usleep(100); + sigqueue(pid,sig,mysigval); + } + return 0; +} diff --git a/testsuite/ltrace.torture/signals.exp b/testsuite/ltrace.torture/signals.exp new file mode 100644 index 0000000..56a2ec9 --- /dev/null +++ b/testsuite/ltrace.torture/signals.exp @@ -0,0 +1,37 @@ +# This file was written by Yao Qi . + +set testfile "signals" +set srcfile ${testfile}.c +set binfile ${testfile} + + +verbose "compiling source file now....." +# Build the shared libraries this test case needs. +if { [ ltrace_compile "${srcdir}/${subdir}/${testfile}.c" "${srcdir}/${subdir}/${binfile}" executable {debug} ] != "" } { + send_user "Testcase compile failed, so all tests in this file will automatically fail\n." +} + +# Set options for ltrace. +ltrace_options "-L" + +# Run PUT for ltarce. +set exec_output [ltrace_runtest $srcdir/$subdir $srcdir/$subdir/$binfile] + +# Check the output of this program. +verbose "ltrace runtest output: $exec_output\n" +if [regexp {ELF from incompatible architecture} $exec_output] { + fail "32-bit ltrace can not perform on 64-bit PUTs and rebuild ltrace in 64 bit mode!" + return +} elseif [ regexp {Couldn't get .hash data} $exec_output ] { + fail "Couldn't get .hash data!" + return +} + +# Extract LOOP from source file. +set fd [ open $srcdir/$subdir/$srcfile r] +while { [gets $fd line] >= 0 } { + regexp {define LOOP.*([0-9]+)} $line match count +} +set pattern "SIGUSR1" +ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern $count + diff --git a/testsuite/run-my-tests.sh b/testsuite/run-my-tests.sh new file mode 100755 index 0000000..3882c79 --- /dev/null +++ b/testsuite/run-my-tests.sh @@ -0,0 +1,43 @@ +#! /bin/sh +bitmode="" + +# This shell script is used to run the ltrace test suite. It is possible to +# run it via 'make check' using RUNTESTFLAGS. This script just makes it easy. + +function usage +{ + echo usage: `basename $0` '-m32|-m64 [ | ""] []' +} + +# The first argument is not optional: it must either be -m32 or -m64. If the +# second argument is used, it specifies the file name of the ltrace to be +# tested. The third argument specifies a particular test case to run. If +# the third argument is omitted, then all test cases are run. If you wish to +# use the third argument, but not the second, specify the second as "". + +# there is a secret argument: if the name of this script is 'test', then +# the --verbose argument is added to RUNTESTFLAGS. + +if [ x"$1" == x -o x"$1" != x-m32 -a x"$1" != x-m64 ]; then + usage + exit 1 +fi + +flags='' + +if [ `basename $0` == test ]; then + flags="--verbose " +fi + +if [ x"$2" != x ]; then + flags="${flags}--tool_exec=$2 " +fi + +flags="${flags}CFLAGS_FOR_TARGET=$1" + +if [ x"$3" != x ]; then + flags="$flags $3" +fi + +set -o xtrace +make check RUNTESTFLAGS="$flags" -- 2.7.4