Imported Upstream version 0.5.3 upstream/0.5.3
authorAnas Nashif <anas.nashif@intel.com>
Tue, 13 Nov 2012 15:28:12 +0000 (07:28 -0800)
committerAnas Nashif <anas.nashif@intel.com>
Tue, 13 Nov 2012 15:28:12 +0000 (07:28 -0800)
196 files changed:
BUGS [new file with mode: 0644]
COPYING [new file with mode: 0644]
ChangeLog [new file with mode: 0644]
INSTALL [new file with mode: 0644]
Makefile.in [new file with mode: 0644]
README [new file with mode: 0644]
TODO [new file with mode: 0644]
VERSION [new file with mode: 0644]
aclocal.m4 [new file with mode: 0644]
breakpoints.c [new file with mode: 0644]
common.h [new file with mode: 0644]
configure [new file with mode: 0755]
debian/changelog [new file with mode: 0644]
debian/compat [new file with mode: 0644]
debian/control.in [new file with mode: 0644]
debian/copyright [new file with mode: 0644]
debian/rules [new file with mode: 0755]
debug.c [new file with mode: 0644]
debug.h [new file with mode: 0644]
defs.h [new file with mode: 0644]
demangle.c [new file with mode: 0644]
demangle.h [new file with mode: 0644]
dict.c [new file with mode: 0644]
dict.h [new file with mode: 0644]
display_args.c [new file with mode: 0644]
elf.c [new file with mode: 0644]
elf.h [new file with mode: 0644]
etc/ltrace.conf [new file with mode: 0644]
execute_program.c [new file with mode: 0644]
handle_event.c [new file with mode: 0644]
libltrace.c [new file with mode: 0644]
ltrace.1 [new file with mode: 0644]
ltrace.h [new file with mode: 0644]
ltrace.spec [new file with mode: 0644]
main.c [new file with mode: 0644]
mkdist [new file with mode: 0755]
options.c [new file with mode: 0644]
options.h [new file with mode: 0644]
output.c [new file with mode: 0644]
output.h [new file with mode: 0644]
proc.c [new file with mode: 0644]
read_config_file.c [new file with mode: 0644]
read_config_file.h [new file with mode: 0644]
summary.c [new file with mode: 0644]
sysdeps/README [new file with mode: 0644]
sysdeps/linux-gnu/Makefile [new file with mode: 0644]
sysdeps/linux-gnu/README [new file with mode: 0644]
sysdeps/linux-gnu/alpha/Makefile [new file with mode: 0644]
sysdeps/linux-gnu/alpha/arch.h [new file with mode: 0644]
sysdeps/linux-gnu/alpha/plt.c [new file with mode: 0644]
sysdeps/linux-gnu/alpha/ptrace.h [new file with mode: 0644]
sysdeps/linux-gnu/alpha/regs.c [new file with mode: 0644]
sysdeps/linux-gnu/alpha/signalent.h [new file with mode: 0644]
sysdeps/linux-gnu/alpha/syscallent.h [new file with mode: 0644]
sysdeps/linux-gnu/alpha/trace.c [new file with mode: 0644]
sysdeps/linux-gnu/arch_mksyscallent [new file with mode: 0644]
sysdeps/linux-gnu/arm/Makefile [new file with mode: 0644]
sysdeps/linux-gnu/arm/arch.h [new file with mode: 0644]
sysdeps/linux-gnu/arm/arch_syscallent.h [new file with mode: 0644]
sysdeps/linux-gnu/arm/breakpoint.c [new file with mode: 0644]
sysdeps/linux-gnu/arm/plt.c [new file with mode: 0644]
sysdeps/linux-gnu/arm/ptrace.h [new file with mode: 0644]
sysdeps/linux-gnu/arm/regs.c [new file with mode: 0644]
sysdeps/linux-gnu/arm/signalent.h [new file with mode: 0644]
sysdeps/linux-gnu/arm/syscallent.h [new file with mode: 0644]
sysdeps/linux-gnu/arm/trace.c [new file with mode: 0644]
sysdeps/linux-gnu/breakpoint.c [new file with mode: 0644]
sysdeps/linux-gnu/events.c [new file with mode: 0644]
sysdeps/linux-gnu/i386/Makefile [new file with mode: 0644]
sysdeps/linux-gnu/i386/arch.h [new file with mode: 0644]
sysdeps/linux-gnu/i386/plt.c [new file with mode: 0644]
sysdeps/linux-gnu/i386/ptrace.h [new file with mode: 0644]
sysdeps/linux-gnu/i386/regs.c [new file with mode: 0644]
sysdeps/linux-gnu/i386/signalent.h [new file with mode: 0644]
sysdeps/linux-gnu/i386/syscallent.h [new file with mode: 0644]
sysdeps/linux-gnu/i386/trace.c [new file with mode: 0644]
sysdeps/linux-gnu/ia64/Makefile [new file with mode: 0644]
sysdeps/linux-gnu/ia64/arch.h [new file with mode: 0644]
sysdeps/linux-gnu/ia64/breakpoint.c [new file with mode: 0644]
sysdeps/linux-gnu/ia64/plt.c [new file with mode: 0644]
sysdeps/linux-gnu/ia64/ptrace.h [new file with mode: 0644]
sysdeps/linux-gnu/ia64/regs.c [new file with mode: 0644]
sysdeps/linux-gnu/ia64/signalent.h [new file with mode: 0644]
sysdeps/linux-gnu/ia64/syscallent.h [new file with mode: 0644]
sysdeps/linux-gnu/ia64/trace.c [new file with mode: 0644]
sysdeps/linux-gnu/m68k/Makefile [new file with mode: 0644]
sysdeps/linux-gnu/m68k/arch.h [new file with mode: 0644]
sysdeps/linux-gnu/m68k/plt.c [new file with mode: 0644]
sysdeps/linux-gnu/m68k/ptrace.h [new file with mode: 0644]
sysdeps/linux-gnu/m68k/regs.c [new file with mode: 0644]
sysdeps/linux-gnu/m68k/signalent.h [new file with mode: 0644]
sysdeps/linux-gnu/m68k/syscallent.h [new file with mode: 0644]
sysdeps/linux-gnu/m68k/trace.c [new file with mode: 0644]
sysdeps/linux-gnu/mipsel/Doxyfile [new file with mode: 0644]
sysdeps/linux-gnu/mipsel/Makefile [new file with mode: 0644]
sysdeps/linux-gnu/mipsel/arch.h [new file with mode: 0644]
sysdeps/linux-gnu/mipsel/mipsel.h [new file with mode: 0644]
sysdeps/linux-gnu/mipsel/plt.c [new file with mode: 0644]
sysdeps/linux-gnu/mipsel/ptrace.h [new file with mode: 0644]
sysdeps/linux-gnu/mipsel/regs.c [new file with mode: 0644]
sysdeps/linux-gnu/mipsel/signalent.h [new file with mode: 0644]
sysdeps/linux-gnu/mipsel/syscallent.h [new file with mode: 0644]
sysdeps/linux-gnu/mipsel/trace.c [new file with mode: 0644]
sysdeps/linux-gnu/mksignalent [new file with mode: 0755]
sysdeps/linux-gnu/mksyscallent [new file with mode: 0755]
sysdeps/linux-gnu/mksyscallent_s390 [new file with mode: 0644]
sysdeps/linux-gnu/ppc/Makefile [new file with mode: 0644]
sysdeps/linux-gnu/ppc/arch.h [new file with mode: 0644]
sysdeps/linux-gnu/ppc/plt.c [new file with mode: 0644]
sysdeps/linux-gnu/ppc/ptrace.h [new file with mode: 0644]
sysdeps/linux-gnu/ppc/regs.c [new file with mode: 0644]
sysdeps/linux-gnu/ppc/signalent.h [new file with mode: 0644]
sysdeps/linux-gnu/ppc/syscallent.h [new file with mode: 0644]
sysdeps/linux-gnu/ppc/trace.c [new file with mode: 0644]
sysdeps/linux-gnu/proc.c [new file with mode: 0644]
sysdeps/linux-gnu/s390/Makefile [new file with mode: 0644]
sysdeps/linux-gnu/s390/arch.h [new file with mode: 0644]
sysdeps/linux-gnu/s390/plt.c [new file with mode: 0644]
sysdeps/linux-gnu/s390/ptrace.h [new file with mode: 0644]
sysdeps/linux-gnu/s390/regs.c [new file with mode: 0644]
sysdeps/linux-gnu/s390/signalent.h [new file with mode: 0644]
sysdeps/linux-gnu/s390/signalent1.h [new file with mode: 0644]
sysdeps/linux-gnu/s390/syscallent.h [new file with mode: 0644]
sysdeps/linux-gnu/s390/syscallent1.h [new file with mode: 0644]
sysdeps/linux-gnu/s390/syscalls31.h [new file with mode: 0644]
sysdeps/linux-gnu/s390/syscalls64.h [new file with mode: 0644]
sysdeps/linux-gnu/s390/trace.c [new file with mode: 0644]
sysdeps/linux-gnu/sparc/Makefile [new file with mode: 0644]
sysdeps/linux-gnu/sparc/arch.h [new file with mode: 0644]
sysdeps/linux-gnu/sparc/plt.c [new file with mode: 0644]
sysdeps/linux-gnu/sparc/ptrace.h [new file with mode: 0644]
sysdeps/linux-gnu/sparc/regs.c [new file with mode: 0644]
sysdeps/linux-gnu/sparc/signalent.h [new file with mode: 0644]
sysdeps/linux-gnu/sparc/syscallent.h [new file with mode: 0644]
sysdeps/linux-gnu/sparc/trace.c [new file with mode: 0644]
sysdeps/linux-gnu/trace.c [new file with mode: 0644]
sysdeps/linux-gnu/x86_64/Makefile [new file with mode: 0644]
sysdeps/linux-gnu/x86_64/arch.h [new file with mode: 0644]
sysdeps/linux-gnu/x86_64/ffcheck.c [new file with mode: 0644]
sysdeps/linux-gnu/x86_64/plt.c [new file with mode: 0644]
sysdeps/linux-gnu/x86_64/ptrace.h [new file with mode: 0644]
sysdeps/linux-gnu/x86_64/regs.c [new file with mode: 0644]
sysdeps/linux-gnu/x86_64/signalent.h [new file with mode: 0644]
sysdeps/linux-gnu/x86_64/signalent1.h [new file with mode: 0644]
sysdeps/linux-gnu/x86_64/syscallent.h [new file with mode: 0644]
sysdeps/linux-gnu/x86_64/syscallent1.h [new file with mode: 0644]
sysdeps/linux-gnu/x86_64/trace.c [new file with mode: 0644]
testsuite/Makefile [new file with mode: 0644]
testsuite/README [new file with mode: 0644]
testsuite/config/unix.exp [new file with mode: 0644]
testsuite/lib/compiler.c [new file with mode: 0644]
testsuite/lib/compiler.cc [new file with mode: 0644]
testsuite/lib/ltrace.exp [new file with mode: 0644]
testsuite/ltrace.main/Makefile [new file with mode: 0644]
testsuite/ltrace.main/main-internal-1.c [new file with mode: 0644]
testsuite/ltrace.main/main-internal.c [new file with mode: 0644]
testsuite/ltrace.main/main-internal.exp [new file with mode: 0644]
testsuite/ltrace.main/main-lib.c [new file with mode: 0644]
testsuite/ltrace.main/main.c [new file with mode: 0644]
testsuite/ltrace.main/main.exp [new file with mode: 0644]
testsuite/ltrace.main/parameters-lib.c [new file with mode: 0644]
testsuite/ltrace.main/parameters.c [new file with mode: 0644]
testsuite/ltrace.main/parameters.conf [new file with mode: 0644]
testsuite/ltrace.main/parameters.exp [new file with mode: 0644]
testsuite/ltrace.main/signals.c [new file with mode: 0644]
testsuite/ltrace.main/signals.exp [new file with mode: 0644]
testsuite/ltrace.main/system_calls.c [new file with mode: 0644]
testsuite/ltrace.main/system_calls.exp [new file with mode: 0644]
testsuite/ltrace.minor/Makefile [new file with mode: 0644]
testsuite/ltrace.minor/attach-process.c [new file with mode: 0644]
testsuite/ltrace.minor/attach-process.exp [new file with mode: 0644]
testsuite/ltrace.minor/count-record.c [new file with mode: 0644]
testsuite/ltrace.minor/count-record.exp [new file with mode: 0644]
testsuite/ltrace.minor/demangle-lib.cpp [new file with mode: 0644]
testsuite/ltrace.minor/demangle.cpp [new file with mode: 0644]
testsuite/ltrace.minor/demangle.exp [new file with mode: 0644]
testsuite/ltrace.minor/demangle.h [new file with mode: 0644]
testsuite/ltrace.minor/print-instruction-pointer.c [new file with mode: 0644]
testsuite/ltrace.minor/print-instruction-pointer.exp [new file with mode: 0644]
testsuite/ltrace.minor/time-record-T.exp [new file with mode: 0644]
testsuite/ltrace.minor/time-record-tt.exp [new file with mode: 0644]
testsuite/ltrace.minor/time-record-ttt.exp [new file with mode: 0644]
testsuite/ltrace.minor/time-record.c [new file with mode: 0644]
testsuite/ltrace.minor/trace-clone.c [new file with mode: 0644]
testsuite/ltrace.minor/trace-clone.exp [new file with mode: 0644]
testsuite/ltrace.minor/trace-exec.c [new file with mode: 0644]
testsuite/ltrace.minor/trace-exec.exp [new file with mode: 0644]
testsuite/ltrace.minor/trace-exec1.c [new file with mode: 0644]
testsuite/ltrace.minor/trace-fork.c [new file with mode: 0644]
testsuite/ltrace.minor/trace-fork.exp [new file with mode: 0644]
testsuite/ltrace.torture/Makefile [new file with mode: 0644]
testsuite/ltrace.torture/ia64-sigill.exp [new file with mode: 0644]
testsuite/ltrace.torture/ia64-sigill.s [new file with mode: 0644]
testsuite/ltrace.torture/signals.c [new file with mode: 0644]
testsuite/ltrace.torture/signals.exp [new file with mode: 0644]
testsuite/run-my-tests.sh [new file with mode: 0755]

diff --git a/BUGS b/BUGS
new file mode 100644 (file)
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 (file)
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.
+\f
+                   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.)
+\f
+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.
+\f
+  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.
+\f
+  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
+\f
+           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.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    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.
+
+  <signature of Ty Coon>, 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 (file)
index 0000000..49b785f
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,539 @@
+2009-07-25  Juan Cespedes <cespedes@debian.org>
+
+       * 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 <cespedes@debian.org>
+
+       * 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 <cespedes@debian.org>
+
+       * clean-up of structs Process, Breakpoint, Function and Event
+
+2009-04-07  Juan Cespedes <cespedes@debian.org>
+
+       * 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 <cespedes@debian.org>
+
+       * 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 <cespedes@debian.org>
+
+       * summary.c: Fix "ltrace -o -c"
+       * mkdist: rm -rf autom4te.cache
+       * debian/control.ini: re-added armel and armeb
+
+2008-12-10  Juan Cespedes <cespedes@debian.org>
+
+       * Release version 0.5.1
+
+2008-12-10  Juan Cespedes <cespedes@debian.org>
+
+       * 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  <luisgpm@br.ibm.com>
+
+       * 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  <cespedes@debian.org>
+
+       * 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  <cespedes@debian.org>
+
+       * 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  <pmachata@redhat.com>
+
+       * Based on work of Supriya Kannery <supriyak@in.ibm.com>
+       * 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  <pmachata@redhat.com>
+
+       * 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  <pmachata@redhat.com>
+
+       * 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  <evaitl@cisco.com>
+
+       * 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  <pmachata@redhat.com>
+
+       * 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  <pmachata@redhat.com>
+
+       * 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 <olh@suse.de>
+
+       * options.c: fix up typo for config file
+
+2006-09-25  Olaf Hering <olh@suse.de>
+
+       * 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 <sphink@gmail.com>
+
+       * 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 <olh@suse.de>
+
+       * 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 <sphink@gmail.com>
+
+       * 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 <sphink@gmail.com>
+
+       * 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 <sphink@gmail.com>
+
+       * 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 <sphink@gmail.com>
+
+       * 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 <sphink@gmail.com>
+
+       * 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 <sphink@gmail.com>
+
+       * 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 <sphink@gmail.com>
+
+       * 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  <sphink@gmail.com>
+
+       * 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 <sphink@gmail.com>
+
+       * display_args.c, etc/ltrace.conf, ltrace.h, read_config_file.c:
+       implement ignored arguments
+
+2006-08-07  Steve Fink <sphink@gmail.com>
+
+       * 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 <sphink@gmail.com>
+
+       * 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 <sphink@gmail.com>
+
+       * testsuite/lib/ltrace.exp: better quoting and error detection for
+       ltrace_verify_output's call to grep
+
+2006-08-07  Steve Fink  <sphink@gmail.com>
+
+       * ltrace.1: update bug email addr
+
+2006-07-26  Ian Wienand  <ianw@debian.org>
+
+       * elf.c: refactor opd2addr to not pass void* (fix warnings)
+
+2006-07-18  Petr Machata <pmachata@redhat.com>
+
+       * 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 <pmachata@redhat.com>
+
+       * elf.c: support .gnu.hash ELF entry
+       * elf.h: likewise
+
+2006-07-18  Petr Machata  <pmachata@redhat.com>
+
+       * options.c: don't hardcode version number
+
+2006-07-18  Justin Pryzby <justinpryzby@users.sourceforge.net>
+
+       * ltrace.1: make demagle clearer
+
+2006-07-16  Steve Fink  <sphink@gmail.com>
+
+       * 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  <ianw@ieee.org>
+
+       * 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 <heiko.carstens@de.ibm.com>
+
+       * sysdeps/linux-gnu/s390/syscalls31.h: update to 2.6.17
+       * sysdeps/linux-gnu/s390/syscalls64.h: ditto
+
+2006-06-16  Justin Pryzby <justinpryzby@users.sourceforge.net>
+
+       * ltrace.1: spelling fix
+       * TODO: spelling fix
+
+2006-06-14  Ian Wienand  <ianw@gelato.unsw.edu.au>
+
+       * 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 <heiko.carstens@de.ibm.com>
+
+       * 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 <pgilliam@us.ibm.com>
+
+       * 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 <pgilliam@us.ibm.com>
+
+       * 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 <pgilliam@us.ibm.com>
+
+       * summery.c: Correct a typo prevented the inclusion of "demangle.h".
+
+2006-03-16  Ian Wienand  <ianw@gelato.unsw.edu.au>
+
+       * testsuite/ltrace.minor/trace-clone.c: use __clone2() for IA64
+       clone test
+
+2006-03=13  Paul Gilliam <pgilliam@us.ibm.com>
+
+       * 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 <pgilliam@us.ibm.com>
+
+       * 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  <ianw@ieee.org>
+
+       * Makefile.in: remove unneeded dirs from make dist; use rm
+       directly.
+
+2006-02-22  Ian Wienand  <ianw@ieee.org>
+
+       * COPYING: update from FSF to update address
+       * Makefile.in: check for SVN checkout with make dist.
+
+2006-02-21  Ian Wienand  <ianw@ieee.org>
+
+       * README: update to point to Alioth list
+
+2006-02-21  Ian Wienand  <ianw@ieee.org>
+
+       * 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  <ianw@ieee.org>
+
+       * 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  <ianw@ieee.org>
+
+       * Makefile.in: install documentation into share/doc, make dist
+       target from SVN export.
+
+2006-02-16  Rajeev V. Pillai <rajeevvp@yahoo.com>
+
+       * Makefile.in: pass through CPP and LD FLAGS
+
+2006-02-16  Ian Wienand  <ianw@ieee.org>
+
+       * 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 <bernd@zeimetz.de>
+
+       * ltrace.1: reference reportbug
+
+2006-02-16 Colin S. Miller <csmiller@iname.com>
+
+       * ltrace.1: fix debug typo
+
+2006-02-16  Andrew Stribblehill <ads@debian.org>
+
+       * etc/ltrace.conf: fix putenv typo
+
+2006-02-16  Ian Wienand <ianw@ieee.org>
+
+       * 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 (file)
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-<version>.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 (file)
index 0000000..1e8adcd
--- /dev/null
@@ -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 (file)
index 0000000..ab1a2e5
--- /dev/null
+++ b/README
@@ -0,0 +1,92 @@
+                                ltrace
+
+                       A Dynamic Library Tracer
+
+         Copyright 1997-2009 Juan Cespedes <cespedes@debian.org>
+
+
+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 <cespedes@debian.org>,
+but he has received many contributions from other people.  The following
+people have contributed significantly to this project:
+
+* César Sánchez <cesar.sanchez@imdea.org>
+* Santiago Romero <santiago.romero@imdea.org>
+* Pat Beirne <pbeirne@home.com> (ARM port)
+* Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de> (m68k port)
+* Morten Eriksen <mortene@sim.no> (misc fixes)
+* Silvio Cesare <silvio@big.net.au> (ELF hacking)
+* Timothy Fesig <slate@us.ibm.com> (S390 port)
+* Anton Blanchard <anton@samba.org> (Powerpc port)
+* Jakub Jelinek <jakub@redhat.com> (SPARC port, support for libelf, many fixes)
+* Jakub Bogusz <qboosh@pld-linux.org> (alpha port)
+* SuSE (amd64 port)
+* Ian Wienand <ianw@gelato.unsw.edu.au> (IA64 port)
+* Eric Vaitl <evaitl@cisco.com> (mipsel port)
+* Petr Machata <pmachata@redhat.com> (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 <cespedes@debian.org>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    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 (file)
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 (file)
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 (file)
index 0000000..abe07e0
--- /dev/null
@@ -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 </dev/null` in
+*GNU* | *'with BFD'*)
+  acl_cv_prog_gnu_ld=yes ;;
+*)
+  acl_cv_prog_gnu_ld=no ;;
+esac])
+with_gnu_ld=$acl_cv_prog_gnu_ld
+])
+
+dnl From libtool-1.4. Sets the variable LD.
+AC_DEFUN([AC_LIB_PROG_LD],
+[AC_ARG_WITH(gnu-ld,
+[  --with-gnu-ld           assume the C compiler uses GNU ld [default=no]],
+test "$withval" = no || with_gnu_ld=yes, with_gnu_ld=no)
+AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([AC_CANONICAL_HOST])dnl
+# Prepare PATH_SEPARATOR.
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+  echo "#! /bin/sh" >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 (file)
index 0000000..ba3b060
--- /dev/null
@@ -0,0 +1,230 @@
+#include "config.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#ifdef __powerpc__
+#include <sys/ptrace.h>
+#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 (file)
index 0000000..c672913
--- /dev/null
+++ b/common.h
@@ -0,0 +1,253 @@
+#include <sys/types.h>
+#include <sys/time.h>
+#include <stdio.h>
+
+#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 (executable)
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 <gelf.h>
+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 (file)
index 0000000..f97cb8f
--- /dev/null
@@ -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 <cespedes@debian.org>  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 <cespedes@debian.org>  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 <cespedes@debian.org>  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 <cespedes@debian.org>  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 <cespedes@debian.org>  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 <riku.voipio@iki.fi>  Tue, 29 Jan 2008 00:26:50 +0200
+
+ltrace (0.5-3) unstable; urgency=low
+
+  * Really fix compilation problems in ppc (!)
+
+ -- Juan Cespedes <cespedes@debian.org>  Fri, 31 Aug 2007 19:04:03 +0200
+
+ltrace (0.5-2) unstable; urgency=low
+
+  * Fixed compilation issue in ppc
+
+ -- Juan Cespedes <cespedes@debian.org>  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 <cespedes@debian.org>  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 <jianfenggui@gmail.com>)
+
+ -- Juan Cespedes <cespedes@debian.org>  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 <ianw@ieee.org>  Tue, 21 Feb 2006 09:23:09 +1100
+
+ltrace (0.3.38-1) unstable; urgency=low
+
+  * Closes: 306862 -- Add IA64 support
+
+ -- Ian Wienand <ianw@ieee.org>  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 <ianw@ieee.org>  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 <ianw@ieee.org>  Thu, 16 Feb 2006 11:51:32 +1100
+
+ltrace (0.3.36-2) unstable; urgency=low
+
+  * Corrected path for Debian changelog
+
+ -- Juan Cespedes <cespedes@debian.org>  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 <cespedes@debian.org>  Wed, 10 Nov 2004 00:14:19 +0100
+
+ltrace (0.3.35.1) unstable; urgency=low
+
+  * Non-maintainer upload
+  * Applied patch from Jakub Jelinek <jakub@redhat.com> 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 <apollock@debian.org>  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 <cespedes@debian.org>  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 <cespedes@debian.org>  Wed, 07 Jul 2004 10:40:56 +0200
+
+ltrace (0.3.33) unstable; urgency=low
+
+  * Fixed two bugs, thanks to Mauro Meneghin <G1ld0@lycos.it>:
+    + 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 <taw@users.sf.net>)
+  * Some fixes from Jakub Bogusz <qboosh@pld-linux.org>:
+    + Small 64-bit cleanup of code
+    + support for more than 6 function arguments on amd64
+    + Adapted SPARC port from Jakub Jelinek <jakub@redhat.com>
+    + Added alpha support
+  
+ -- Juan Cespedes <cespedes@debian.org>  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 <bk@suse.de> for his great work
+
+ -- Juan Cespedes <cespedes@debian.org>  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 <jakub@redhat.com>    (closes: Bug#144518)
+  * Fixed off-by-one problem in checking syscall number
+  * Removed some warnings
+
+ -- Juan Cespedes <cespedes@debian.org>  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 <cespedes@debian.org>  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 <cespedes@debian.org>  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 <cespedes@debian.org>  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 <cespedes@debian.org>  Fri, 31 Jan 2003 18:58:55 +0100
+
+ltrace (0.3.26) unstable; urgency=low
+
+  * Fixed `ltrace -L' in powerpc
+
+ -- Juan Cespedes <cespedes@debian.org>  Sun, 31 Mar 2002 20:53:49 +0200
+
+ltrace (0.3.25) unstable; urgency=low
+
+  * Finally added powerpc support (Anton Blanchard <anton@samba.org>)
+
+ -- Juan Cespedes <cespedes@debian.org>  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 <anton@samba.org>)
+
+ -- Juan Cespedes <cespedes@debian.org>  Wed, 27 Mar 2002 00:20:57 +0100
+
+ltrace (0.3.23) unstable; urgency=low
+
+  * Fixed missing include <unistd.h> in trace.c
+  * One arch-dependent function less (continue_after_breakpoint)
+  * Fixed S/390 port (it didn't compile yet...)
+
+ -- Juan Cespedes <cespedes@debian.org>  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 <cespedes@debian.org>  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 <cespedes@debian.org>  Sun,  3 Mar 2002 02:37:46 +0100
+
+ltrace (0.3.20) unstable; urgency=low
+
+  * Added s390 port (Timothy R. Fesig <slate@us.ibm.com>)
+  * Modified configure process to use ltrace.spec.in to generate
+    ltrace.spec (Timothy R. Fesig <slate@us.ibm.com>)
+  * Fixed some problems using ltrace.spec on Intel platform.
+                (Timothy R. Fesig <slate@us.ibm.com>)
+
+ -- Juan Cespedes <cespedes@debian.org>  Sat,  2 Mar 2002 23:33:00 +0100
+
+ltrace (0.3.19) unstable; urgency=low
+
+  * Fixed small bug: "<unifinished...>" lines were sometimes incorrectly
+    displayed
+  * Added new functions to /etc/ltrace.conf (thanks to James R. Van Zandt
+    <jrv@vanzandt.mv.com>)                          (closes: Bug#91349)
+
+ -- Juan Cespedes <cespedes@debian.org>  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
+    <twaugh@redhat.com> fixed this problem in RedHat two years ago;
+    thank you for NOT noticing me...)
+
+ -- Juan Cespedes <cespedes@debian.org>  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 <cespedes@debian.org>  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 <cespedes@debian.org>  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 <cespedes@debian.org>  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 <cespedes@debian.org>  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 <cespedes@debian.org>  Tue,  3 Jul 2001 18:36:15 +0200
+
+ltrace (0.3.12) unstable; urgency=low
+
+  * Re-wrote of "elf.c" (Silvio Cesare <silvio@big.net.au>)
+  * 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 <cespedes@debian.org>  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 <cespedes@debian.org>  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 <cespedes@debian.org>  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 <cespedes@debian.org>  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 <getopt.h>
+  * 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 <mortene@sim.no>)
+  * New Standards-Version: 3.0.1 (but keeping docs in /usr/doc)
+
+ -- Juan Cespedes <cespedes@debian.org>  Mon, 30 Aug 1999 19:34:47 +0200
+
+ltrace (0.3.7) unstable; urgency=low
+
+  * Minor fixes
+  * Added minor patch from Alex Buell <alex.buell@tahallah.demon.co.uk>
+    to be able to compile under glibc 2.1
+  * Additions to config file from David Dyck <dcd@tc.fluke.com>
+  * 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 <cespedes@debian.org>  Sat,  3 Apr 1999 03:21:50 +0200
+
+ltrace (0.3.6) unstable; urgency=low
+
+  * Added m68k port (Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>) (Bug#27075)
+  * Changed "int pid" with "pid_t pid" everywhere
+  * Fixed return type of some functions from "int" to "void *" (thanks, Roman)
+
+ -- Juan Cespedes <cespedes@debian.org>  Fri, 25 Sep 1998 14:48:37 +0200
+
+ltrace (0.3.5) unstable; urgency=low
+
+  * Added ARMLinux port (Pat Beirne <pbeirne@home.com>) (Bug#27040)
+  * Fixed minor things in options.c
+
+ -- Juan Cespedes <cespedes@debian.org>  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 <cespedes@debian.org>  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 <cespedes@debian.org>  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 <cespedes@debian.org>  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 <cespedes@debian.org>  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 <cespedes@debian.org>  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 <cespedes@debian.org>  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 <cespedes@debian.org>  Sat,  4 Apr 1998 08:34:03 +0200
+
+ltrace (0.2.7) unstable; urgency=low
+
+  * Some minor fixes
+
+ -- Juan Cespedes <cespedes@debian.org>  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 <cespedes@debian.org>  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 <cespedes@debian.org>  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 <cespedes@debian.org>  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 <cespedes@debian.org>  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 <cespedes@debian.org>  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 <cespedes@debian.org>  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 <cespedes@debian.org>  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 <cespedes@debian.org>  Sun, 26 Oct 1997 19:53:20 +0100
+
+ltrace (0.1.6) experimental; urgency=low
+
+  * New maintainer address
+  * New Standards-Version
+
+ -- Juan Cespedes <cespedes@debian.org>  Thu, 11 Sep 1997 23:22:32 +0200
+
+ltrace (0.1.5) experimental; urgency=low
+
+  * `command' is now searched in the PATH
+
+ -- Juan Cespedes <cespedes@etsit.upm.es>  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 <cespedes@etsit.upm.es>  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 <cespedes@etsit.upm.es>  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 <cespedes@etsit.upm.es>  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 <cespedes@etsit.upm.es>  Sat, 23 Aug 1997 02:09:14 +0200
+
+ltrace (0.1.0) experimental; urgency=low
+
+  * Some clean-ups
+  * Added simple manual page
+
+ -- Juan Cespedes <cespedes@etsit.upm.es>  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 <cespedes@etsit.upm.es>  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 <cespedes@etsit.upm.es>  Sat,  9 Aug 1997 20:55:24 +0200
diff --git a/debian/compat b/debian/compat
new file mode 100644 (file)
index 0000000..7ed6ff8
--- /dev/null
@@ -0,0 +1 @@
+5
diff --git a/debian/control.in b/debian/control.in
new file mode 100644 (file)
index 0000000..aff5316
--- /dev/null
@@ -0,0 +1,23 @@
+Source: ltrace
+Section: utils
+Priority: optional
+Maintainer: Juan Cespedes <cespedes@debian.org>
+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 (file)
index 0000000..facd682
--- /dev/null
@@ -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 <cespedes@debian.org>
+
+ARMLinux port: Copyright (C) 1998 Pat Beirne <pbeirne@home.com>
+m68k port: Copyright (C) 1998 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
+Misc fixes: Copyright (C) 1999 Morten Eriksen <mortene@sim.no>
+s390 port: Copyright (C) 2001 IBM Poughkeepsie, IBM Cororation <slate@us.ibm.com>
+ELF hacking: Copyright (C) 1999 Silvio Cesare <silvio@big.net.au>
+PowerPC port: Copyright (C) 2001-2002 Anton Blanchard <anton@samba.org>
+SPARC port: Copyright (C) 1999 Jakub Jelinek <jakub@redhat.com>
+
+
+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 (executable)
index 0000000..4105eb7
--- /dev/null
@@ -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 (file)
index 0000000..1be873b
--- /dev/null
+++ b/debug.c
@@ -0,0 +1,112 @@
+#include <stdio.h>
+#include <stdarg.h>
+
+#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 <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/ptrace.h>
+
+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 (file)
index 0000000..653da84
--- /dev/null
+++ b/debug.h
@@ -0,0 +1,17 @@
+#include <features.h>
+
+/* 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 (file)
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 (file)
index 0000000..5825e28
--- /dev/null
@@ -0,0 +1,44 @@
+#include "config.h"
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#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 (file)
index 0000000..beac791
--- /dev/null
@@ -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 (file)
index 0000000..486a461
--- /dev/null
+++ b/dict.c
@@ -0,0 +1,215 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "common.h"
+
+/*
+  Dictionary based on code by Morten Eriksen <mortene@sim.no>.
+*/
+
+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 (file)
index 0000000..a70c3d5
--- /dev/null
+++ b/dict.h
@@ -0,0 +1,20 @@
+/*
+  Dictionary based on code by Morten Eriksen <mortene@sim.no>.
+*/
+
+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 (file)
index 0000000..993a808
--- /dev/null
@@ -0,0 +1,460 @@
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#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, "<array without address>");
+       case ARGTYPE_ENUM:
+               return display_enum(type, proc, info, value);
+       case ARGTYPE_STRUCT:
+               return fprintf(options.output, "<struct without address>");
+       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 (file)
index 0000000..aeff211
--- /dev/null
+++ b/elf.c
@@ -0,0 +1,619 @@
+# include "config.h"
+
+#include <endian.h>
+#include <errno.h>
+#include <error.h>
+#include <fcntl.h>
+#include <gelf.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#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, &lte->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 = &lte[i].hash[2];
+                       chain = &lte[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(&lte[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; i<lte->dynsym_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(&lte[i]);
+
+       return library_symbols;
+}
diff --git a/elf.h b/elf.h
new file mode 100644 (file)
index 0000000..426f7b8
--- /dev/null
+++ b/elf.h
@@ -0,0 +1,49 @@
+#ifndef LTRACE_ELF_H
+#define LTRACE_ELF_H
+
+#include <gelf.h>
+#include <stdlib.h>
+
+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 (file)
index 0000000..ed4fc5a
--- /dev/null
@@ -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 (file)
index 0000000..5fd6379
--- /dev/null
@@ -0,0 +1,91 @@
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <pwd.h>
+#include <grp.h>
+
+#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 (file)
index 0000000..1dfb82b
--- /dev/null
@@ -0,0 +1,696 @@
+#include "config.h"
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <assert.h>
+#include <sys/time.h>
+
+#include "common.h"
+
+#ifdef __powerpc__
+#include <sys/ptrace.h>
+#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 (file)
index 0000000..0f48d11
--- /dev/null
@@ -0,0 +1,154 @@
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/param.h>
+#include <signal.h>
+#include <sys/wait.h>
+
+#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; i<num_ltrace_callbacks[ev->type]; 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 (file)
index 0000000..358d6aa
--- /dev/null
+++ b/ltrace.1
@@ -0,0 +1,206 @@
+.\" Copyright (c) 1997-2005 Juan Cespedes <cespedes@debian.org>
+.\" 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 <cespedes@debian.org>
+
+.SH "SEE ALSO"
+.BR strace(1) ,
+.BR ptrace(2)
+
diff --git a/ltrace.h b/ltrace.h
new file mode 100644 (file)
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 (file)
index 0000000..3740190
--- /dev/null
@@ -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 <jkeating@redhat.com> - 0.3.36-4.2
+- bump again for double-long bug on ppc(64)
+
+* Tue Feb 07 2006 Jesse Keating <jkeating@redhat.com> - 0.3.36-4.1
+- rebuilt for new gcc4.1 snapshot and glibc changes
+
+* Mon Jan  9 2006 Jakub Jelinek <jakub@redhat.com> 0.3.36-4
+- added ppc64 and s390x support (IBM)
+- added ia64 support (Ian Wienand)
+
+* Sat Mar  5 2005 Jakub Jelinek <jakub@redhat.com> 0.3.36-3
+- rebuilt with GCC 4
+
+* Tue Dec 14 2004 Jakub Jelinek <jakub@redhat.com> 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 <jakub@redhat.com> 0.3.36-1
+- update to 0.3.36
+
+* Mon Oct 11 2004 Jakub Jelinek <jakub@redhat.com> 0.3.35-1
+- update to 0.3.35
+- update syscall tables from latest kernel source
+
+* Tue Jun 15 2004 Elliot Lee <sopwith@redhat.com>
+- rebuilt
+
+* Tue Jun  8 2004 Jakub Jelinek <jakub@redhat.com> 0.3.32-3
+- buildreq elfutils-libelf-devel (#124921)
+
+* Thu Apr 22 2004 Jakub Jelinek <jakub@redhat.com> 0.3.32-2
+- fix demangling
+
+* Thu Apr 22 2004 Jakub Jelinek <jakub@redhat.com> 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 <sopwith@redhat.com>
+- rebuilt
+
+* Mon Feb  3 2003 Jakub Jelinek <jakub@redhat.com> 0.3.29-1
+- update to 0.3.29
+
+* Wed Jan 22 2003 Tim Powers <timp@redhat.com>
+- rebuilt
+
+* Sun Sep  1 2002 Jakub Jelinek <jakub@redhat.com> 0.3.10-12
+- add a bunch of missing functions to ltrace.conf
+  (like strlen, ugh)
+
+* Fri Jun 21 2002 Tim Powers <timp@redhat.com>
+- automated rebuild
+
+* Tue May 28 2002 Phil Knirsch <pknirsch@redhat.com>
+- Added the 'official' s390 patch.
+
+* Thu May 23 2002 Tim Powers <timp@redhat.com>
+- automated rebuild
+
+* Wed Jan 09 2002 Tim Powers <timp@redhat.com>
+- automated rebuild
+
+* Fri Jul 20 2001 Jakub Jelinek <jakub@redhat.com>
+- fix stale symlink in documentation directory (#47749)
+
+* Sun Jun 24 2001 Elliot Lee <sopwith@redhat.com>
+- Bump release + rebuild.
+
+* Thu Aug  2 2000 Tim Waugh <twaugh@redhat.com>
+- fix off-by-one problem in checking syscall number
+
+* Wed Jul 12 2000 Prospector <bugzilla@redhat.com>
+- automatic rebuild
+
+* Mon Jun 19 2000 Matt Wilson <msw@redhat.com>
+- rebuilt for next release
+- patched Makefile.in to take a hint on mandir (patch2)
+- use %%{_mandir} and %%makeinstall
+
+* Wed Feb 02 2000 Cristian Gafton <gafton@redhat.com>
+- fix description
+
+* Fri Jan  7 2000 Jeff Johnson <jbj@redhat.com>
+- update to 0.3.10.
+- include (but don't apply) sparc patch from Jakub Jellinek.
+
+* Sun Mar 21 1999 Cristian Gafton <gafton@redhat.com> 
+- auto rebuild in the new build environment (release 2)
+
+* Fri Mar 12 1999 Jeff Johnson <jbj@redhat.com>
+- update to 0.3.6.
+
+* Mon Sep 21 1998 Preston Brown <pbrown@redhat.com>
+- upgraded to 0.3.4
diff --git a/main.c b/main.c
new file mode 100644 (file)
index 0000000..bd443cf
--- /dev/null
+++ b/main.c
@@ -0,0 +1,37 @@
+#include <stdio.h>
+#include <unistd.h>
+
+#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 (executable)
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 (file)
index 0000000..aef73b1
--- /dev/null
+++ b/options.c
@@ -0,0 +1,431 @@
+#include "config.h"
+
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <limits.h>
+#include <sys/ioctl.h>
+
+#include <getopt.h>
+
+#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=<octal> or -D<octal>:\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 <cespedes@debian.org>.\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 (file)
index 0000000..db253c5
--- /dev/null
+++ b/options.h
@@ -0,0 +1,55 @@
+#include <stdio.h>
+#include <sys/types.h>
+
+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 (file)
index 0000000..bb07ab1
--- /dev/null
+++ b/output.c
@@ -0,0 +1,303 @@
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <time.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+#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, " <unfinished ...>\n");
+               } else {
+                       fprintf(options.output, " <no return ...>\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, " <unfinished ...>\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, " <unfinished ...>\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, "<void>");
+               } 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 (file)
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 (file)
index 0000000..bfc6e41
--- /dev/null
+++ b/proc.c
@@ -0,0 +1,65 @@
+#include <sys/types.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#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 (file)
index 0000000..b4b1b56
--- /dev/null
@@ -0,0 +1,680 @@
+#include "config.h"
+
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#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 (file)
index 0000000..8000b1c
--- /dev/null
@@ -0,0 +1 @@
+extern void read_config_file(char *);
diff --git a/summary.c b/summary.c
new file mode 100644 (file)
index 0000000..dab845c
--- /dev/null
+++ b/summary.c
@@ -0,0 +1,86 @@
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/time.h>
+
+#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 (file)
index 0000000..ce033ef
--- /dev/null
@@ -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 (file)
index 0000000..eb1ec60
--- /dev/null
@@ -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 (file)
index 0000000..a8bc8ee
--- /dev/null
@@ -0,0 +1,13 @@
+* "arch/syscallent.h" is made from <asm/unistd.h>.
+  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 <asm/signal.h>.
+  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 (file)
index 0000000..60d7531
--- /dev/null
@@ -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 (file)
index 0000000..1107b5f
--- /dev/null
@@ -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 (file)
index 0000000..83337b2
--- /dev/null
@@ -0,0 +1,12 @@
+#include <gelf.h>
+#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 (file)
index 0000000..c3cbcb6
--- /dev/null
@@ -0,0 +1 @@
+#include <sys/ptrace.h>
diff --git a/sysdeps/linux-gnu/alpha/regs.c b/sysdeps/linux-gnu/alpha/regs.c
new file mode 100644 (file)
index 0000000..9554e48
--- /dev/null
@@ -0,0 +1,40 @@
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/ptrace.h>
+#include <asm/ptrace.h>
+
+#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 (file)
index 0000000..c2a6170
--- /dev/null
@@ -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 (file)
index 0000000..7cacc8c
--- /dev/null
@@ -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 (file)
index 0000000..e4d4063
--- /dev/null
@@ -0,0 +1,75 @@
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <sys/ptrace.h>
+#include <asm/ptrace.h>
+
+#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 (file)
index 0000000..853d62d
--- /dev/null
@@ -0,0 +1,42 @@
+#!/usr/bin/awk -f
+
+# hack expression to generate arch_syscallent.h from <asm/unistd.h>
+# 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 (file)
index 0000000..f55ba48
--- /dev/null
@@ -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 (file)
index 0000000..8f2dfb3
--- /dev/null
@@ -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 (file)
index 0000000..ce1e844
--- /dev/null
@@ -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 (file)
index 0000000..4c20260
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * This file is part of ltrace.
+ *
+ * Copyright (C) 2007 by Instituto Nokia de Tecnologia (INdT)
+ *
+ * Author: Anderson Lizardo <anderson.lizardo@indt.org.br>
+ *
+ * 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 <sys/ptrace.h>
+#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 (file)
index 0000000..bd92a63
--- /dev/null
@@ -0,0 +1,12 @@
+#include <gelf.h>
+#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 (file)
index 0000000..52215bc
--- /dev/null
@@ -0,0 +1,9 @@
+#include <sys/ptrace.h>
+#include <asm/ptrace.h>
+
+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 (file)
index 0000000..2488b0a
--- /dev/null
@@ -0,0 +1,51 @@
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/ptrace.h>
+#include <asm/ptrace.h>
+
+#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 (file)
index 0000000..0afb004
--- /dev/null
@@ -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 (file)
index 0000000..4113234
--- /dev/null
@@ -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 (file)
index 0000000..10f7cc4
--- /dev/null
@@ -0,0 +1,131 @@
+#include "config.h"
+
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <sys/ptrace.h>
+#include <asm/ptrace.h>
+
+#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<cond> 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 (file)
index 0000000..5ca131a
--- /dev/null
@@ -0,0 +1,86 @@
+#include "config.h"
+
+#include <sys/ptrace.h>
+#include <string.h>
+
+#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 (file)
index 0000000..a1e2a14
--- /dev/null
@@ -0,0 +1,161 @@
+#include "config.h"
+
+#define        _GNU_SOURCE     1
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <signal.h>
+#include <string.h>
+#include <sys/ptrace.h>
+
+#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 (file)
index 0000000..60d7531
--- /dev/null
@@ -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 (file)
index 0000000..dc7383f
--- /dev/null
@@ -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 (file)
index 0000000..b53ff44
--- /dev/null
@@ -0,0 +1,12 @@
+#include <gelf.h>
+#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 (file)
index 0000000..c3cbcb6
--- /dev/null
@@ -0,0 +1 @@
+#include <sys/ptrace.h>
diff --git a/sysdeps/linux-gnu/i386/regs.c b/sysdeps/linux-gnu/i386/regs.c
new file mode 100644 (file)
index 0000000..6777f17
--- /dev/null
@@ -0,0 +1,40 @@
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/ptrace.h>
+#include <asm/ptrace.h>
+
+#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 (file)
index 0000000..5395f82
--- /dev/null
@@ -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 (file)
index 0000000..8f4c887
--- /dev/null
@@ -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 (file)
index 0000000..76f1105
--- /dev/null
@@ -0,0 +1,85 @@
+#include "config.h"
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <sys/ptrace.h>
+#include <asm/ptrace.h>
+
+#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 (file)
index 0000000..4f0ef63
--- /dev/null
@@ -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 (file)
index 0000000..673047c
--- /dev/null
@@ -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 (file)
index 0000000..4f09173
--- /dev/null
@@ -0,0 +1,212 @@
+/* IA64 breakpoint support.  Much of this clagged from gdb
+ *  -Ian Wienand <ianw@gelato.unsw.edu.au> 10/3/2005
+ */
+
+#include "config.h"
+
+#include <sys/ptrace.h>
+#include <string.h>
+#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 (file)
index 0000000..7fd451b
--- /dev/null
@@ -0,0 +1,46 @@
+#include <gelf.h>
+#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 (file)
index 0000000..c3cbcb6
--- /dev/null
@@ -0,0 +1 @@
+#include <sys/ptrace.h>
diff --git a/sysdeps/linux-gnu/ia64/regs.c b/sysdeps/linux-gnu/ia64/regs.c
new file mode 100644 (file)
index 0000000..d161d34
--- /dev/null
@@ -0,0 +1,51 @@
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/ptrace.h>
+
+#include <asm/ptrace_offsets.h>
+#include <asm/rse.h>
+
+#include <stddef.h>
+#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 (file)
index 0000000..5395f82
--- /dev/null
@@ -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 (file)
index 0000000..9bb4fb8
--- /dev/null
@@ -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 (file)
index 0000000..799e0ff
--- /dev/null
@@ -0,0 +1,268 @@
+#include "config.h"
+
+#include <stdlib.h>
+#include <stddef.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <sys/ptrace.h>
+#include <string.h>
+#include <asm/ptrace_offsets.h>
+#include <asm/rse.h>
+
+#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(&reg);
+       }
+
+       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(&reg);
+               } 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(&reg);
+               }
+       }
+
+       /* 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 (file)
index 0000000..60d7531
--- /dev/null
@@ -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 (file)
index 0000000..1790d09
--- /dev/null
@@ -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 (file)
index 0000000..508d7fc
--- /dev/null
@@ -0,0 +1,13 @@
+#include <gelf.h>
+#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 (file)
index 0000000..c3cbcb6
--- /dev/null
@@ -0,0 +1 @@
+#include <sys/ptrace.h>
diff --git a/sysdeps/linux-gnu/m68k/regs.c b/sysdeps/linux-gnu/m68k/regs.c
new file mode 100644 (file)
index 0000000..959a60e
--- /dev/null
@@ -0,0 +1,40 @@
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/ptrace.h>
+#include <asm/ptrace.h>
+
+#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 (file)
index 0000000..5395f82
--- /dev/null
@@ -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 (file)
index 0000000..4d65b39
--- /dev/null
@@ -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 (file)
index 0000000..2f89fdf
--- /dev/null
@@ -0,0 +1,89 @@
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <sys/ptrace.h>
+#include <asm/ptrace.h>
+
+#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 (file)
index 0000000..b4f5eb2
--- /dev/null
@@ -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 (file)
index 0000000..44f4aae
--- /dev/null
@@ -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 (file)
index 0000000..dd0ca35
--- /dev/null
@@ -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 (file)
index 0000000..a63cafd
--- /dev/null
@@ -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 (file)
index 0000000..003171b
--- /dev/null
@@ -0,0 +1,72 @@
+#include <debug.h>
+#include <gelf.h>
+#include <sys/ptrace.h>
+#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 (file)
index 0000000..c3cbcb6
--- /dev/null
@@ -0,0 +1 @@
+#include <sys/ptrace.h>
diff --git a/sysdeps/linux-gnu/mipsel/regs.c b/sysdeps/linux-gnu/mipsel/regs.c
new file mode 100644 (file)
index 0000000..a7a6de1
--- /dev/null
@@ -0,0 +1,76 @@
+#include "config.h"
+
+#include <stddef.h>
+#include <sys/types.h>
+#include <sys/ptrace.h>
+#include <asm/ptrace.h>
+#include <linux/user.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
+   @{
+ */
+
+
+/**
+   \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 (file)
index 0000000..6bb1ff6
--- /dev/null
@@ -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 (file)
index 0000000..bed43fe
--- /dev/null
@@ -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 (file)
index 0000000..ff94930
--- /dev/null
@@ -0,0 +1,167 @@
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <sys/ptrace.h>
+#include <asm/ptrace.h>
+#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 (executable)
index 0000000..316d81f
--- /dev/null
@@ -0,0 +1,33 @@
+#!/usr/bin/awk -f
+
+# hack expression to generate arch/signalent.h from <asm/signal.h>
+# 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 (executable)
index 0000000..e0c3ec7
--- /dev/null
@@ -0,0 +1,45 @@
+#!/usr/bin/awk -f
+
+# hack expression to generate arch/syscallent.h from <asm/unistd.h>
+# 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 (file)
index 0000000..73416d9
--- /dev/null
@@ -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 (file)
index 0000000..60d7531
--- /dev/null
@@ -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 (file)
index 0000000..711b4a3
--- /dev/null
@@ -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 (file)
index 0000000..31830fb
--- /dev/null
@@ -0,0 +1,54 @@
+#include <gelf.h>
+#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 (file)
index 0000000..c3cbcb6
--- /dev/null
@@ -0,0 +1 @@
+#include <sys/ptrace.h>
diff --git a/sysdeps/linux-gnu/ppc/regs.c b/sysdeps/linux-gnu/ppc/regs.c
new file mode 100644 (file)
index 0000000..eca58ff
--- /dev/null
@@ -0,0 +1,47 @@
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/ptrace.h>
+#include <asm/ptrace.h>
+
+#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 (file)
index 0000000..d58a36c
--- /dev/null
@@ -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 (file)
index 0000000..5ce5739
--- /dev/null
@@ -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 (file)
index 0000000..81fb71d
--- /dev/null
@@ -0,0 +1,155 @@
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <sys/ptrace.h>
+#include <asm/ptrace.h>
+#include <elf.h>
+#include <errno.h>
+
+#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 (file)
index 0000000..4251c1d
--- /dev/null
@@ -0,0 +1,36 @@
+#include "config.h"
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+#include <unistd.h>
+
+/* /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 (file)
index 0000000..cea1b45
--- /dev/null
@@ -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 (file)
index 0000000..03690b8
--- /dev/null
@@ -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 (file)
index 0000000..85a1dd1
--- /dev/null
@@ -0,0 +1,12 @@
+#include <gelf.h>
+#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 (file)
index 0000000..c3cbcb6
--- /dev/null
@@ -0,0 +1 @@
+#include <sys/ptrace.h>
diff --git a/sysdeps/linux-gnu/s390/regs.c b/sysdeps/linux-gnu/s390/regs.c
new file mode 100644 (file)
index 0000000..169893e
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+** S/390 version
+** Copyright (C) 2001 IBM Poughkeepsie, IBM Corporation
+*/
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/ptrace.h>
+#include <asm/ptrace.h>
+
+#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 (file)
index 0000000..35b74f1
--- /dev/null
@@ -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 (file)
index 0000000..b5b6ca8
--- /dev/null
@@ -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 (file)
index 0000000..5a35d93
--- /dev/null
@@ -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 (file)
index 0000000..c9fdc81
--- /dev/null
@@ -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 (file)
index 0000000..42631eb
--- /dev/null
@@ -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 (file)
index 0000000..97be52c
--- /dev/null
@@ -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 (file)
index 0000000..9df2437
--- /dev/null
@@ -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 <errno.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <sys/ptrace.h>
+#include <asm/ptrace.h>
+
+#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 (file)
index 0000000..b3914e5
--- /dev/null
@@ -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 (file)
index 0000000..75251b8
--- /dev/null
@@ -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 (file)
index 0000000..f9e6d80
--- /dev/null
@@ -0,0 +1,12 @@
+#include <gelf.h>
+#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 (file)
index 0000000..bbaf01a
--- /dev/null
@@ -0,0 +1,21 @@
+#undef PTRACE_GETREGS
+#undef PTRACE_SETREGS
+#undef PTRACE_GETFPREGS
+#undef PTRACE_SETFPREGS
+#include <sys/ptrace.h>
+#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 <asm/ptrace.h>
+
+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 (file)
index 0000000..49d2729
--- /dev/null
@@ -0,0 +1,49 @@
+#include "config.h"
+
+#include <sys/types.h>
+#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 (file)
index 0000000..d30f69e
--- /dev/null
@@ -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 (file)
index 0000000..96eeec9
--- /dev/null
@@ -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 (file)
index 0000000..7f05b55
--- /dev/null
@@ -0,0 +1,81 @@
+#include "config.h"
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <string.h>
+#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 (file)
index 0000000..df5b090
--- /dev/null
@@ -0,0 +1,193 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include "ptrace.h"
+#include <asm/unistd.h>
+
+#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 (file)
index 0000000..0a19c97
--- /dev/null
@@ -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 (file)
index 0000000..255395c
--- /dev/null
@@ -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 (file)
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 (file)
index 0000000..b53ff44
--- /dev/null
@@ -0,0 +1,12 @@
+#include <gelf.h>
+#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 (file)
index 0000000..c3cbcb6
--- /dev/null
@@ -0,0 +1 @@
+#include <sys/ptrace.h>
diff --git a/sysdeps/linux-gnu/x86_64/regs.c b/sysdeps/linux-gnu/x86_64/regs.c
new file mode 100644 (file)
index 0000000..ed1f118
--- /dev/null
@@ -0,0 +1,54 @@
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/ptrace.h>
+#include <sys/reg.h>
+
+#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 (file)
index 0000000..d58a36c
--- /dev/null
@@ -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 (file)
index 0000000..5ead946
--- /dev/null
@@ -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 (file)
index 0000000..5e5f88a
--- /dev/null
@@ -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 (file)
index 0000000..d8dd9f7
--- /dev/null
@@ -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 (file)
index 0000000..189734d
--- /dev/null
@@ -0,0 +1,144 @@
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <sys/ptrace.h>
+#include <sys/reg.h>
+
+#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 (file)
index 0000000..b78807e
--- /dev/null
@@ -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 (file)
index 0000000..63d2b3b
--- /dev/null
@@ -0,0 +1,244 @@
+                     README for ltrace testsuite
+              18, October, 2005 by Yao Qi  <qiyao@cn.ibm.com>
+
+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 (file)
index 0000000..29d28a2
--- /dev/null
@@ -0,0 +1 @@
+load_lib ltrace.exp
diff --git a/testsuite/lib/compiler.c b/testsuite/lib/compiler.c
new file mode 100644 (file)
index 0000000..e6b1ec6
--- /dev/null
@@ -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 (file)
index 0000000..7068462
--- /dev/null
@@ -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 (file)
index 0000000..b56d50d
--- /dev/null
@@ -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 (file)
index 0000000..449214a
--- /dev/null
@@ -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 (file)
index 0000000..2a5cd0c
--- /dev/null
@@ -0,0 +1,8 @@
+#include<stdio.h>
+
+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 (file)
index 0000000..7508d06
--- /dev/null
@@ -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 <qiyao@cn.ibm.com>. */
+#include<stdio.h>
+
+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 (file)
index 0000000..f3f0015
--- /dev/null
@@ -0,0 +1,33 @@
+# This file was written by Yao Qi <qiyao@cn.ibm.com>.
+
+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 (file)
index 0000000..5fd53b3
--- /dev/null
@@ -0,0 +1,7 @@
+#include<stdio.h>
+
+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 (file)
index 0000000..0f270bf
--- /dev/null
@@ -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 <qiyao@cn.ibm.com>.  */
+
+extern void print ( char* );
+
+#define        PRINT_LOOP      10
+
+int
+main ()
+{
+  int i;
+
+  for (i=0; i<PRINT_LOOP; i++)
+    print ("Library function call!");
+  
+  return 0;
+}
+
diff --git a/testsuite/ltrace.main/main.exp b/testsuite/ltrace.main/main.exp
new file mode 100644 (file)
index 0000000..ca66deb
--- /dev/null
@@ -0,0 +1,39 @@
+# This file was written by Yao Qi <qiyao@cn.ibm.com>.
+
+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 (file)
index 0000000..26e4c3b
--- /dev/null
@@ -0,0 +1,117 @@
+#include <string.h>
+#include <stdio.h>
+
+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 (file)
index 0000000..dd63612
--- /dev/null
@@ -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 <sphink@gmail.com>. */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+
+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 (file)
index 0000000..33c1a1e
--- /dev/null
@@ -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 (file)
index 0000000..bb55e03
--- /dev/null
@@ -0,0 +1,72 @@
+# This file was written by Steve Fink <sphink@gmail.com>.
+# Based on main.c by Yao Qi <qiyao@cn.ibm.com>.
+
+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 (file)
index 0000000..a02e795
--- /dev/null
@@ -0,0 +1,48 @@
+/* Ltrace Test : signals.c.
+   Objectives  : Verify that ltrace can trace user defined signal.
+   This file was written by Yao Qi <qiyao@cn.ibm.com>. */
+
+#include<stdio.h>
+#include<signal.h>
+#include <sys/types.h>
+
+#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<LOOP; i++)
+    {
+      sleep(1);
+      sigqueue(pid,sig,mysigval);
+    }
+  return 0;
+}
diff --git a/testsuite/ltrace.main/signals.exp b/testsuite/ltrace.main/signals.exp
new file mode 100644 (file)
index 0000000..f0708e9
--- /dev/null
@@ -0,0 +1,39 @@
+# This file was written by Yao Qi <qiyao@cn.ibm.com>.
+
+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 (file)
index 0000000..7be3d04
--- /dev/null
@@ -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 <qiyao@cn.ibm.com>. */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+#include <sys/stat.h>
+#include <errno.h>
+
+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 (file)
index 0000000..b274db5
--- /dev/null
@@ -0,0 +1,67 @@
+# This file was written by Yao Qi <qiyao@cn.ibm.com>.
+
+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 (file)
index 0000000..cd4914f
--- /dev/null
@@ -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 (file)
index 0000000..4c00bce
--- /dev/null
@@ -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 <qiyao@cn.ibm.com>.  */
+
+#include<unistd.h>
+#include <sys/types.h>
+
+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 (file)
index 0000000..ab5460e
--- /dev/null
@@ -0,0 +1,38 @@
+# This file was written by Yao Qi <qiyao@cn.ibm.com>.
+
+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 (file)
index 0000000..3b609ad
--- /dev/null
@@ -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 <qiyao@cn.ibm.com>.  */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+#include <sys/stat.h>
+#include <errno.h>
+
+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 (file)
index 0000000..f8c4923
--- /dev/null
@@ -0,0 +1,77 @@
+# This file was written by Yao Qi <qiyao@cn.ibm.com>.
+
+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 (file)
index 0000000..01ab18d
--- /dev/null
@@ -0,0 +1,97 @@
+#include<stddef.h>
+#include<iostream>
+
+#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 (file)
index 0000000..14cc9f6
--- /dev/null
@@ -0,0 +1,121 @@
+/* Ltrace Test : demangle.cpp
+   Objectives  : Verify that ltrace can demangle C++ symbols.
+
+   This file was written by Yao Qi <qiyao@cn.ibm.com>.  */
+
+#include<stddef.h>
+#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 (file)
index 0000000..5077ac0
--- /dev/null
@@ -0,0 +1,63 @@
+# This file was written by Yao Qi <qiyao@cn.ibm.com>.
+
+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 (file)
index 0000000..02aa156
--- /dev/null
@@ -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 (file)
index 0000000..37b8441
--- /dev/null
@@ -0,0 +1,11 @@
+#include <stdio.h>
+
+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 (file)
index 0000000..87cc8f7
--- /dev/null
@@ -0,0 +1,42 @@
+# This file was written by Yao Qi <qiyao@cn.ibm.com>.
+
+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\]* <main>/,/^\[0-9a-fA-F\]\[0-9a-fA-F\]* </p'| grep -A 1 'call\\|bl' }" output
+#verbose "output=$output"
+catch "exec sh -c {echo \"$output\" | sed -n '2p'| awk -F' ' '{print \$1}'|awk -F: '{print \$1}'}" addr1
+catch "exec sh -c {echo \"$output\" | sed -n '5p'| awk -F' ' '{print \$1}'|awk -F: '{print \$1}'}" addr2
+
+verbose "addr1 = $addr1"
+verbose "addr2 = $addr2"
+# Verify the output by checking numbers of print in main.ltrace.
+set pattern "$addr1.*printf"
+ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern 1
+
+set pattern "$addr2.*printf"
+ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace $pattern 1
diff --git a/testsuite/ltrace.minor/time-record-T.exp b/testsuite/ltrace.minor/time-record-T.exp
new file mode 100644 (file)
index 0000000..b411add
--- /dev/null
@@ -0,0 +1,84 @@
+# This file was written by Yao Qi <qiyao@cn.ibm.com>.
+
+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 (file)
index 0000000..332704a
--- /dev/null
@@ -0,0 +1,107 @@
+# This file was written by Yao Qi <qiyao@cn.ibm.com>.
+
+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 (file)
index 0000000..2aee9d3
--- /dev/null
@@ -0,0 +1,112 @@
+# This file was written by Yao Qi <qiyao@cn.ibm.com>.
+
+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 (file)
index 0000000..a66b838
--- /dev/null
@@ -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 <qiyao@cn.ibm.com>.  */
+#include <stdio.h>
+#include <time.h>
+
+#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 (file)
index 0000000..a1ccb22
--- /dev/null
@@ -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 <qiyao@cn.ibm.com>.  */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <sched.h>
+
+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 (file)
index 0000000..bda036f
--- /dev/null
@@ -0,0 +1,44 @@
+# This file was written by Yao Qi <qiyao@cn.ibm.com>.
+
+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 (file)
index 0000000..e798cde
--- /dev/null
@@ -0,0 +1,8 @@
+#include <unistd.h>
+#include <stdlib.h>
+
+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 (file)
index 0000000..c9de6f3
--- /dev/null
@@ -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 (file)
index 0000000..e234fa0
--- /dev/null
@@ -0,0 +1,6 @@
+#include <stdio.h>
+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 (file)
index 0000000..a2d8a56
--- /dev/null
@@ -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 <qiyao@cn.ibm.com>.  */
+
+#include <stdio.h>
+#include <sys/types.h>
+
+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 (file)
index 0000000..5f30061
--- /dev/null
@@ -0,0 +1,40 @@
+# This file was written by Yao Qi <qiyao@cn.ibm.com>.
+
+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 (file)
index 0000000..bb4baa0
--- /dev/null
@@ -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 (file)
index 0000000..c4cf5a2
--- /dev/null
@@ -0,0 +1,33 @@
+# This file was written by Yao Qi <qiyao@cn.ibm.com>.
+
+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 (file)
index 0000000..dccb674
--- /dev/null
@@ -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 (file)
index 0000000..439aba1
--- /dev/null
@@ -0,0 +1,44 @@
+/* Ltrace Test : signals.c.
+   Objectives  : Verify that ltrace can trace user defined signal.
+   This file was written by Yao Qi <qiyao@cn.ibm.com>. */
+
+#include<stdio.h>
+#include<signal.h>
+#include <sys/types.h>
+
+#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 (file)
index 0000000..56a2ec9
--- /dev/null
@@ -0,0 +1,37 @@
+# This file was written by Yao Qi <qiyao@cn.ibm.com>.
+
+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 (executable)
index 0000000..3882c79
--- /dev/null
@@ -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 [<tool> | ""] [<test.exp>]'
+}
+
+# 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"