summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--BUGS6
-rw-r--r--COPYING340
-rw-r--r--ChangeLog539
-rw-r--r--INSTALL19
-rw-r--r--Makefile.in74
-rw-r--r--README92
-rw-r--r--TODO36
-rw-r--r--VERSION1
-rw-r--r--aclocal.m4833
-rw-r--r--breakpoints.c230
-rw-r--r--common.h253
-rwxr-xr-xconfigure157
-rw-r--r--debian/changelog652
-rw-r--r--debian/compat1
-rw-r--r--debian/control.in23
-rw-r--r--debian/copyright39
-rwxr-xr-xdebian/rules7
-rw-r--r--debug.c112
-rw-r--r--debug.h17
-rw-r--r--defs.h18
-rw-r--r--demangle.c44
-rw-r--r--demangle.h12
-rw-r--r--dict.c215
-rw-r--r--dict.h20
-rw-r--r--display_args.c460
-rw-r--r--elf.c619
-rw-r--r--elf.h49
-rw-r--r--etc/ltrace.conf604
-rw-r--r--execute_program.c91
-rw-r--r--handle_event.c696
-rw-r--r--libltrace.c154
-rw-r--r--ltrace.1206
-rw-r--r--ltrace.h38
-rw-r--r--ltrace.spec164
-rw-r--r--main.c37
-rwxr-xr-xmkdist19
-rw-r--r--options.c431
-rw-r--r--options.h55
-rw-r--r--output.c303
-rw-r--r--output.h3
-rw-r--r--proc.c65
-rw-r--r--read_config_file.c680
-rw-r--r--read_config_file.h1
-rw-r--r--summary.c86
-rw-r--r--sysdeps/README32
-rw-r--r--sysdeps/linux-gnu/Makefile60
-rw-r--r--sysdeps/linux-gnu/README13
-rw-r--r--sysdeps/linux-gnu/alpha/Makefile10
-rw-r--r--sysdeps/linux-gnu/alpha/arch.h8
-rw-r--r--sysdeps/linux-gnu/alpha/plt.c12
-rw-r--r--sysdeps/linux-gnu/alpha/ptrace.h1
-rw-r--r--sysdeps/linux-gnu/alpha/regs.c40
-rw-r--r--sysdeps/linux-gnu/alpha/signalent.h32
-rw-r--r--sysdeps/linux-gnu/alpha/syscallent.h439
-rw-r--r--sysdeps/linux-gnu/alpha/trace.c75
-rw-r--r--sysdeps/linux-gnu/arch_mksyscallent42
-rw-r--r--sysdeps/linux-gnu/arm/Makefile10
-rw-r--r--sysdeps/linux-gnu/arm/arch.h11
-rw-r--r--sysdeps/linux-gnu/arm/arch_syscallent.h6
-rw-r--r--sysdeps/linux-gnu/arm/breakpoint.c77
-rw-r--r--sysdeps/linux-gnu/arm/plt.c12
-rw-r--r--sysdeps/linux-gnu/arm/ptrace.h9
-rw-r--r--sysdeps/linux-gnu/arm/regs.c51
-rw-r--r--sysdeps/linux-gnu/arm/signalent.h33
-rw-r--r--sysdeps/linux-gnu/arm/syscallent.h322
-rw-r--r--sysdeps/linux-gnu/arm/trace.c131
-rw-r--r--sysdeps/linux-gnu/breakpoint.c86
-rw-r--r--sysdeps/linux-gnu/events.c161
-rw-r--r--sysdeps/linux-gnu/i386/Makefile10
-rw-r--r--sysdeps/linux-gnu/i386/arch.h6
-rw-r--r--sysdeps/linux-gnu/i386/plt.c12
-rw-r--r--sysdeps/linux-gnu/i386/ptrace.h1
-rw-r--r--sysdeps/linux-gnu/i386/regs.c40
-rw-r--r--sysdeps/linux-gnu/i386/signalent.h32
-rw-r--r--sysdeps/linux-gnu/i386/syscallent.h317
-rw-r--r--sysdeps/linux-gnu/i386/trace.c85
-rw-r--r--sysdeps/linux-gnu/ia64/Makefile10
-rw-r--r--sysdeps/linux-gnu/ia64/arch.h13
-rw-r--r--sysdeps/linux-gnu/ia64/breakpoint.c212
-rw-r--r--sysdeps/linux-gnu/ia64/plt.c46
-rw-r--r--sysdeps/linux-gnu/ia64/ptrace.h1
-rw-r--r--sysdeps/linux-gnu/ia64/regs.c51
-rw-r--r--sysdeps/linux-gnu/ia64/signalent.h32
-rw-r--r--sysdeps/linux-gnu/ia64/syscallent.h1303
-rw-r--r--sysdeps/linux-gnu/ia64/trace.c268
-rw-r--r--sysdeps/linux-gnu/m68k/Makefile10
-rw-r--r--sysdeps/linux-gnu/m68k/arch.h6
-rw-r--r--sysdeps/linux-gnu/m68k/plt.c13
-rw-r--r--sysdeps/linux-gnu/m68k/ptrace.h1
-rw-r--r--sysdeps/linux-gnu/m68k/regs.c40
-rw-r--r--sysdeps/linux-gnu/m68k/signalent.h32
-rw-r--r--sysdeps/linux-gnu/m68k/syscallent.h282
-rw-r--r--sysdeps/linux-gnu/m68k/trace.c89
-rw-r--r--sysdeps/linux-gnu/mipsel/Doxyfile275
-rw-r--r--sysdeps/linux-gnu/mipsel/Makefile22
-rw-r--r--sysdeps/linux-gnu/mipsel/arch.h9
-rw-r--r--sysdeps/linux-gnu/mipsel/mipsel.h11
-rw-r--r--sysdeps/linux-gnu/mipsel/plt.c72
-rw-r--r--sysdeps/linux-gnu/mipsel/ptrace.h1
-rw-r--r--sysdeps/linux-gnu/mipsel/regs.c76
-rw-r--r--sysdeps/linux-gnu/mipsel/signalent.h32
-rw-r--r--sysdeps/linux-gnu/mipsel/syscallent.h241
-rw-r--r--sysdeps/linux-gnu/mipsel/trace.c167
-rwxr-xr-xsysdeps/linux-gnu/mksignalent33
-rwxr-xr-xsysdeps/linux-gnu/mksyscallent45
-rw-r--r--sysdeps/linux-gnu/mksyscallent_s39038
-rw-r--r--sysdeps/linux-gnu/ppc/Makefile10
-rw-r--r--sysdeps/linux-gnu/ppc/arch.h24
-rw-r--r--sysdeps/linux-gnu/ppc/plt.c54
-rw-r--r--sysdeps/linux-gnu/ppc/ptrace.h1
-rw-r--r--sysdeps/linux-gnu/ppc/regs.c47
-rw-r--r--sysdeps/linux-gnu/ppc/signalent.h32
-rw-r--r--sysdeps/linux-gnu/ppc/syscallent.h272
-rw-r--r--sysdeps/linux-gnu/ppc/trace.c155
-rw-r--r--sysdeps/linux-gnu/proc.c36
-rw-r--r--sysdeps/linux-gnu/s390/Makefile13
-rw-r--r--sysdeps/linux-gnu/s390/arch.h18
-rw-r--r--sysdeps/linux-gnu/s390/plt.c12
-rw-r--r--sysdeps/linux-gnu/s390/ptrace.h1
-rw-r--r--sysdeps/linux-gnu/s390/regs.c75
-rw-r--r--sysdeps/linux-gnu/s390/signalent.h33
-rw-r--r--sysdeps/linux-gnu/s390/signalent1.h1
-rw-r--r--sysdeps/linux-gnu/s390/syscallent.h5
-rw-r--r--sysdeps/linux-gnu/s390/syscallent1.h1
-rw-r--r--sysdeps/linux-gnu/s390/syscalls31.h310
-rw-r--r--sysdeps/linux-gnu/s390/syscalls64.h310
-rw-r--r--sysdeps/linux-gnu/s390/trace.c198
-rw-r--r--sysdeps/linux-gnu/sparc/Makefile9
-rw-r--r--sysdeps/linux-gnu/sparc/arch.h8
-rw-r--r--sysdeps/linux-gnu/sparc/plt.c12
-rw-r--r--sysdeps/linux-gnu/sparc/ptrace.h21
-rw-r--r--sysdeps/linux-gnu/sparc/regs.c49
-rw-r--r--sysdeps/linux-gnu/sparc/signalent.h32
-rw-r--r--sysdeps/linux-gnu/sparc/syscallent.h284
-rw-r--r--sysdeps/linux-gnu/sparc/trace.c81
-rw-r--r--sysdeps/linux-gnu/trace.c193
-rw-r--r--sysdeps/linux-gnu/x86_64/Makefile9
-rw-r--r--sysdeps/linux-gnu/x86_64/arch.h12
-rw-r--r--sysdeps/linux-gnu/x86_64/ffcheck.c0
-rw-r--r--sysdeps/linux-gnu/x86_64/plt.c12
-rw-r--r--sysdeps/linux-gnu/x86_64/ptrace.h1
-rw-r--r--sysdeps/linux-gnu/x86_64/regs.c54
-rw-r--r--sysdeps/linux-gnu/x86_64/signalent.h32
-rw-r--r--sysdeps/linux-gnu/x86_64/signalent1.h1
-rw-r--r--sysdeps/linux-gnu/x86_64/syscallent.h256
-rw-r--r--sysdeps/linux-gnu/x86_64/syscallent1.h1
-rw-r--r--sysdeps/linux-gnu/x86_64/trace.c144
-rw-r--r--testsuite/Makefile71
-rw-r--r--testsuite/README244
-rw-r--r--testsuite/config/unix.exp1
-rw-r--r--testsuite/lib/compiler.c58
-rw-r--r--testsuite/lib/compiler.cc45
-rw-r--r--testsuite/lib/ltrace.exp279
-rw-r--r--testsuite/ltrace.main/Makefile33
-rw-r--r--testsuite/ltrace.main/main-internal-1.c8
-rw-r--r--testsuite/ltrace.main/main-internal.c19
-rw-r--r--testsuite/ltrace.main/main-internal.exp33
-rw-r--r--testsuite/ltrace.main/main-lib.c7
-rw-r--r--testsuite/ltrace.main/main.c21
-rw-r--r--testsuite/ltrace.main/main.exp39
-rw-r--r--testsuite/ltrace.main/parameters-lib.c117
-rw-r--r--testsuite/ltrace.main/parameters.c120
-rw-r--r--testsuite/ltrace.main/parameters.conf15
-rw-r--r--testsuite/ltrace.main/parameters.exp72
-rw-r--r--testsuite/ltrace.main/signals.c48
-rw-r--r--testsuite/ltrace.main/signals.exp39
-rw-r--r--testsuite/ltrace.main/system_calls.c68
-rw-r--r--testsuite/ltrace.main/system_calls.exp67
-rw-r--r--testsuite/ltrace.minor/Makefile36
-rw-r--r--testsuite/ltrace.minor/attach-process.c16
-rw-r--r--testsuite/ltrace.minor/attach-process.exp38
-rw-r--r--testsuite/ltrace.minor/count-record.c51
-rw-r--r--testsuite/ltrace.minor/count-record.exp77
-rw-r--r--testsuite/ltrace.minor/demangle-lib.cpp97
-rw-r--r--testsuite/ltrace.minor/demangle.cpp121
-rw-r--r--testsuite/ltrace.minor/demangle.exp63
-rw-r--r--testsuite/ltrace.minor/demangle.h36
-rw-r--r--testsuite/ltrace.minor/print-instruction-pointer.c11
-rw-r--r--testsuite/ltrace.minor/print-instruction-pointer.exp42
-rw-r--r--testsuite/ltrace.minor/time-record-T.exp84
-rw-r--r--testsuite/ltrace.minor/time-record-tt.exp107
-rw-r--r--testsuite/ltrace.minor/time-record-ttt.exp112
-rw-r--r--testsuite/ltrace.minor/time-record.c23
-rw-r--r--testsuite/ltrace.minor/trace-clone.c38
-rw-r--r--testsuite/ltrace.minor/trace-clone.exp44
-rw-r--r--testsuite/ltrace.minor/trace-exec.c8
-rw-r--r--testsuite/ltrace.minor/trace-exec.exp45
-rw-r--r--testsuite/ltrace.minor/trace-exec1.c6
-rw-r--r--testsuite/ltrace.minor/trace-fork.c33
-rw-r--r--testsuite/ltrace.minor/trace-fork.exp40
-rw-r--r--testsuite/ltrace.torture/Makefile33
-rw-r--r--testsuite/ltrace.torture/ia64-sigill.exp33
-rw-r--r--testsuite/ltrace.torture/ia64-sigill.s43
-rw-r--r--testsuite/ltrace.torture/signals.c44
-rw-r--r--testsuite/ltrace.torture/signals.exp37
-rwxr-xr-xtestsuite/run-my-tests.sh43
196 files changed, 19692 insertions, 0 deletions
diff --git a/BUGS b/BUGS
new file mode 100644
index 0000000..fd44ac0
--- /dev/null
+++ b/BUGS
@@ -0,0 +1,6 @@
+* Manual page is not accurate (config files...)
+* Doesn't do inter-library calls (BP is in the executable's PLT)
+* It lacks support for several Linux archs, and many operating systems
+* 2008-12-29: this line in config file does not work (2nd argument not used):
+ string setlocale(enum(LC_ALL=6), string);
+* 2009-04-07 doesn't work with threads (processes sharing memory)
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..3912109
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <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
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
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
index 0000000..1e8adcd
--- /dev/null
+++ b/Makefile.in
@@ -0,0 +1,74 @@
+#
+# ltrace's Makefile.in
+#
+
+#OS := $(shell uname -s)
+OS := @HOST_OS@
+
+TOPDIR = $(shell pwd)
+
+prefix = @prefix@
+sysconfdir = @sysconfdir@
+bindir = $(prefix)/bin
+mandir = @mandir@
+docdir = $(prefix)/share/doc/ltrace
+
+CC = @CC@
+CFLAGS = -Wall @CFLAGS@
+CPPFLAGS = -iquote $(TOPDIR) -iquote $(TOPDIR)/sysdeps/$(OS) -DSYSCONFDIR=\"$(sysconfdir)\" @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+
+INSTALL = @INSTALL@
+INSTALL_FILE = $(INSTALL) -p -m 644
+INSTALL_PROGRAM = $(INSTALL) -p -m 755
+INSTALL_SCRIPT = $(INSTALL) -p -m 755
+INSTALL_DIR = $(INSTALL) -p -d -m 755
+
+OBJ = libltrace.o options.o elf.o output.o read_config_file.o \
+ execute_program.o handle_event.o display_args.o \
+ breakpoints.o proc.o demangle.o dict.o debug.o summary.o
+
+VERSION = @PACKAGE_VERSION@
+
+all: ltrace
+
+ltrace: main.o libltrace.a
+ $(CC) $(LDFLAGS) $^ $(LIBS) -o $@
+
+libltrace.a: sysdeps/sysdep.o $(OBJ)
+ $(AR) rcv $@ $^
+
+sysdeps/sysdep.o: dummy
+ $(MAKE) -C sysdeps/$(OS)
+
+clean-deja:
+ $(RM) testrun.log testrun.sum
+ cd testsuite; make clean
+
+clean: clean-deja
+ $(MAKE) -C sysdeps/$(OS) clean
+ rm -f ltrace main.o libltrace.a $(OBJ)
+ rm -f *~ *.bak a.out core
+
+distclean: clean
+ rm -f config.h Makefile
+
+realclean: distclean
+
+install: ltrace
+ $(INSTALL_DIR) $(DESTDIR)$(bindir) $(DESTDIR)$(docdir) $(DESTDIR)$(mandir)/man1
+ $(INSTALL_DIR) $(DESTDIR)$(sysconfdir)
+ $(INSTALL_PROGRAM) ltrace $(DESTDIR)$(bindir)
+ $(INSTALL_FILE) etc/ltrace.conf $(DESTDIR)$(sysconfdir)
+ $(INSTALL_FILE) COPYING README TODO BUGS ChangeLog $(DESTDIR)$(docdir)
+ $(INSTALL_FILE) ltrace.1 $(DESTDIR)$(mandir)/man1
+
+check:
+ cd testsuite;cat /proc/version;uptime;free -m;$(MAKE) check
+
+dummy:
+
+.PHONY: all clean distclean dist install dummy
+
+.EXPORT_ALL_VARIABLES:
diff --git a/README b/README
new file mode 100644
index 0000000..ab1a2e5
--- /dev/null
+++ b/README
@@ -0,0 +1,92 @@
+ ltrace
+
+ A Dynamic Library Tracer
+
+ Copyright 1997-2009 Juan Cespedes <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
index 0000000..5063737
--- /dev/null
+++ b/TODO
@@ -0,0 +1,36 @@
+* BFD:
+ + New executable formats
+ + Read list of libraries needed
+ + Read list of undefined symbols in executables
+ + Read list of exported symbols in libraries
+ + Read debugging info from executables/libraries
+* Automatically update list of syscalls?
+* Improve documentation
+* Improve -e/-x options (regexp?)
+* Improve -l option
+* Improve C++ name demangling
+* Display different argument types
+* Update /etc/ltrace.conf
+* More architectures, cleaner way to port
+* More operating systems (solaris?)
+* Option -I (inter-library calls)
+* Modify ARGTYPE_STRING[0-5] types so that they don't stop displaying chars when '\0' is seen
+* Get rid of EVENT_ARCH_SYSCALL and EVENT_ARCH_SYSRET
+* Cleaner way to use breakpoints:
+ + BP is placed in the PLT
+ + When control hits there:
+ - write down return address
+ - change return address with another one (handled by ltrace)
+ - get arguments...
+ - change the process' PC to be in the correct place,
+ without removing breakpoint
+ + When control hits one of our return addresses:
+ - get return value...
+ - change PC to the right place
+* To be able to work with processes sharing memory, we must:
+ + ptrace() every single thread
+ + place breakpoints only in places where the process control can continue
+ without having to remove it
+* List source dependencies in Makefile
+* Create different ltrace processes to trace different children
+* After a clone(), syscalls may be seen as sysrets in s390 (see trace.c:syscall_p())
diff --git a/VERSION b/VERSION
new file mode 100644
index 0000000..be14282
--- /dev/null
+++ b/VERSION
@@ -0,0 +1 @@
+0.5.3
diff --git a/aclocal.m4 b/aclocal.m4
new file mode 100644
index 0000000..abe07e0
--- /dev/null
+++ b/aclocal.m4
@@ -0,0 +1,833 @@
+dnl aclocal.m4t generated automatically by aclocal 1.4-p6
+
+dnl Copyright (C) 1994, 1995-8, 1999, 2001 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl This program is distributed in the hope that it will be useful,
+dnl but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+dnl even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+dnl PARTICULAR PURPOSE.
+
+# lib-prefix.m4 serial 3 (gettext-0.13)
+dnl Copyright (C) 2001-2003 Free Software Foundation, Inc.
+dnl This file is free software, distributed under the terms of the GNU
+dnl General Public License. As a special exception to the GNU General
+dnl Public License, this file may be distributed as part of a program
+dnl that contains a configuration script generated by Autoconf, under
+dnl the same distribution terms as the rest of that program.
+
+dnl From Bruno Haible.
+
+dnl AC_LIB_ARG_WITH is synonymous to AC_ARG_WITH in autoconf-2.13, and
+dnl similar to AC_ARG_WITH in autoconf 2.52...2.57 except that is doesn't
+dnl require excessive bracketing.
+ifdef([AC_HELP_STRING],
+[AC_DEFUN([AC_LIB_ARG_WITH], [AC_ARG_WITH([$1],[[$2]],[$3],[$4])])],
+[AC_DEFUN([AC_][LIB_ARG_WITH], [AC_ARG_WITH([$1],[$2],[$3],[$4])])])
+
+dnl AC_LIB_PREFIX adds to the CPPFLAGS and LDFLAGS the flags that are needed
+dnl to access previously installed libraries. The basic assumption is that
+dnl a user will want packages to use other packages he previously installed
+dnl with the same --prefix option.
+dnl This macro is not needed if only AC_LIB_LINKFLAGS is used to locate
+dnl libraries, but is otherwise very convenient.
+AC_DEFUN([AC_LIB_PREFIX],
+[
+ AC_BEFORE([$0], [AC_LIB_LINKFLAGS])
+ AC_REQUIRE([AC_PROG_CC])
+ AC_REQUIRE([AC_CANONICAL_HOST])
+ AC_REQUIRE([AC_LIB_PREPARE_PREFIX])
+ dnl By default, look in $includedir and $libdir.
+ use_additional=yes
+ AC_LIB_WITH_FINAL_PREFIX([
+ eval additional_includedir=\"$includedir\"
+ eval additional_libdir=\"$libdir\"
+ ])
+ AC_LIB_ARG_WITH([lib-prefix],
+[ --with-lib-prefix[=DIR] search for libraries in DIR/include and DIR/lib
+ --without-lib-prefix don't search for libraries in includedir and libdir],
+[
+ if test "X$withval" = "Xno"; then
+ use_additional=no
+ else
+ if test "X$withval" = "X"; then
+ AC_LIB_WITH_FINAL_PREFIX([
+ eval additional_includedir=\"$includedir\"
+ eval additional_libdir=\"$libdir\"
+ ])
+ else
+ additional_includedir="$withval/include"
+ additional_libdir="$withval/lib"
+ fi
+ fi
+])
+ if test $use_additional = yes; then
+ dnl Potentially add $additional_includedir to $CPPFLAGS.
+ dnl But don't add it
+ dnl 1. if it's the standard /usr/include,
+ dnl 2. if it's already present in $CPPFLAGS,
+ dnl 3. if it's /usr/local/include and we are using GCC on Linux,
+ dnl 4. if it doesn't exist as a directory.
+ if test "X$additional_includedir" != "X/usr/include"; then
+ haveit=
+ for x in $CPPFLAGS; do
+ AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+ if test "X$x" = "X-I$additional_includedir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ if test "X$additional_includedir" = "X/usr/local/include"; then
+ if test -n "$GCC"; then
+ case $host_os in
+ linux*) haveit=yes;;
+ esac
+ fi
+ fi
+ if test -z "$haveit"; then
+ if test -d "$additional_includedir"; then
+ dnl Really add $additional_includedir to $CPPFLAGS.
+ CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }-I$additional_includedir"
+ fi
+ fi
+ fi
+ fi
+ dnl Potentially add $additional_libdir to $LDFLAGS.
+ dnl But don't add it
+ dnl 1. if it's the standard /usr/lib,
+ dnl 2. if it's already present in $LDFLAGS,
+ dnl 3. if it's /usr/local/lib and we are using GCC on Linux,
+ dnl 4. if it doesn't exist as a directory.
+ if test "X$additional_libdir" != "X/usr/lib"; then
+ haveit=
+ for x in $LDFLAGS; do
+ AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+ if test "X$x" = "X-L$additional_libdir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ if test "X$additional_libdir" = "X/usr/local/lib"; then
+ if test -n "$GCC"; then
+ case $host_os in
+ linux*) haveit=yes;;
+ esac
+ fi
+ fi
+ if test -z "$haveit"; then
+ if test -d "$additional_libdir"; then
+ dnl Really add $additional_libdir to $LDFLAGS.
+ LDFLAGS="${LDFLAGS}${LDFLAGS:+ }-L$additional_libdir"
+ fi
+ fi
+ fi
+ fi
+ fi
+])
+
+dnl AC_LIB_PREPARE_PREFIX creates variables acl_final_prefix,
+dnl acl_final_exec_prefix, containing the values to which $prefix and
+dnl $exec_prefix will expand at the end of the configure script.
+AC_DEFUN([AC_LIB_PREPARE_PREFIX],
+[
+ dnl Unfortunately, prefix and exec_prefix get only finally determined
+ dnl at the end of configure.
+ if test "X$prefix" = "XNONE"; then
+ acl_final_prefix="$ac_default_prefix"
+ else
+ acl_final_prefix="$prefix"
+ fi
+ if test "X$exec_prefix" = "XNONE"; then
+ acl_final_exec_prefix='${prefix}'
+ else
+ acl_final_exec_prefix="$exec_prefix"
+ fi
+ acl_save_prefix="$prefix"
+ prefix="$acl_final_prefix"
+ eval acl_final_exec_prefix=\"$acl_final_exec_prefix\"
+ prefix="$acl_save_prefix"
+])
+
+dnl AC_LIB_WITH_FINAL_PREFIX([statement]) evaluates statement, with the
+dnl variables prefix and exec_prefix bound to the values they will have
+dnl at the end of the configure script.
+AC_DEFUN([AC_LIB_WITH_FINAL_PREFIX],
+[
+ acl_save_prefix="$prefix"
+ prefix="$acl_final_prefix"
+ acl_save_exec_prefix="$exec_prefix"
+ exec_prefix="$acl_final_exec_prefix"
+ $1
+ exec_prefix="$acl_save_exec_prefix"
+ prefix="$acl_save_prefix"
+])
+
+# lib-link.m4 serial 4 (gettext-0.12)
+dnl Copyright (C) 2001-2003 Free Software Foundation, Inc.
+dnl This file is free software, distributed under the terms of the GNU
+dnl General Public License. As a special exception to the GNU General
+dnl Public License, this file may be distributed as part of a program
+dnl that contains a configuration script generated by Autoconf, under
+dnl the same distribution terms as the rest of that program.
+
+dnl From Bruno Haible.
+
+dnl AC_LIB_LINKFLAGS(name [, dependencies]) searches for libname and
+dnl the libraries corresponding to explicit and implicit dependencies.
+dnl Sets and AC_SUBSTs the LIB${NAME} and LTLIB${NAME} variables and
+dnl augments the CPPFLAGS variable.
+AC_DEFUN([AC_LIB_LINKFLAGS],
+[
+ AC_REQUIRE([AC_LIB_PREPARE_PREFIX])
+ AC_REQUIRE([AC_LIB_RPATH])
+ define([Name],[translit([$1],[./-], [___])])
+ define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-],
+ [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])])
+ AC_CACHE_CHECK([how to link with lib[]$1], [ac_cv_lib[]Name[]_libs], [
+ AC_LIB_LINKFLAGS_BODY([$1], [$2])
+ ac_cv_lib[]Name[]_libs="$LIB[]NAME"
+ ac_cv_lib[]Name[]_ltlibs="$LTLIB[]NAME"
+ ac_cv_lib[]Name[]_cppflags="$INC[]NAME"
+ ])
+ LIB[]NAME="$ac_cv_lib[]Name[]_libs"
+ LTLIB[]NAME="$ac_cv_lib[]Name[]_ltlibs"
+ INC[]NAME="$ac_cv_lib[]Name[]_cppflags"
+ AC_LIB_APPENDTOVAR([CPPFLAGS], [$INC]NAME)
+ AC_SUBST([LIB]NAME)
+ AC_SUBST([LTLIB]NAME)
+ dnl Also set HAVE_LIB[]NAME so that AC_LIB_HAVE_LINKFLAGS can reuse the
+ dnl results of this search when this library appears as a dependency.
+ HAVE_LIB[]NAME=yes
+ undefine([Name])
+ undefine([NAME])
+])
+
+dnl AC_LIB_HAVE_LINKFLAGS(name, dependencies, includes, testcode)
+dnl searches for libname and the libraries corresponding to explicit and
+dnl implicit dependencies, together with the specified include files and
+dnl the ability to compile and link the specified testcode. If found, it
+dnl sets and AC_SUBSTs HAVE_LIB${NAME}=yes and the LIB${NAME} and
+dnl LTLIB${NAME} variables and augments the CPPFLAGS variable, and
+dnl #defines HAVE_LIB${NAME} to 1. Otherwise, it sets and AC_SUBSTs
+dnl HAVE_LIB${NAME}=no and LIB${NAME} and LTLIB${NAME} to empty.
+AC_DEFUN([AC_LIB_HAVE_LINKFLAGS],
+[
+ AC_REQUIRE([AC_LIB_PREPARE_PREFIX])
+ AC_REQUIRE([AC_LIB_RPATH])
+ define([Name],[translit([$1],[./-], [___])])
+ define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-],
+ [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])])
+
+ dnl Search for lib[]Name and define LIB[]NAME, LTLIB[]NAME and INC[]NAME
+ dnl accordingly.
+ AC_LIB_LINKFLAGS_BODY([$1], [$2])
+
+ dnl Add $INC[]NAME to CPPFLAGS before performing the following checks,
+ dnl because if the user has installed lib[]Name and not disabled its use
+ dnl via --without-lib[]Name-prefix, he wants to use it.
+ ac_save_CPPFLAGS="$CPPFLAGS"
+ AC_LIB_APPENDTOVAR([CPPFLAGS], [$INC]NAME)
+
+ AC_CACHE_CHECK([for lib[]$1], [ac_cv_lib[]Name], [
+ ac_save_LIBS="$LIBS"
+ LIBS="$LIBS $LIB[]NAME"
+ AC_TRY_LINK([$3], [$4], [ac_cv_lib[]Name=yes], [ac_cv_lib[]Name=no])
+ LIBS="$ac_save_LIBS"
+ ])
+ if test "$ac_cv_lib[]Name" = yes; then
+ HAVE_LIB[]NAME=yes
+ AC_DEFINE([HAVE_LIB]NAME, 1, [Define if you have the $1 library.])
+ AC_MSG_CHECKING([how to link with lib[]$1])
+ AC_MSG_RESULT([$LIB[]NAME])
+ else
+ HAVE_LIB[]NAME=no
+ dnl If $LIB[]NAME didn't lead to a usable library, we don't need
+ dnl $INC[]NAME either.
+ CPPFLAGS="$ac_save_CPPFLAGS"
+ LIB[]NAME=
+ LTLIB[]NAME=
+ fi
+ AC_SUBST([HAVE_LIB]NAME)
+ AC_SUBST([LIB]NAME)
+ AC_SUBST([LTLIB]NAME)
+ undefine([Name])
+ undefine([NAME])
+])
+
+dnl Determine the platform dependent parameters needed to use rpath:
+dnl libext, shlibext, hardcode_libdir_flag_spec, hardcode_libdir_separator,
+dnl hardcode_direct, hardcode_minus_L.
+AC_DEFUN([AC_LIB_RPATH],
+[
+ AC_REQUIRE([AC_PROG_CC]) dnl we use $CC, $GCC, $LDFLAGS
+ AC_REQUIRE([AC_LIB_PROG_LD]) dnl we use $LD, $with_gnu_ld
+ AC_REQUIRE([AC_CANONICAL_HOST]) dnl we use $host
+ AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT]) dnl we use $ac_aux_dir
+ AC_CACHE_CHECK([for shared library run path origin], acl_cv_rpath, [
+ CC="$CC" GCC="$GCC" LDFLAGS="$LDFLAGS" LD="$LD" with_gnu_ld="$with_gnu_ld" \
+ ${CONFIG_SHELL-/bin/sh} "$ac_aux_dir/config.rpath" "$host" > conftest.sh
+ . ./conftest.sh
+ rm -f ./conftest.sh
+ acl_cv_rpath=done
+ ])
+ wl="$acl_cv_wl"
+ libext="$acl_cv_libext"
+ shlibext="$acl_cv_shlibext"
+ hardcode_libdir_flag_spec="$acl_cv_hardcode_libdir_flag_spec"
+ hardcode_libdir_separator="$acl_cv_hardcode_libdir_separator"
+ hardcode_direct="$acl_cv_hardcode_direct"
+ hardcode_minus_L="$acl_cv_hardcode_minus_L"
+ dnl Determine whether the user wants rpath handling at all.
+ AC_ARG_ENABLE(rpath,
+ [ --disable-rpath do not hardcode runtime library paths],
+ :, enable_rpath=yes)
+])
+
+dnl AC_LIB_LINKFLAGS_BODY(name [, dependencies]) searches for libname and
+dnl the libraries corresponding to explicit and implicit dependencies.
+dnl Sets the LIB${NAME}, LTLIB${NAME} and INC${NAME} variables.
+AC_DEFUN([AC_LIB_LINKFLAGS_BODY],
+[
+ define([NAME],[translit([$1],[abcdefghijklmnopqrstuvwxyz./-],
+ [ABCDEFGHIJKLMNOPQRSTUVWXYZ___])])
+ dnl By default, look in $includedir and $libdir.
+ use_additional=yes
+ AC_LIB_WITH_FINAL_PREFIX([
+ eval additional_includedir=\"$includedir\"
+ eval additional_libdir=\"$libdir\"
+ ])
+ AC_LIB_ARG_WITH([lib$1-prefix],
+[ --with-lib$1-prefix[=DIR] search for lib$1 in DIR/include and DIR/lib
+ --without-lib$1-prefix don't search for lib$1 in includedir and libdir],
+[
+ if test "X$withval" = "Xno"; then
+ use_additional=no
+ else
+ if test "X$withval" = "X"; then
+ AC_LIB_WITH_FINAL_PREFIX([
+ eval additional_includedir=\"$includedir\"
+ eval additional_libdir=\"$libdir\"
+ ])
+ else
+ additional_includedir="$withval/include"
+ additional_libdir="$withval/lib"
+ fi
+ fi
+])
+ dnl Search the library and its dependencies in $additional_libdir and
+ dnl $LDFLAGS. Using breadth-first-seach.
+ LIB[]NAME=
+ LTLIB[]NAME=
+ INC[]NAME=
+ rpathdirs=
+ ltrpathdirs=
+ names_already_handled=
+ names_next_round='$1 $2'
+ while test -n "$names_next_round"; do
+ names_this_round="$names_next_round"
+ names_next_round=
+ for name in $names_this_round; do
+ already_handled=
+ for n in $names_already_handled; do
+ if test "$n" = "$name"; then
+ already_handled=yes
+ break
+ fi
+ done
+ if test -z "$already_handled"; then
+ names_already_handled="$names_already_handled $name"
+ dnl See if it was already located by an earlier AC_LIB_LINKFLAGS
+ dnl or AC_LIB_HAVE_LINKFLAGS call.
+ uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./-|ABCDEFGHIJKLMNOPQRSTUVWXYZ___|'`
+ eval value=\"\$HAVE_LIB$uppername\"
+ if test -n "$value"; then
+ if test "$value" = yes; then
+ eval value=\"\$LIB$uppername\"
+ test -z "$value" || LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$value"
+ eval value=\"\$LTLIB$uppername\"
+ test -z "$value" || LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$value"
+ else
+ dnl An earlier call to AC_LIB_HAVE_LINKFLAGS has determined
+ dnl that this library doesn't exist. So just drop it.
+ :
+ fi
+ else
+ dnl Search the library lib$name in $additional_libdir and $LDFLAGS
+ dnl and the already constructed $LIBNAME/$LTLIBNAME.
+ found_dir=
+ found_la=
+ found_so=
+ found_a=
+ if test $use_additional = yes; then
+ if test -n "$shlibext" && test -f "$additional_libdir/lib$name.$shlibext"; then
+ found_dir="$additional_libdir"
+ found_so="$additional_libdir/lib$name.$shlibext"
+ if test -f "$additional_libdir/lib$name.la"; then
+ found_la="$additional_libdir/lib$name.la"
+ fi
+ else
+ if test -f "$additional_libdir/lib$name.$libext"; then
+ found_dir="$additional_libdir"
+ found_a="$additional_libdir/lib$name.$libext"
+ if test -f "$additional_libdir/lib$name.la"; then
+ found_la="$additional_libdir/lib$name.la"
+ fi
+ fi
+ fi
+ fi
+ if test "X$found_dir" = "X"; then
+ for x in $LDFLAGS $LTLIB[]NAME; do
+ AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+ case "$x" in
+ -L*)
+ dir=`echo "X$x" | sed -e 's/^X-L//'`
+ if test -n "$shlibext" && test -f "$dir/lib$name.$shlibext"; then
+ found_dir="$dir"
+ found_so="$dir/lib$name.$shlibext"
+ if test -f "$dir/lib$name.la"; then
+ found_la="$dir/lib$name.la"
+ fi
+ else
+ if test -f "$dir/lib$name.$libext"; then
+ found_dir="$dir"
+ found_a="$dir/lib$name.$libext"
+ if test -f "$dir/lib$name.la"; then
+ found_la="$dir/lib$name.la"
+ fi
+ fi
+ fi
+ ;;
+ esac
+ if test "X$found_dir" != "X"; then
+ break
+ fi
+ done
+ fi
+ if test "X$found_dir" != "X"; then
+ dnl Found the library.
+ LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$found_dir -l$name"
+ if test "X$found_so" != "X"; then
+ dnl Linking with a shared library. We attempt to hardcode its
+ dnl directory into the executable's runpath, unless it's the
+ dnl standard /usr/lib.
+ if test "$enable_rpath" = no || test "X$found_dir" = "X/usr/lib"; then
+ dnl No hardcoding is needed.
+ LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so"
+ else
+ dnl Use an explicit option to hardcode DIR into the resulting
+ dnl binary.
+ dnl Potentially add DIR to ltrpathdirs.
+ dnl The ltrpathdirs will be appended to $LTLIBNAME at the end.
+ haveit=
+ for x in $ltrpathdirs; do
+ if test "X$x" = "X$found_dir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ ltrpathdirs="$ltrpathdirs $found_dir"
+ fi
+ dnl The hardcoding into $LIBNAME is system dependent.
+ if test "$hardcode_direct" = yes; then
+ dnl Using DIR/libNAME.so during linking hardcodes DIR into the
+ dnl resulting binary.
+ LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so"
+ else
+ if test -n "$hardcode_libdir_flag_spec" && test "$hardcode_minus_L" = no; then
+ dnl Use an explicit option to hardcode DIR into the resulting
+ dnl binary.
+ LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so"
+ dnl Potentially add DIR to rpathdirs.
+ dnl The rpathdirs will be appended to $LIBNAME at the end.
+ haveit=
+ for x in $rpathdirs; do
+ if test "X$x" = "X$found_dir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ rpathdirs="$rpathdirs $found_dir"
+ fi
+ else
+ dnl Rely on "-L$found_dir".
+ dnl But don't add it if it's already contained in the LDFLAGS
+ dnl or the already constructed $LIBNAME
+ haveit=
+ for x in $LDFLAGS $LIB[]NAME; do
+ AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+ if test "X$x" = "X-L$found_dir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir"
+ fi
+ if test "$hardcode_minus_L" != no; then
+ dnl FIXME: Not sure whether we should use
+ dnl "-L$found_dir -l$name" or "-L$found_dir $found_so"
+ dnl here.
+ LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_so"
+ else
+ dnl We cannot use $hardcode_runpath_var and LD_RUN_PATH
+ dnl here, because this doesn't fit in flags passed to the
+ dnl compiler. So give up. No hardcoding. This affects only
+ dnl very old systems.
+ dnl FIXME: Not sure whether we should use
+ dnl "-L$found_dir -l$name" or "-L$found_dir $found_so"
+ dnl here.
+ LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name"
+ fi
+ fi
+ fi
+ fi
+ else
+ if test "X$found_a" != "X"; then
+ dnl Linking with a static library.
+ LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$found_a"
+ else
+ dnl We shouldn't come here, but anyway it's good to have a
+ dnl fallback.
+ LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$found_dir -l$name"
+ fi
+ fi
+ dnl Assume the include files are nearby.
+ additional_includedir=
+ case "$found_dir" in
+ */lib | */lib/)
+ basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e 's,/lib/*$,,'`
+ additional_includedir="$basedir/include"
+ ;;
+ esac
+ if test "X$additional_includedir" != "X"; then
+ dnl Potentially add $additional_includedir to $INCNAME.
+ dnl But don't add it
+ dnl 1. if it's the standard /usr/include,
+ dnl 2. if it's /usr/local/include and we are using GCC on Linux,
+ dnl 3. if it's already present in $CPPFLAGS or the already
+ dnl constructed $INCNAME,
+ dnl 4. if it doesn't exist as a directory.
+ if test "X$additional_includedir" != "X/usr/include"; then
+ haveit=
+ if test "X$additional_includedir" = "X/usr/local/include"; then
+ if test -n "$GCC"; then
+ case $host_os in
+ linux*) haveit=yes;;
+ esac
+ fi
+ fi
+ if test -z "$haveit"; then
+ for x in $CPPFLAGS $INC[]NAME; do
+ AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+ if test "X$x" = "X-I$additional_includedir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ if test -d "$additional_includedir"; then
+ dnl Really add $additional_includedir to $INCNAME.
+ INC[]NAME="${INC[]NAME}${INC[]NAME:+ }-I$additional_includedir"
+ fi
+ fi
+ fi
+ fi
+ fi
+ dnl Look for dependencies.
+ if test -n "$found_la"; then
+ dnl Read the .la file. It defines the variables
+ dnl dlname, library_names, old_library, dependency_libs, current,
+ dnl age, revision, installed, dlopen, dlpreopen, libdir.
+ save_libdir="$libdir"
+ case "$found_la" in
+ */* | *\\*) . "$found_la" ;;
+ *) . "./$found_la" ;;
+ esac
+ libdir="$save_libdir"
+ dnl We use only dependency_libs.
+ for dep in $dependency_libs; do
+ case "$dep" in
+ -L*)
+ additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'`
+ dnl Potentially add $additional_libdir to $LIBNAME and $LTLIBNAME.
+ dnl But don't add it
+ dnl 1. if it's the standard /usr/lib,
+ dnl 2. if it's /usr/local/lib and we are using GCC on Linux,
+ dnl 3. if it's already present in $LDFLAGS or the already
+ dnl constructed $LIBNAME,
+ dnl 4. if it doesn't exist as a directory.
+ if test "X$additional_libdir" != "X/usr/lib"; then
+ haveit=
+ if test "X$additional_libdir" = "X/usr/local/lib"; then
+ if test -n "$GCC"; then
+ case $host_os in
+ linux*) haveit=yes;;
+ esac
+ fi
+ fi
+ if test -z "$haveit"; then
+ haveit=
+ for x in $LDFLAGS $LIB[]NAME; do
+ AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+ if test "X$x" = "X-L$additional_libdir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ if test -d "$additional_libdir"; then
+ dnl Really add $additional_libdir to $LIBNAME.
+ LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-L$additional_libdir"
+ fi
+ fi
+ haveit=
+ for x in $LDFLAGS $LTLIB[]NAME; do
+ AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+ if test "X$x" = "X-L$additional_libdir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ if test -d "$additional_libdir"; then
+ dnl Really add $additional_libdir to $LTLIBNAME.
+ LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-L$additional_libdir"
+ fi
+ fi
+ fi
+ fi
+ ;;
+ -R*)
+ dir=`echo "X$dep" | sed -e 's/^X-R//'`
+ if test "$enable_rpath" != no; then
+ dnl Potentially add DIR to rpathdirs.
+ dnl The rpathdirs will be appended to $LIBNAME at the end.
+ haveit=
+ for x in $rpathdirs; do
+ if test "X$x" = "X$dir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ rpathdirs="$rpathdirs $dir"
+ fi
+ dnl Potentially add DIR to ltrpathdirs.
+ dnl The ltrpathdirs will be appended to $LTLIBNAME at the end.
+ haveit=
+ for x in $ltrpathdirs; do
+ if test "X$x" = "X$dir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ ltrpathdirs="$ltrpathdirs $dir"
+ fi
+ fi
+ ;;
+ -l*)
+ dnl Handle this in the next round.
+ names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'`
+ ;;
+ *.la)
+ dnl Handle this in the next round. Throw away the .la's
+ dnl directory; it is already contained in a preceding -L
+ dnl option.
+ names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'`
+ ;;
+ *)
+ dnl Most likely an immediate library name.
+ LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$dep"
+ LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }$dep"
+ ;;
+ esac
+ done
+ fi
+ else
+ dnl Didn't find the library; assume it is in the system directories
+ dnl known to the linker and runtime loader. (All the system
+ dnl directories known to the linker should also be known to the
+ dnl runtime loader, otherwise the system is severely misconfigured.)
+ LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }-l$name"
+ LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-l$name"
+ fi
+ fi
+ fi
+ done
+ done
+ if test "X$rpathdirs" != "X"; then
+ if test -n "$hardcode_libdir_separator"; then
+ dnl Weird platform: only the last -rpath option counts, the user must
+ dnl pass all path elements in one option. We can arrange that for a
+ dnl single library, but not when more than one $LIBNAMEs are used.
+ alldirs=
+ for found_dir in $rpathdirs; do
+ alldirs="${alldirs}${alldirs:+$hardcode_libdir_separator}$found_dir"
+ done
+ dnl Note: hardcode_libdir_flag_spec uses $libdir and $wl.
+ acl_save_libdir="$libdir"
+ libdir="$alldirs"
+ eval flag=\"$hardcode_libdir_flag_spec\"
+ libdir="$acl_save_libdir"
+ LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag"
+ else
+ dnl The -rpath options are cumulative.
+ for found_dir in $rpathdirs; do
+ acl_save_libdir="$libdir"
+ libdir="$found_dir"
+ eval flag=\"$hardcode_libdir_flag_spec\"
+ libdir="$acl_save_libdir"
+ LIB[]NAME="${LIB[]NAME}${LIB[]NAME:+ }$flag"
+ done
+ fi
+ fi
+ if test "X$ltrpathdirs" != "X"; then
+ dnl When using libtool, the option that works for both libraries and
+ dnl executables is -R. The -R options are cumulative.
+ for found_dir in $ltrpathdirs; do
+ LTLIB[]NAME="${LTLIB[]NAME}${LTLIB[]NAME:+ }-R$found_dir"
+ done
+ fi
+])
+
+dnl AC_LIB_APPENDTOVAR(VAR, CONTENTS) appends the elements of CONTENTS to VAR,
+dnl unless already present in VAR.
+dnl Works only for CPPFLAGS, not for LIB* variables because that sometimes
+dnl contains two or three consecutive elements that belong together.
+AC_DEFUN([AC_LIB_APPENDTOVAR],
+[
+ for element in [$2]; do
+ haveit=
+ for x in $[$1]; do
+ AC_LIB_WITH_FINAL_PREFIX([eval x=\"$x\"])
+ if test "X$x" = "X$element"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ [$1]="${[$1]}${[$1]:+ }$element"
+ fi
+ done
+])
+
+# lib-ld.m4 serial 3 (gettext-0.13)
+dnl Copyright (C) 1996-2003 Free Software Foundation, Inc.
+dnl This file is free software, distributed under the terms of the GNU
+dnl General Public License. As a special exception to the GNU General
+dnl Public License, this file may be distributed as part of a program
+dnl that contains a configuration script generated by Autoconf, under
+dnl the same distribution terms as the rest of that program.
+
+dnl Subroutines of libtool.m4,
+dnl with replacements s/AC_/AC_LIB/ and s/lt_cv/acl_cv/ to avoid collision
+dnl with libtool.m4.
+
+dnl From libtool-1.4. Sets the variable with_gnu_ld to yes or no.
+AC_DEFUN([AC_LIB_PROG_LD_GNU],
+[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], acl_cv_prog_gnu_ld,
+[# I'd rather use --version here, but apparently some GNU ld's only accept -v.
+case `$LD -v 2>&1 </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
index 0000000..ba3b060
--- /dev/null
+++ b/breakpoints.c
@@ -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
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
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
index 0000000..f97cb8f
--- /dev/null
+++ b/debian/changelog
@@ -0,0 +1,652 @@
+ltrace (0.5.3-1) unstable; urgency=low
+
+ * New upstream release
+ * Make it work again in sparc with new kernel headers (closes: Bug#532195)
+
+ -- Juan Cespedes <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
index 0000000..7ed6ff8
--- /dev/null
+++ b/debian/compat
@@ -0,0 +1 @@
+5
diff --git a/debian/control.in b/debian/control.in
new file mode 100644
index 0000000..aff5316
--- /dev/null
+++ b/debian/control.in
@@ -0,0 +1,23 @@
+Source: ltrace
+Section: utils
+Priority: optional
+Maintainer: Juan Cespedes <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
index 0000000..facd682
--- /dev/null
+++ b/debian/copyright
@@ -0,0 +1,39 @@
+This is the Debian GNU/Linux's prepackaged version of the
+Dynamic Library Tracer ``ltrace''.
+
+It was downloaded from http://www.ltrace.org/
+
+
+Copyrights
+----------
+Copyright (C) 1997-2009 Juan Cespedes <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
index 0000000..4105eb7
--- /dev/null
+++ b/debian/rules
@@ -0,0 +1,7 @@
+#!/usr/bin/make -f
+
+include /usr/share/cdbs/1/rules/debhelper.mk
+include /usr/share/cdbs/1/class/autotools.mk
+
+install/ltrace::
+ rm -f debian/ltrace/usr/share/doc/ltrace/*
diff --git a/debug.c b/debug.c
new file mode 100644
index 0000000..1be873b
--- /dev/null
+++ b/debug.c
@@ -0,0 +1,112 @@
+#include <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
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
index 0000000..b694099
--- /dev/null
+++ b/defs.h
@@ -0,0 +1,18 @@
+
+#ifndef DEFAULT_ALIGN
+#define DEFAULT_ALIGN 50 /* default alignment column for results */
+#endif /* (-a switch) */
+
+#ifndef MAX_ARGS
+#define MAX_ARGS 32 /* maximum number of args for a function */
+#endif
+
+#ifndef DEFAULT_STRLEN
+#define DEFAULT_STRLEN 32 /* default maximum # of bytes printed in */
+#endif /* strings (-s switch) */
+
+#ifndef DEFAULT_ARRAYLEN
+#define DEFAULT_ARRAYLEN 4 /* default maximum # array elements */
+#endif /* (-A switch) */
+
+#define MAX_LIBRARIES 30
diff --git a/demangle.c b/demangle.c
new file mode 100644
index 0000000..5825e28
--- /dev/null
+++ b/demangle.c
@@ -0,0 +1,44 @@
+#include "config.h"
+
+#include <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
index 0000000..beac791
--- /dev/null
+++ b/demangle.h
@@ -0,0 +1,12 @@
+#include "config.h"
+
+extern char *cplus_demangle(const char *mangled, int options);
+
+const char *my_demangle(const char *function_name);
+
+/* Options passed to cplus_demangle (in 2nd parameter). */
+
+#define DMGL_NO_OPTS 0 /* For readability... */
+#define DMGL_PARAMS (1 << 0) /* Include function args */
+#define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */
+#define DMGL_JAVA (1 << 2) /* Demangle as Java rather than C++. */
diff --git a/dict.c b/dict.c
new file mode 100644
index 0000000..486a461
--- /dev/null
+++ b/dict.c
@@ -0,0 +1,215 @@
+#include <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
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
index 0000000..993a808
--- /dev/null
+++ b/display_args.c
@@ -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
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
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
index 0000000..ed4fc5a
--- /dev/null
+++ b/etc/ltrace.conf
@@ -0,0 +1,604 @@
+; ltrace.conf
+;
+; ~/.ltrace.conf will also be read, if it exists. The -F option may be
+; used to suppress the automatic inclusion of both this file and
+; ~/.ltrace.conf, and load a different config file or config files
+; instead.
+
+; Argument types:
+; + == May vary (ie, is a returned value) (prefix)
+; void
+; int
+; uint == (unsigned int)
+; long
+; ulong == (unsigned long)
+; octal == (unsigned) [written in octal]
+; char
+; short == (short)
+; ushort == (unsigned short)
+; addr == (void *) [unsigned, written in hexa]
+; file == (FILE *) [TODO]
+; format == ((const char *), ...) [printf() like] [TODO]
+; string == (char *)
+; string[argN] == (char *) [N>0] [show only up to (arg N) bytes]
+; string[eltN] == (char *) [N>0] [show only up to (elt N) bytes]
+; string[retval] == (char *) [show only up to (return val) bytes]
+; string[arg0] == (char *) [same as string[retval]]
+; string[N] == (char *) [N>0] [show only up to N bytes]
+; type* == (type *) [pointer to any other type]
+; enum (key=value,key=value,...) [enumeration, see below]
+; array(type,argN)
+; == (type[SIZE]) [array of (arg N) elements]
+; array(type,eltN)
+; == (type[SIZE]) [array of (struct element N) elements]
+; array(type,N) == (type[N]) [array of N elements]
+; struct(type,type,...)
+; == (struct {...}) [struct of several types]
+;
+; Backwards-compatibility:
+; string0 == (char *) [same as string[retval]]
+; stringN == (char *) [N>0] [same as string[argN]]
+
+
+
+; Typedefs
+;
+; To make it easier to specify argument lists, you can use 'typedef'
+; directives to avoid repeating complex parameter descriptors:
+;
+; typedef color = enum(RED=1,BLUE=2,GREEN=3)
+; void draw_line(color,int,int,int,int)
+; void draw_square(color,int,int,int,int)
+;
+; Enumerations
+;
+; The syntax is a parenthesized list of key=value assignments, like so:
+; enum (F_DUPFD=0,F_GETFD=1,F_SETFD=2)
+; an example usage might look like
+; int fcntl(int,enum (F_DUPFD=0,F_GETFD=1,F_SETFD=2))
+;
+; Arrays
+;
+; NOTE: Uses of array(...) alone are very rare. You almost always
+; want array(...)*. The exceptions are when you have a fixed-size
+; array.
+;
+; Structs
+;
+; NOTE: Uses of struct(...) alone are very rare. You almost always
+; want struct(...)* (a pointer to a struct) anyway. Most compilers
+; pass structs as pointers anyway, and those that don't are not yet
+; supported. The one time when you want to use a non-pointer
+; struct(...) type are when you have an array of structs, or a struct
+; containing another struct.
+;
+; For example, if you have
+; struct s1 {
+; int y_size;
+; int * y;
+; int z[3];
+; struct { char c; } a;
+; struct { char c; } * b;
+; }
+; and a function
+; void f(struct s1*)
+; then the corresponding ltrace spec is
+; void f(struct(int,array(int,elt0),array(int,3),struct(char),struct(char)*)*)
+; which, formatted similarly to the C declaration, looks like
+; void f(struct(
+; int,
+; array(int,elt0),
+; array(int,3),
+; struct(char),
+; struct(char)*
+; )*
+; )
+
+
+; arpa/inet.h
+int inet_aton(string,addr);
+string inet_ntoa(addr); ; It isn't an ADDR but an hexa number...
+addr inet_addr(string);
+
+; bfd.h
+void bfd_init(void);
+int bfd_set_default_target(string);
+addr bfd_scan_vma(string, addr, int);
+addr bfd_openr(string,string);
+int bfd_check_format(addr,int);
+
+; ctype.h
+char tolower(char);
+char toupper(char);
+addr __ctype_b_loc(void);
+addr __ctype_tolower_loc(void);
+addr __ctype_toupper_loc(void);
+
+; curses.h
+int waddch(addr, char);
+int mvprintw(int, int, format);
+int wmove(addr, int, int);
+int waddnstr(addr, string, int);
+string tgoto(string, int, int);
+
+; dirent.h
+int closedir(addr);
+addr opendir(string);
+addr readdir(addr);
+addr readdir64(addr);
+
+; dlfcn.h
+addr dlopen(string, int);
+string dlerror(void);
+addr dlsym(addr, string);
+int dlclose(addr);
+
+; errno.h
+addr __errno_location(void);
+
+; fcntl.h
+int open(string,int,octal); ; WARNING: 3rd argument may not be there
+int open64(string,int,octal); ; WARNING: 3rd argument may not be there
+
+; fnmatch.h
+int fnmatch(string, string, int);
+
+; getopt.h
+int getopt_long(int,addr,string,addr,int*);
+int getopt_long_only(int,addr,string,addr,addr);
+
+; grp.h
+void endgrent(void);
+addr getgrnam(string);
+void setgrent(void);
+addr getgrent(void);
+
+; libintl.h
+string __dcgettext(string,string,int);
+string bindtextdomain(string, string);
+string textdomain(string);
+
+; libio.h
+char _IO_getc(file);
+int _IO_putc(char,file);
+
+; locale.h
+string setlocale(int, string);
+
+; mcheck.h
+void mtrace(void);
+void muntrace(void);
+
+; mntent.h
+int endmntent(file);
+file setmntent(string,string);
+addr getmntent(addr);
+
+; mqueue.h
+int mq_open(string, int, octal, addr); ; WARNING: 3rd and 4th arguments may not be there
+int mq_close(int);
+int mq_unlink(string);
+int mq_getattr(int, addr);
+int mq_setattr(int, addr, addr);
+int mq_notify(int, addr);
+int mq_send(int, string3, ulong, uint);
+int mq_timedsend(int, string3, ulong, uint, addr);
+long mq_receive(int, +string0, ulong, addr);
+long mq_timedreceive(int, +string0, ulong, addr, addr);
+
+; netdb.h
+void endhostent(void);
+void endnetent(void);
+void endnetgrent(void);
+void endprotoent(void);
+void endservent(void);
+void freeaddrinfo(addr);
+string gai_strerror(int);
+int getaddrinfo(string, string, addr, addr);
+addr gethostbyaddr(string, uint, int);
+addr gethostbyname(string);
+addr gethostent(void);
+int getnameinfo(addr, uint, string, uint, string, uint, uint);
+addr getnetbyaddr(uint, int);
+addr getnetbyname(string);
+addr getnetent(void);
+int getnetgrent(addr, addr, addr);
+addr getprotobyname(string);
+addr getprotobynumber(int);
+addr getprotoent(void);
+addr getservbyname(string, string);
+addr getservbyport(int, string);
+addr getservent(void);
+void herror(string);
+string hstrerror(int);
+int rcmd(addr, ushort, string, string, string, addr);
+int rcmd_af(addr, ushort, string, string, string, addr, int);
+int rexec(addr, int, string, string, string, addr);
+int rexec_af(addr, int, string, string, string, addr, int);
+int rresvport (addr);
+int rresvport_af (addr, int);
+int ruserok(string, int, string, string);
+int ruserok_af(string, int, string, string, int);
+void sethostent(int);
+void setnetent(int);
+int setnetgrent(string);
+void setprotoent(int);
+void setservent(int);
+
+; netinet/in.h
+uint ntohs(uint);
+
+; pcap.h
+string pcap_lookupdev(addr);
+addr pcap_open_live(string, int, int, int, addr);
+int pcap_snapshot(addr);
+int pcap_lookupnet(string, addr, addr, addr);
+int pcap_compile(addr, addr, string, int, addr);
+
+; pwd.h
+string getpass(string);
+void endpwent(void);
+addr getpwnam(string);
+void setpwent(void);
+
+; readline/readline.h
+string readline(string);
+
+; signal.h
+int kill(int,int);
+addr signal(int,addr);
+int sigemptyset(addr);
+int sigfillset(addr);
+int sigaddset(addr, int);
+int sigdelset(addr, int);
+int sigismember(addr, int);
+int sigaction(int, addr, addr);
+int sigprocmask(int, addr, addr);
+int sigpending(addr);
+int sigsuspend(addr);
+
+; stdio.h
+int fclose(file);
+int feof(file);
+int ferror(file);
+int fflush(file);
+char fgetc(file);
+addr fgets(+string, int, file);
+int fileno(file);
+file fopen(string,string);
+file fopen64(string,string);
+int fprintf(file,format);
+int fputc(char,file);
+int fputs(string,file);
+ulong fread(addr,ulong,ulong,file);
+ulong fread_unlocked(addr,ulong,ulong,file);
+ulong fwrite(string,ulong,ulong,file);
+ulong fwrite_unlocked(string,ulong,ulong,file);
+int pclose(addr);
+void perror(string);
+addr popen(string, string);
+int printf(format);
+int puts(string);
+int remove(string);
+int snprintf(+string2,ulong,format);
+int sprintf(+string,format);
+string tempnam(string,string);
+int vfprintf(file,string,addr);
+int vsnprintf(+string2,ulong,string,addr);
+int setvbuf(file,addr,int,ulong);
+void setbuf(file,addr);
+void setbuffer(file,addr,ulong);
+void setlinebuf(file);
+int rename(string,string);
+
+; stdlib.h
+long __strtol_internal(string,addr,int);
+ulong __strtoul_internal(string,addr,int);
+int atexit(addr);
+addr bsearch(string, addr, ulong, ulong, addr);
+addr calloc(ulong, ulong);
+void exit(int);
+void free(addr);
+string getenv(string);
+int putenv(string);
+int setenv(string,string,int);
+void unsetenv(string);
+addr malloc(ulong);
+void qsort(addr,ulong,ulong,addr);
+int random(void);
+addr realloc(addr,ulong);
+void srandom(uint);
+int system(string);
+
+; string.h
+void bcopy(addr,addr,ulong);
+void bzero(addr,ulong);
+string basename(string);
+string index(string,char);
+addr memchr(string,char,ulong);
+addr memcpy(addr,string3,ulong);
+addr memset(addr,char,long);
+string rindex(string,char);
+addr stpcpy(addr,string);
+int strcasecmp(string, string);
+string strcat(string, string);
+string strchr(string,char);
+int strcoll(string,string);
+ulong strlen(string);
+int strcmp(string,string);
+addr strcpy(addr,string);
+addr strdup(string);
+string strerror(int);
+int strncmp(string,string,ulong);
+addr strncpy(addr,string3,ulong);
+string strrchr(string,char);
+string strsep(addr,string);
+ulong strspn(string,string);
+ulong strcspn(string,string);
+string strstr(string,string);
+string strtok(string, string);
+
+; sys/ioctl.h
+int ioctl(int, int, addr);
+
+; sys/socket.h
+int socket(int,int,int);
+
+; sys/stat.h
+int __fxstat(int,int,addr);
+int __xstat(int,string,addr);
+int __lxstat(int,string,addr);
+int __fxstat64(int,int,addr);
+int __xstat64(int,string,addr);
+int __lxstat64(int,string,addr);
+int chmod(string,octal);
+int fchmod(int,octal);
+int mkfifo(string,octal);
+octal umask(octal);
+
+; sys/utsname.h
+int uname(addr);
+
+; sys/vfs.h
+int statfs(string,addr);
+
+; syslog.h
+void closelog(void);
+void openlog(string,int,int);
+void syslog(int,format);
+
+; term.h
+int tputs(string, int, addr);
+
+; termios.h
+int tcgetattr(int,addr);
+int tcsetattr(int,int,addr);
+
+; time.h
+string ctime(addr);
+int gettimeofday(addr, addr);
+addr gmtime(addr);
+addr localtime(addr);
+ulong strftime(+string2,ulong,string,addr);
+long time(addr);
+
+; unistd.h
+void _exit(int);
+int access(string, int);
+uint alarm(uint);
+int chdir(string);
+int chown(string,int,int);
+int close(int);
+string crypt(string,string);
+int dup2(int,int);
+int execlp(string,string,addr,addr,addr);
+int execv(string,addr);
+int fchdir(int);
+int fork(void);
+int ftruncate(int,ulong);
+string2 getcwd(addr,ulong);
+int getdomainname(+string2,ulong);
+int geteuid(void);
+int getegid(void);
+int getgid(void);
+int gethostname(+string2,ulong);
+string getlogin(void);
+int getopt(int,addr,string);
+int getpid(void);
+int getppid(void);
+int getuid(void);
+int getpgrp(void);
+int setpgrp(void);
+int getpgid(int);
+int isatty(int);
+int link(string,string);
+int mkdir(string,octal);
+long read(int, +string[retval], ulong);
+int rmdir(string);
+int seteuid(uint);
+int setgid(int);
+int sethostname(+string2,ulong);
+int setpgid(int,int);
+int setreuid(uint, uint);
+int setuid(int);
+uint sleep(uint);
+int symlink(string,string);
+int sync(void);
+int truncate(string,ulong);
+string ttyname(int);
+int unlink(string);
+void usleep(uint);
+long write(int, string3, ulong);
+addr sbrk(long);
+int getpagesize(void);
+long lseek(int,long,int);
+int pipe(addr);
+
+; utmp.h
+void endutent(void);
+addr getutent(void);
+void setutent(void);
+
+; wchar.h
+int fwide(addr, int);
+
+; sys/wait.h
+int wait(addr);
+int waitpid(int,addr,int);
+
+; X11/Xlib.h
+void XCloseDisplay(addr);
+int XMapWindow(addr,addr);
+addr XOpenDisplay(string);
+
+; sys/acl.h
+int acl_add_perm(addr,uint);
+int acl_calc_mask(addr);
+int acl_clear_perms(addr);
+int acl_copy_entry(addr,addr);
+int acl_copy_ext(addr,addr,int);
+addr acl_copy_int(addr);
+int acl_create_entry(addr,addr);
+int acl_delete_def_file(string);
+int acl_delete_entry(addr,addr);
+int acl_delete_perm(addr,uint);
+addr acl_dup(addr);
+int acl_free(addr);
+addr acl_from_text(string);
+int acl_get_entry(addr,int,addr);
+addr acl_get_fd(int);
+addr acl_get_file(string,int);
+int acl_get_permset(addr,addr);
+addr acl_get_qualifier(addr);
+int acl_get_tag_type(addr,addr);
+addr acl_init(int);
+int acl_set_fd(int,addr);
+int acl_set_file(string,int,addr);
+int acl_set_permset(addr,addr);
+int acl_set_qualifier(addr,addr);
+int acl_set_tag_type(addr,int);
+int acl_size(addr);
+string acl_to_text(addr,addr);
+itn acl_valid(addr);
+
+; acl/libacl.h
+int acl_check(addr,addr);
+int acl_cmp(addr,addr);
+int acl_entries(addr);
+int acl_equiv_mode(addr,addr);
+string acl_error(int);
+int acl_extended_fd(int);
+int acl_extended_file(string);
+addr acl_from_mode(octal);
+int acl_get_perm(addr,uint);
+string acl_to_any_text(addr,string,char,int);
+
+; SYSCALLS
+addr SYS_brk(addr);
+int SYS_close(int);
+int SYS_execve(string,addr,addr);
+void SYS_exit(int);
+void SYS_exit_group(int);
+int SYS_fork(void);
+int SYS_getcwd(+string2,ulong);
+int SYS_getpid(void);
+;addr SYS_mmap(addr,ulong,int,int,int,long);
+int SYS_munmap(addr,ulong);
+int SYS_open(string,int,octal);
+int SYS_personality(uint);
+long SYS_read(int,+string0,ulong);
+int SYS_stat(string,addr);
+octal SYS_umask(octal);
+int SYS_uname(addr);
+long SYS_write(int,string3,ulong);
+int SYS_sync(void);
+int SYS_setxattr(string,string,addr,uint,int);
+int SYS_lsetxattr(string,string,addr,uint,int);
+int SYS_fsetxattr(int,string,addr,uint,int);
+int SYS_getxattr(string,string,addr,uint);
+int SYS_lgetxattr(string,string,addr,uint);
+int SYS_fgetxattr(int,string,addr,uint);
+int SYS_listxattr(string,addr,uint);
+int SYS_llistxattr(string,addr,uint);
+int SYS_flistxattr(int,addr,uint);
+int SYS_removexattr(string,string);
+int SYS_lremovexattr(string,string);
+int SYS_fremovexattr(int,string);
+int SYS_chdir(string);
+int SYS_fchdir(int);
+int SYS_chmod(string,octal);
+int SYS_fchmod(int,octal);
+int SYS_chown(string,int,int);
+int SYS_fchown(int,int,int);
+int SYS_lchown(string,int,int);
+int SYS_chroot(string);
+int SYS_dup(int);
+int SYS_dup2(int,int);
+int SYS_fdatasync(int);
+int SYS_fsync(int);
+int SYS_getpriority(int,int);
+int SYS_setpriority(int,int,int);
+int SYS_getrlimit(int,addr);
+int SYS_setrlimit(int,addr);
+int SYS_gettimeofday(addr,addr);
+int SYS_settimeofday(addr,addr);
+int SYS_setfsgid(int);
+int SYS_setfsuid(int);
+int SYS_getuid(void);
+int SYS_setuid(int);
+int SYS_getgid(void);
+int SYS_setgid(int);
+int SYS_getsid(int);
+int SYS_setsid(int);
+int SYS_setreuid(int,int);
+int SYS_setregid(int,int);
+int SYS_geteuid(void);
+int SYS_getegid(void);
+int SYS_setpgid(int,int);
+int SYS_getresuid(addr,addr,addr);
+int SYS_setresuid(int,int,int);
+int SYS_getresgid(addr,addr,addr);
+int SYS_setresgid(int,int,int);
+int SYS_kill(int,int);
+int SYS_link(string,string);
+int SYS_madvise(addr,ulong,int);
+int SYS_mkdir(string,octal);
+int SYS_mknod(string,octal,int);
+int SYS_msync(addr,ulong,int);
+int SYS_nice(int);
+int SYS_poll(addr,uint,int);
+int SYS_readdir(uint,addr,uint);
+int SYS_readlink(string,string,ulong);
+int SYS_reboot(int,int,int,addr);
+int SYS_rename(string,string);
+int SYS_rmdir(string);
+int SYS_sigaltstack(addr,addr);
+int SYS_statfs(string,addr);
+int SYS_fstatfs(int,addr);
+int SYS_fstat(int,addr);
+int SYS_lstat(string,addr);
+int SYS_stime(addr);
+int SYS_symlink(string, string);
+int SYS_sysinfo(addr);
+int SYS_syslog(int,string,int);
+int SYS_truncate(string,long);
+int SYS_ftruncate(int,long);
+int SYS_mount(string,string,string,ulong,addr);
+int SYS_umount(string);
+int SYS_umount2(string,int);
+int SYS_unlink(string);
+int SYS_utime(string,addr);
+long SYS_lseek(int,long,int);
+addr SYS_signal(int,addr);
+int SYS_sigaction(int,addr,addr);
+int SYS_pause(void);
+int SYS_sigpending(addr);
+int SYS_sigprocmask(int,addr,addr);
+int SYS_sigqueue(int,int,addr);
+int SYS_sigsuspend(addr);
+int SYS_wait(addr);
+int SYS_waitpid(int,addr,int);
+ulong SYS_readv(int,addr,int);
+ulong SYS_writev(int,addr,int);
+int SYS_mprotect(addr,int,int);
+int SYS_access(string,octal);
diff --git a/execute_program.c b/execute_program.c
new file mode 100644
index 0000000..5fd6379
--- /dev/null
+++ b/execute_program.c
@@ -0,0 +1,91 @@
+#include "config.h"
+
+#include <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
index 0000000..1dfb82b
--- /dev/null
+++ b/handle_event.c
@@ -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
index 0000000..0f48d11
--- /dev/null
+++ b/libltrace.c
@@ -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
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
index 0000000..5e43ba5
--- /dev/null
+++ b/ltrace.h
@@ -0,0 +1,38 @@
+typedef enum Event_type Event_type;
+enum Event_type {
+ EVENT_NONE=0,
+ EVENT_SIGNAL,
+ EVENT_EXIT,
+ EVENT_EXIT_SIGNAL,
+ EVENT_SYSCALL,
+ EVENT_SYSRET,
+ EVENT_ARCH_SYSCALL,
+ EVENT_ARCH_SYSRET,
+ EVENT_CLONE,
+ EVENT_EXEC,
+ EVENT_BREAKPOINT,
+ EVENT_LIBCALL,
+ EVENT_LIBRET,
+ EVENT_NEW, /* in this case, proc is NULL */
+ EVENT_MAX
+};
+
+typedef struct Process Process;
+typedef struct Event Event;
+struct Event {
+ Process * proc;
+ Event_type type;
+ union {
+ int ret_val; /* EVENT_EXIT */
+ int signum; /* EVENT_SIGNAL, EVENT_EXIT_SIGNAL */
+ int sysnum; /* EVENT_SYSCALL, EVENT_SYSRET */
+ void * brk_addr; /* EVENT_BREAKPOINT */
+ int newpid; /* EVENT_CLONE, EVENT_NEW */
+ } e_un;
+};
+
+typedef void (*callback_func) (Event *);
+
+extern void ltrace_init(int argc, char **argv);
+extern void ltrace_add_callback(callback_func f, Event_type type);
+extern void ltrace_main(void);
diff --git a/ltrace.spec b/ltrace.spec
new file mode 100644
index 0000000..3740190
--- /dev/null
+++ b/ltrace.spec
@@ -0,0 +1,164 @@
+Summary: Tracks runtime library calls from dynamically linked executables.
+Name: ltrace
+Version: 0.3.36
+Release: 4.2
+Source: ftp://ftp.debian.org/debian/pool/main/l/ltrace/ltrace_%{version}.orig.tar.gz
+Patch1: ftp://ftp.debian.org/debian/pool/main/l/ltrace/ltrace_0.3.36-2.diff.gz
+Patch2: ltrace-ppc64.patch
+Patch3: ltrace-ppc64-2.patch
+Patch4: ltrace-s390x.patch
+Patch5: ltrace-syscallent-update.patch
+Patch6: ltrace-fixes.patch
+Patch7: ltrace-ia64.patch
+License: GPL
+Group: Development/Debuggers
+ExclusiveArch: i386 x86_64 ia64 ppc ppc64 s390 s390x alpha sparc
+Prefix: %{_prefix}
+BuildRoot: /var/tmp/%{name}-root
+BuildRequires: elfutils-libelf-devel
+
+%description
+Ltrace is a debugging program which runs a specified command until the
+command exits. While the command is executing, ltrace intercepts and
+records both the dynamic library calls called by the executed process
+and the signals received by the executed process. Ltrace can also
+intercept and print system calls executed by the process.
+
+You should install ltrace if you need a sysadmin tool for tracking the
+execution of processes.
+
+%prep
+%setup -q
+%patch1 -p1
+%patch2 -p1
+%patch3 -p1
+%patch4 -p1
+%patch5 -p1
+%patch6 -p1
+%patch7 -p1
+sed -i -e 's/-o root -g root//' Makefile.in
+
+%build
+export CC="gcc`echo $RPM_OPT_FLAGS | sed -n 's/^.*\(-m[36][124]\).*$/ \1/p'`"
+%configure CC="$CC"
+make
+
+%install
+make DESTDIR=$RPM_BUILD_ROOT mandir=%{_mandir} install
+rm -f ChangeLog; mv -f debian/changelog ChangeLog
+rm -rf $RPM_BUILD_ROOT/%{_prefix}/doc
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%files
+%defattr(-,root,root)
+%doc COPYING README TODO BUGS ChangeLog
+%{_prefix}/bin/ltrace
+%{_mandir}/man1/ltrace.1*
+%config /etc/ltrace.conf
+
+%changelog
+* Fri Feb 10 2006 Jesse Keating <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
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
index 0000000..25182fb
--- /dev/null
+++ b/mkdist
@@ -0,0 +1,19 @@
+#!/bin/sh -e
+
+# Create ltrace-${version}.tar.gz from a GIT repository
+
+if [ ! -d .git -o ! -f libltrace.c ]
+then
+ echo "This must be called inside a ltrace GIT repository" 1>&2
+ exit 1
+fi
+
+VERSION=$( cat VERSION )
+
+echo Building ltrace-$VERSION.tar.gz ...
+rm -rf ltrace-$VERSION
+git clone ./ ltrace-$VERSION >/dev/null
+GZIP=-9 tar --exclude .git -zcf ltrace-$VERSION.tar.gz ltrace-$VERSION
+rm -rf ltrace-$VERSION
+echo Done.
+
diff --git a/options.c b/options.c
new file mode 100644
index 0000000..aef73b1
--- /dev/null
+++ b/options.c
@@ -0,0 +1,431 @@
+#include "config.h"
+
+#include <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
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
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
index 0000000..c58577a
--- /dev/null
+++ b/output.h
@@ -0,0 +1,3 @@
+void output_line(Process *proc, char *fmt, ...);
+void output_left(enum tof type, Process *proc, char *function_name);
+void output_right(enum tof type, Process *proc, char *function_name);
diff --git a/proc.c b/proc.c
new file mode 100644
index 0000000..bfc6e41
--- /dev/null
+++ b/proc.c
@@ -0,0 +1,65 @@
+#include <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
index 0000000..b4b1b56
--- /dev/null
+++ b/read_config_file.c
@@ -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
index 0000000..8000b1c
--- /dev/null
+++ b/read_config_file.h
@@ -0,0 +1 @@
+extern void read_config_file(char *);
diff --git a/summary.c b/summary.c
new file mode 100644
index 0000000..dab845c
--- /dev/null
+++ b/summary.c
@@ -0,0 +1,86 @@
+#include "config.h"
+
+#include <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
index 0000000..ce033ef
--- /dev/null
+++ b/sysdeps/README
@@ -0,0 +1,32 @@
+Each operating system must have a subdir here, with a Makefile
+The first target of that Makefile must build a file "sysdep.o" in this
+directory.
+The "clean" target of that Makefile must undo all the efects of the
+first target, and must remove "sysdep.o" in this dir.
+
+Files "sysdep.h", "signalent.h" and "syscallent.h" must be present
+inside the directory after invoking the first target of the Makefile.
+
+-----------
+"sysdep.o" must export the following functions:
+
+Event * next_event(void);
+void continue_after_breakpoint(Process * proc, Breakpoint * sbp, int delete_it);
+void continue_after_signal(pid_t pid, int signum);
+void continue_enabling_breakpoint(pid_t pid, Breakpoint * sbp);
+void continue_process(pid_t pid);
+void enable_breakpoint(pid_t pid, Breakpoint * sbp);
+void disable_breakpoint(pid_t pid, Breakpoint * sbp);
+int fork_p(int sysnum);
+int exec_p(int sysnum);
+int syscall_p(Process * proc, int status, int * sysnum);
+void * get_instruction_pointer(pid_t pid);
+void * get_stack_pointer(pid_t pid);
+void * get_return_addr(pid_t pid, void * stack_pointer);
+long gimme_arg(enum tof type, Process * proc, arg_type_info*);
+int umovestr(Process * proc, void * addr, int len, void * laddr);
+int umovelong(Process * proc, void * addr, long * result);
+char * pid2name(pid_t pid);
+void trace_me(void);
+int trace_pid(pid_t pid);
+void untrace_pid(pid_t pid);
diff --git a/sysdeps/linux-gnu/Makefile b/sysdeps/linux-gnu/Makefile
new file mode 100644
index 0000000..eb1ec60
--- /dev/null
+++ b/sysdeps/linux-gnu/Makefile
@@ -0,0 +1,60 @@
+ARCH := $(shell uname -m | sed \
+ -e s/i.86/i386/ \
+ -e s/sun4u/sparc64/ \
+ -e s/sparc64/sparc/ \
+ -e s/arm.*/arm/ \
+ -e s/sa110/arm/ \
+ -e s/ppc64/ppc/ \
+ -e s/s390x/s390/ \
+ )
+
+CPPFLAGS += -I$(TOPDIR)/sysdeps/linux-gnu/$(ARCH)
+
+OBJ = events.o trace.o proc.o breakpoint.o
+
+all: sysdep.h signalent.h syscallent.h arch_syscallent.h signalent1.h syscallent1.h ../sysdep.o
+
+sysdep.h: $(ARCH)/arch.h
+ cat $(ARCH)/arch.h > sysdep.h
+
+signalent.h:
+ cp $(ARCH)/signalent.h signalent.h
+signalent1.h:
+ if [ -f $(ARCH)/signalent1.h ]; then \
+ cp $(ARCH)/signalent1.h signalent1.h; \
+ else \
+ > signalent1.h; \
+ fi
+
+syscallent.h:
+ cp $(ARCH)/syscallent.h syscallent.h
+
+syscallent1.h:
+ if [ -f $(ARCH)/syscallent1.h ]; then \
+ cp $(ARCH)/syscallent1.h syscallent1.h; \
+ else \
+ > syscallent1.h; \
+ fi
+
+arch_syscallent.h:
+ if [ -f $(ARCH)/arch_syscallent.h ]; then \
+ cp $(ARCH)/arch_syscallent.h arch_syscallent.h; \
+ else \
+ > arch_syscallent.h; \
+ fi
+
+../sysdep.o: os.o $(ARCH)/arch.o
+ $(CC) -nostdlib -r -o ../sysdep.o os.o $(ARCH)/arch.o
+
+os.o: $(OBJ)
+ $(CC) -nostdlib -r -o os.o $(OBJ)
+
+$(ARCH)/arch.o: dummy
+ $(MAKE) -C $(ARCH)
+
+clean:
+ $(MAKE) -C $(ARCH) clean
+ rm -f $(OBJ) sysdep.h signalent.h signalent1.h syscallent.h arch_syscallent.h
+ rm -f syscallent1.h os.o sysdep.o ../sysdep.o
+
+dummy:
diff --git a/sysdeps/linux-gnu/README b/sysdeps/linux-gnu/README
new file mode 100644
index 0000000..a8bc8ee
--- /dev/null
+++ b/sysdeps/linux-gnu/README
@@ -0,0 +1,13 @@
+* "arch/syscallent.h" is made from <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
index 0000000..60d7531
--- /dev/null
+++ b/sysdeps/linux-gnu/alpha/Makefile
@@ -0,0 +1,10 @@
+OBJ = trace.o regs.o plt.o
+
+all: arch.o
+
+arch.o: $(OBJ)
+ $(CC) -nostdlib -r -o arch.o $(OBJ)
+
+clean:
+ $(RM) $(OBJ) arch.o
+
diff --git a/sysdeps/linux-gnu/alpha/arch.h b/sysdeps/linux-gnu/alpha/arch.h
new file mode 100644
index 0000000..1107b5f
--- /dev/null
+++ b/sysdeps/linux-gnu/alpha/arch.h
@@ -0,0 +1,8 @@
+#define BREAKPOINT_VALUE { 0x80, 0x00, 0x00, 0x00 }
+#define BREAKPOINT_LENGTH 4
+#define DECR_PC_AFTER_BREAK 4
+
+#define LT_ELFCLASS ELFCLASS64
+#define LT_ELF_MACHINE EM_ALPHA
+#define LT_ELFCLASS2 ELFCLASS64
+#define LT_ELF_MACHINE2 EM_FAKE_ALPHA
diff --git a/sysdeps/linux-gnu/alpha/plt.c b/sysdeps/linux-gnu/alpha/plt.c
new file mode 100644
index 0000000..83337b2
--- /dev/null
+++ b/sysdeps/linux-gnu/alpha/plt.c
@@ -0,0 +1,12 @@
+#include <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
index 0000000..c3cbcb6
--- /dev/null
+++ b/sysdeps/linux-gnu/alpha/ptrace.h
@@ -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
index 0000000..9554e48
--- /dev/null
+++ b/sysdeps/linux-gnu/alpha/regs.c
@@ -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
index 0000000..c2a6170
--- /dev/null
+++ b/sysdeps/linux-gnu/alpha/signalent.h
@@ -0,0 +1,32 @@
+"SIG_0", /* 0 */
+ "SIGHUP", /* 1 */
+ "SIGINT", /* 2 */
+ "SIGQUIT", /* 3 */
+ "SIGILL", /* 4 */
+ "SIGTRAP", /* 5 */
+ "SIGABRT", /* 6 */
+ "SIGEMT", /* 7 */
+ "SIGFPE", /* 8 */
+ "SIGKILL", /* 9 */
+ "SIGBUS", /* 10 */
+ "SIGSEGV", /* 11 */
+ "SIGSYS", /* 12 */
+ "SIGPIPE", /* 13 */
+ "SIGALRM", /* 14 */
+ "SIGTERM", /* 15 */
+ "SIGURG", /* 16 */
+ "SIGSTOP", /* 17 */
+ "SIGTSTP", /* 18 */
+ "SIGCONT", /* 19 */
+ "SIGCHLD", /* 20 */
+ "SIGTTIN", /* 21 */
+ "SIGTTOU", /* 22 */
+ "SIGIO", /* 23 */
+ "SIGXCPU", /* 24 */
+ "SIGXFSZ", /* 25 */
+ "SIGVTALRM", /* 26 */
+ "SIGPROF", /* 27 */
+ "SIGWINCH", /* 28 */
+ "SIGINFO", /* 29 */
+ "SIGUSR1", /* 30 */
+ "SIGUSR2", /* 31 */
diff --git a/sysdeps/linux-gnu/alpha/syscallent.h b/sysdeps/linux-gnu/alpha/syscallent.h
new file mode 100644
index 0000000..7cacc8c
--- /dev/null
+++ b/sysdeps/linux-gnu/alpha/syscallent.h
@@ -0,0 +1,439 @@
+"osf_syscall", /* 0, not implemented */
+ "exit", /* 1 */
+ "fork", /* 2 */
+ "read", /* 3 */
+ "write", /* 4 */
+ "osf_old_open", /* 5, not implemented */
+ "close", /* 6 */
+ "osf_wait4", /* 7 */
+ "osf_old_creat", /* 8, not implemented */
+ "link", /* 9 */
+ "unlink", /* 10 */
+ "osf_execve", /* 11, not implemented */
+ "chdir", /* 12 */
+ "fchdir", /* 13 */
+ "mknod", /* 14 */
+ "chmod", /* 15 */
+ "chown", /* 16 */
+ "brk", /* 17 */
+ "osf_getfsstat", /* 18, not implemented */
+ "lseek", /* 19 */
+ "getxpid", /* 20 */
+ "osf_mount", /* 21 */
+ "umount", /* 22 */
+ "setuid", /* 23 */
+ "getxuid", /* 24 */
+ "exec_with_loader", /* 25, not implemented */
+ "ptrace", /* 26 */
+ "osf_nrecmsg", /* 27, not implemented */
+ "osf_nsendmsg", /* 28, not implemented */
+ "osf_nrecvfrom", /* 29, not implemented */
+ "osf_naccept", /* 30, not implemented */
+ "osf_ngetpeername", /* 31, not implemented */
+ "osf_ngetsocketname", /* 32, not implemented */
+ "access", /* 33 */
+ "osf_chflags", /* 34, not implemented */
+ "osf_fchflags", /* 35, not implemented */
+ "sync", /* 36 */
+ "kill", /* 37 */
+ "osf_old_stat", /* 38, not implemented */
+ "setpgid", /* 39 */
+ "osf_old_lstat", /* 40, not implemented */
+ "dup", /* 41 */
+ "pipe", /* 42 */
+ "osf_set_program_attributes", /* 43 */
+ "osf_profil", /* 44, not implemented */
+ "open", /* 45 */
+ "osf_old_sigaction", /* 46, not implemented */
+ "getxgid", /* 47 */
+ "osf_sigprocmask", /* 48 */
+ "osf_getlogin", /* 49, not implemented */
+ "osf_setlogin", /* 50, not implemented */
+ "acct", /* 51 */
+ "sigpending", /* 52 */
+ "SYS_53", /* 53 */
+ "ioctl", /* 54 */
+ "osf_reboot", /* 55, not implemented */
+ "osf_revoke", /* 56, not implemented */
+ "symlink", /* 57 */
+ "readlink", /* 58 */
+ "execve", /* 59 */
+ "umask", /* 60 */
+ "chroot", /* 61 */
+ "osf_old_fstat", /* 62, not implemented */
+ "getpgrp", /* 63 */
+ "getpagesize", /* 64 */
+ "osf_mremap", /* 65, not implemented */
+ "vfork", /* 66 */
+ "stat", /* 67 */
+ "lstat", /* 68 */
+ "osf_sbrk", /* 69, not implemented */
+ "osf_sstk", /* 70, not implemented */
+ "mmap", /* 71 */
+ "osf_old_vadvise", /* 72, not implemented */
+ "munmap", /* 73 */
+ "mprotect", /* 74 */
+ "madvise", /* 75 */
+ "vhangup", /* 76 */
+ "osf_kmodcall", /* 77, not implemented */
+ "osf_mincore", /* 78, not implemented */
+ "getgroups", /* 79 */
+ "setgroups", /* 80 */
+ "osf_old_getpgrp", /* 81, not implemented */
+ "setpgrp", /* 82 */
+ "osf_setitimer", /* 83 */
+ "osf_old_wait", /* 84, not implemented */
+ "osf_table", /* 85, not implemented */
+ "osf_getitimer", /* 86 */
+ "gethostname", /* 87 */
+ "sethostname", /* 88 */
+ "getdtablesize", /* 89 */
+ "dup2", /* 90 */
+ "fstat", /* 91 */
+ "fcntl", /* 92 */
+ "osf_select", /* 93 */
+ "poll", /* 94 */
+ "fsync", /* 95 */
+ "setpriority", /* 96 */
+ "socket", /* 97 */
+ "connect", /* 98 */
+ "accept", /* 99 */
+ "osf_getpriority", /* 100 */
+ "send", /* 101 */
+ "recv", /* 102 */
+ "sigreturn", /* 103 */
+ "bind", /* 104 */
+ "setsockopt", /* 105 */
+ "listen", /* 106 */
+ "osf_plock", /* 107, not implemented */
+ "osf_old_sigvec", /* 108, not implemented */
+ "osf_old_sigblock", /* 109, not implemented */
+ "osf_old_sigsetmask", /* 110, not implemented */
+ "sigsuspend", /* 111 */
+ "sigstack", /* 112 */
+ "recvmsg", /* 113 */
+ "sendmsg", /* 114 */
+ "osf_old_vtrace", /* 115, not implemented */
+ "osf_gettimeofday", /* 116 */
+ "osf_getrusage", /* 117 */
+ "getsockopt", /* 118 */
+ "SYS_119", /* 119 */
+ "readv", /* 120 */
+ "writev", /* 121 */
+ "osf_settimeofday", /* 122 */
+ "fchown", /* 123 */
+ "fchmod", /* 124 */
+ "recvfrom", /* 125 */
+ "setreuid", /* 126 */
+ "setregid", /* 127 */
+ "rename", /* 128 */
+ "truncate", /* 129 */
+ "ftruncate", /* 130 */
+ "flock", /* 131 */
+ "setgid", /* 132 */
+ "sendto", /* 133 */
+ "shutdown", /* 134 */
+ "socketpair", /* 135 */
+ "mkdir", /* 136 */
+ "rmdir", /* 137 */
+ "osf_utimes", /* 138 */
+ "osf_old_sigreturn", /* 139 */
+ "osf_adjtime", /* 140, not implemented */
+ "getpeername", /* 141 */
+ "osf_gethostid", /* 142, not implemented */
+ "osf_sethostid", /* 143, not implemented */
+ "getrlimit", /* 144 */
+ "setrlimit", /* 145 */
+ "osf_old_killpg", /* 146, not implemented */
+ "setsid", /* 147 */
+ "quotactl", /* 148 */
+ "osf_oldquota", /* 149, not implemented */
+ "getsockname", /* 150 */
+ "SYS_151", /* 151 */
+ "SYS_152", /* 152 */
+ "osf_pid_block", /* 153, not implemented */
+ "osf_pid_unblock", /* 154, not implemented */
+ "SYS_155", /* 155 */
+ "sigaction", /* 156 */
+ "osf_sigwaitprim", /* 157, not implemented */
+ "osf_nfssvc", /* 158, not implemented */
+ "osf_getdirentries", /* 159 */
+ "osf_statfs", /* 160 */
+ "osf_fstatfs", /* 161 */
+ "SYS_162", /* 162 */
+ "osf_asynch_daemon", /* 163, not implemented */
+ "osf_getfh", /* 164, not implemented */
+ "osf_getdomainname", /* 165 */
+ "setdomainname", /* 166 */
+ "SYS_167", /* 167 */
+ "SYS_168", /* 168 */
+ "osf_exportfs", /* 169, not implemented */
+ "SYS_170", /* 170 */
+ "SYS_171", /* 171 */
+ "SYS_172", /* 172 */
+ "SYS_173", /* 173 */
+ "SYS_174", /* 174 */
+ "SYS_175", /* 175 */
+ "SYS_176", /* 176 */
+ "SYS_177", /* 177 */
+ "SYS_178", /* 178 */
+ "SYS_179", /* 179 */
+ "SYS_180", /* 180 */
+ "osf_alt_plock", /* 181, not implemented */
+ "SYS_182", /* 182 */
+ "SYS_183", /* 183 */
+ "osf_getmnt", /* 184, not implemented */
+ "SYS_185", /* 185 */
+ "SYS_186", /* 186 */
+ "osf_alt_sigpending", /* 187, not implemented */
+ "osf_alt_setsid", /* 188, not implemented */
+ "SYS_189", /* 189 */
+ "SYS_190", /* 190 */
+ "SYS_191", /* 191 */
+ "SYS_192", /* 192 */
+ "SYS_193", /* 193 */
+ "SYS_194", /* 194 */
+ "SYS_195", /* 195 */
+ "SYS_196", /* 196 */
+ "SYS_197", /* 197 */
+ "SYS_198", /* 198 */
+ "osf_swapon", /* 199 */
+ "msgctl", /* 200 */
+ "msgget", /* 201 */
+ "msgrcv", /* 202 */
+ "msgsnd", /* 203 */
+ "semctl", /* 204 */
+ "semget", /* 205 */
+ "semop", /* 206 */
+ "osf_utsname", /* 207 */
+ "lchown", /* 208 */
+ "osf_shmat", /* 209 */
+ "shmctl", /* 210 */
+ "shmdt", /* 211 */
+ "shmget", /* 212 */
+ "osf_mvalid", /* 213, not implemented */
+ "osf_getaddressconf", /* 214, not implemented */
+ "osf_msleep", /* 215, not implemented */
+ "osf_mwakeup", /* 216, not implemented */
+ "msync", /* 217 */
+ "osf_signal", /* 218, not implemented */
+ "osf_utc_gettime", /* 219, not implemented */
+ "osf_utc_adjtime", /* 220, not implemented */
+ "SYS_221", /* 221 */
+ "osf_security", /* 222, not implemented */
+ "osf_kloadcall", /* 223, not implemented */
+ "SYS_224", /* 224 */
+ "SYS_225", /* 225 */
+ "SYS_226", /* 226 */
+ "SYS_227", /* 227 */
+ "SYS_228", /* 228 */
+ "SYS_229", /* 229 */
+ "SYS_230", /* 230 */
+ "SYS_231", /* 231 */
+ "SYS_232", /* 232 */
+ "getpgid", /* 233 */
+ "getsid", /* 234 */
+ "sigaltstack", /* 235 */
+ "osf_waitid", /* 236, not implemented */
+ "osf_priocntlset", /* 237, not implemented */
+ "osf_sigsendset", /* 238, not implemented */
+ "osf_set_speculative", /* 239, not implemented */
+ "osf_msfs_syscall", /* 240, not implemented */
+ "osf_sysinfo", /* 241 */
+ "osf_uadmin", /* 242, not implemented */
+ "osf_fuser", /* 243, not implemented */
+ "osf_proplist_syscall", /* 244 */
+ "osf_ntp_adjtime", /* 245, not implemented */
+ "osf_ntp_gettime", /* 246, not implemented */
+ "osf_pathconf", /* 247, not implemented */
+ "osf_fpathconf", /* 248, not implemented */
+ "SYS_249", /* 249 */
+ "osf_uswitch", /* 250, not implemented */
+ "osf_usleep_thread", /* 251 */
+ "osf_audcntl", /* 252, not implemented */
+ "osf_audgen", /* 253, not implemented */
+ "sysfs", /* 254 */
+ "osf_subsysinfo", /* 255, not implemented */
+ "osf_getsysinfo", /* 256 */
+ "osf_setsysinfo", /* 257 */
+ "osf_afs_syscall", /* 258, not implemented */
+ "osf_swapctl", /* 259, not implemented */
+ "osf_memcntl", /* 260, not implemented */
+ "osf_fdatasync", /* 261, not implemented */
+ "SYS_262", /* 262 */
+ "SYS_263", /* 263 */
+ "SYS_264", /* 264 */
+ "SYS_265", /* 265 */
+ "SYS_266", /* 266 */
+ "SYS_267", /* 267 */
+ "SYS_268", /* 268 */
+ "SYS_269", /* 269 */
+ "SYS_270", /* 270 */
+ "SYS_271", /* 271 */
+ "SYS_272", /* 272 */
+ "SYS_273", /* 273 */
+ "SYS_274", /* 274 */
+ "SYS_275", /* 275 */
+ "SYS_276", /* 276 */
+ "SYS_277", /* 277 */
+ "SYS_278", /* 278 */
+ "SYS_279", /* 279 */
+ "SYS_280", /* 280 */
+ "SYS_281", /* 281 */
+ "SYS_282", /* 282 */
+ "SYS_283", /* 283 */
+ "SYS_284", /* 284 */
+ "SYS_285", /* 285 */
+ "SYS_286", /* 286 */
+ "SYS_287", /* 287 */
+ "SYS_288", /* 288 */
+ "SYS_289", /* 289 */
+ "SYS_290", /* 290 */
+ "SYS_291", /* 291 */
+ "SYS_292", /* 292 */
+ "SYS_293", /* 293 */
+ "SYS_294", /* 294 */
+ "SYS_295", /* 295 */
+ "SYS_296", /* 296 */
+ "SYS_297", /* 297 */
+ "SYS_298", /* 298 */
+ "SYS_299", /* 299 */
+ "bdflush", /* 300 */
+ "sethae", /* 301 */
+ "mount", /* 302 */
+ "adjtimex32", /* 303 */
+ "swapoff", /* 304 */
+ "getdents", /* 305 */
+ "create_module", /* 306 */
+ "init_module", /* 307 */
+ "delete_module", /* 308 */
+ "get_kernel_syms", /* 309 */
+ "syslog", /* 310 */
+ "reboot", /* 311 */
+ "clone", /* 312 */
+ "uselib", /* 313 */
+ "mlock", /* 314 */
+ "munlock", /* 315 */
+ "mlockall", /* 316 */
+ "munlockall", /* 317 */
+ "sysinfo", /* 318 */
+ "sysctl", /* 319 */
+ "idle", /* 320 */
+ "oldumount", /* 321 */
+ "swapon", /* 322 */
+ "times", /* 323 */
+ "personality", /* 324 */
+ "setfsuid", /* 325 */
+ "setfsgid", /* 326 */
+ "ustat", /* 327 */
+ "statfs", /* 328 */
+ "fstatfs", /* 329 */
+ "sched_setparam", /* 330 */
+ "sched_getparam", /* 331 */
+ "sched_setscheduler", /* 332 */
+ "sched_getscheduler", /* 333 */
+ "sched_yield", /* 334 */
+ "sched_get_priority_max", /* 335 */
+ "sched_get_priority_min", /* 336 */
+ "sched_rr_get_interval", /* 337 */
+ "afs_syscall", /* 338 */
+ "uname", /* 339 */
+ "nanosleep", /* 340 */
+ "mremap", /* 341 */
+ "nfsservctl", /* 342 */
+ "setresuid", /* 343 */
+ "getresuid", /* 344 */
+ "pciconfig_read", /* 345 */
+ "pciconfig_write", /* 346 */
+ "query_module", /* 347 */
+ "prctl", /* 348 */
+ "pread", /* 349 */
+ "pwrite", /* 350 */
+ "rt_sigreturn", /* 351 */
+ "rt_sigaction", /* 352 */
+ "rt_sigprocmask", /* 353 */
+ "rt_sigpending", /* 354 */
+ "rt_sigtimedwait", /* 355 */
+ "rt_sigqueueinfo", /* 356 */
+ "rt_sigsuspend", /* 357 */
+ "select", /* 358 */
+ "gettimeofday", /* 359 */
+ "settimeofday", /* 360 */
+ "getitimer", /* 361 */
+ "setitimer", /* 362 */
+ "utimes", /* 363 */
+ "getrusage", /* 364 */
+ "wait4", /* 365 */
+ "adjtimex", /* 366 */
+ "getcwd", /* 367 */
+ "capget", /* 368 */
+ "capset", /* 369 */
+ "sendfile", /* 370 */
+ "setresgid", /* 371 */
+ "getresgid", /* 372 */
+ "dipc", /* 373, not implemented */
+ "pivot_root", /* 374 */
+ "mincore", /* 375 */
+ "pciconfig_iobase", /* 376 */
+ "getdents64", /* 377 */
+ "gettid", /* 378 */
+ "readahead", /* 379 */
+ "SYS_380", /* 380 */
+ "tkill", /* 381 */
+ "setxattr", /* 382 */
+ "lsetxattr", /* 383 */
+ "fsetxattr", /* 384 */
+ "getxattr", /* 385 */
+ "lgetxattr", /* 386 */
+ "fgetxattr", /* 387 */
+ "listxattr", /* 388 */
+ "llistxattr", /* 389 */
+ "flistxattr", /* 390 */
+ "removexattr", /* 391 */
+ "lremovexattr", /* 392 */
+ "fremovexattr", /* 393 */
+ "futex", /* 394 */
+ "sched_setaffinity", /* 395 */
+ "sched_getaffinity", /* 396 */
+ "tuxcall", /* 397 */
+ "io_setup", /* 398 */
+ "io_destroy", /* 399 */
+ "io_getevents", /* 400 */
+ "io_submit", /* 401 */
+ "io_cancel", /* 402 */
+ "SYS_403", /* 403 */
+ "SYS_404", /* 404 */
+ "exit_group", /* 405 */
+ "lookup_dcookie", /* 406 */
+ "epoll_create", /* 407 */
+ "epoll_ctl", /* 408 */
+ "epoll_wait", /* 409 */
+ "remap_file_pages", /* 410 */
+ "set_tid_address", /* 411 */
+ "restart_syscall", /* 412 */
+ "fadvise", /* 413 */
+ "timer_create", /* 414 */
+ "timer_settime", /* 415 */
+ "timer_gettime", /* 416 */
+ "timer_getoverrun", /* 417 */
+ "timer_delete", /* 418 */
+ "clock_settime", /* 419 */
+ "clock_gettime", /* 420 */
+ "clock_getres", /* 421 */
+ "clock_nanosleep", /* 422 */
+ "semtimedop", /* 423 */
+ "tgkill", /* 424 */
+ "stat64", /* 425 */
+ "lstat64", /* 426 */
+ "fstat64", /* 427 */
+ "vserver", /* 428 */
+ "mbind", /* 429 */
+ "get_mempolicy", /* 430 */
+ "set_mempolicy", /* 431 */
+ "mq_open", /* 432 */
+ "mq_unlink", /* 433 */
+ "mq_timedsend", /* 434 */
+ "mq_timedreceive", /* 435 */
+ "mq_notify", /* 436 */
+ "mq_getsetattr", /* 437 */
+ "waitid" /* 438 */
diff --git a/sysdeps/linux-gnu/alpha/trace.c b/sysdeps/linux-gnu/alpha/trace.c
new file mode 100644
index 0000000..e4d4063
--- /dev/null
+++ b/sysdeps/linux-gnu/alpha/trace.c
@@ -0,0 +1,75 @@
+#include "config.h"
+
+#include <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
index 0000000..853d62d
--- /dev/null
+++ b/sysdeps/linux-gnu/arch_mksyscallent
@@ -0,0 +1,42 @@
+#!/usr/bin/awk -f
+
+# hack expression to generate arch_syscallent.h from <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
index 0000000..f55ba48
--- /dev/null
+++ b/sysdeps/linux-gnu/arm/Makefile
@@ -0,0 +1,10 @@
+OBJ = trace.o regs.o plt.o breakpoint.o
+
+all: arch.o
+
+arch.o: $(OBJ) arch.h
+ $(CC) -nostdlib -r -o arch.o $(OBJ)
+
+clean:
+ $(RM) $(OBJ) arch.o
+
diff --git a/sysdeps/linux-gnu/arm/arch.h b/sysdeps/linux-gnu/arm/arch.h
new file mode 100644
index 0000000..8f2dfb3
--- /dev/null
+++ b/sysdeps/linux-gnu/arm/arch.h
@@ -0,0 +1,11 @@
+#define ARCH_HAVE_ENABLE_BREAKPOINT 1
+#define ARCH_HAVE_DISABLE_BREAKPOINT 1
+
+#define BREAKPOINT_VALUE { 0xf0, 0x01, 0xf0, 0xe7 }
+#define BREAKPOINT_LENGTH 4
+#define THUMB_BREAKPOINT_VALUE { 0x01, 0xde }
+#define THUMB_BREAKPOINT_LENGTH 2
+#define DECR_PC_AFTER_BREAK 0
+
+#define LT_ELFCLASS ELFCLASS32
+#define LT_ELF_MACHINE EM_ARM
diff --git a/sysdeps/linux-gnu/arm/arch_syscallent.h b/sysdeps/linux-gnu/arm/arch_syscallent.h
new file mode 100644
index 0000000..ce1e844
--- /dev/null
+++ b/sysdeps/linux-gnu/arm/arch_syscallent.h
@@ -0,0 +1,6 @@
+ "0", /* 0 */
+ "breakpoint", /* 1 */
+ "cacheflush", /* 2 */
+ "usr26", /* 3 */
+ "usr32", /* 4 */
+ "set_tls", /* 5 */
diff --git a/sysdeps/linux-gnu/arm/breakpoint.c b/sysdeps/linux-gnu/arm/breakpoint.c
new file mode 100644
index 0000000..4c20260
--- /dev/null
+++ b/sysdeps/linux-gnu/arm/breakpoint.c
@@ -0,0 +1,77 @@
+/*
+ * This file is part of ltrace.
+ *
+ * Copyright (C) 2007 by Instituto Nokia de Tecnologia (INdT)
+ *
+ * Author: Anderson Lizardo <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
index 0000000..bd92a63
--- /dev/null
+++ b/sysdeps/linux-gnu/arm/plt.c
@@ -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
index 0000000..52215bc
--- /dev/null
+++ b/sysdeps/linux-gnu/arm/ptrace.h
@@ -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
index 0000000..2488b0a
--- /dev/null
+++ b/sysdeps/linux-gnu/arm/regs.c
@@ -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
index 0000000..0afb004
--- /dev/null
+++ b/sysdeps/linux-gnu/arm/signalent.h
@@ -0,0 +1,33 @@
+ "SIG_0", /* 0 */
+ "SIGHUP", /* 1 */
+ "SIGINT", /* 2 */
+ "SIGQUIT", /* 3 */
+ "SIGILL", /* 4 */
+ "SIGTRAP", /* 5 */
+ "SIGABRT", /* 6 */
+ "SIGBUS", /* 7 */
+ "SIGFPE", /* 8 */
+ "SIGKILL", /* 9 */
+ "SIGUSR1", /* 10 */
+ "SIGSEGV", /* 11 */
+ "SIGUSR2", /* 12 */
+ "SIGPIPE", /* 13 */
+ "SIGALRM", /* 14 */
+ "SIGTERM", /* 15 */
+ "SIGSTKFLT", /* 16 */
+ "SIGCHLD", /* 17 */
+ "SIGCONT", /* 18 */
+ "SIGSTOP", /* 19 */
+ "SIGTSTP", /* 20 */
+ "SIGTTIN", /* 21 */
+ "SIGTTOU", /* 22 */
+ "SIGURG", /* 23 */
+ "SIGXCPU", /* 24 */
+ "SIGXFSZ", /* 25 */
+ "SIGVTALRM", /* 26 */
+ "SIGPROF", /* 27 */
+ "SIGWINCH", /* 28 */
+ "SIGIO", /* 29 */
+ "SIGPWR", /* 30 */
+ "SIGSYS", /* 31 */
+ "SIGSWI", /* 32 */
diff --git a/sysdeps/linux-gnu/arm/syscallent.h b/sysdeps/linux-gnu/arm/syscallent.h
new file mode 100644
index 0000000..4113234
--- /dev/null
+++ b/sysdeps/linux-gnu/arm/syscallent.h
@@ -0,0 +1,322 @@
+ "restart_syscall", /* 0 */
+ "exit", /* 1 */
+ "fork", /* 2 */
+ "read", /* 3 */
+ "write", /* 4 */
+ "open", /* 5 */
+ "close", /* 6 */
+ "7", /* 7 */
+ "creat", /* 8 */
+ "link", /* 9 */
+ "unlink", /* 10 */
+ "execve", /* 11 */
+ "chdir", /* 12 */
+ "time", /* 13 */
+ "mknod", /* 14 */
+ "chmod", /* 15 */
+ "lchown", /* 16 */
+ "17", /* 17 */
+ "18", /* 18 */
+ "lseek", /* 19 */
+ "getpid", /* 20 */
+ "mount", /* 21 */
+ "umount", /* 22 */
+ "setuid", /* 23 */
+ "getuid", /* 24 */
+ "stime", /* 25 */
+ "ptrace", /* 26 */
+ "alarm", /* 27 */
+ "28", /* 28 */
+ "pause", /* 29 */
+ "utime", /* 30 */
+ "31", /* 31 */
+ "32", /* 32 */
+ "access", /* 33 */
+ "nice", /* 34 */
+ "35", /* 35 */
+ "sync", /* 36 */
+ "kill", /* 37 */
+ "rename", /* 38 */
+ "mkdir", /* 39 */
+ "rmdir", /* 40 */
+ "dup", /* 41 */
+ "pipe", /* 42 */
+ "times", /* 43 */
+ "44", /* 44 */
+ "brk", /* 45 */
+ "setgid", /* 46 */
+ "getgid", /* 47 */
+ "48", /* 48 */
+ "geteuid", /* 49 */
+ "getegid", /* 50 */
+ "acct", /* 51 */
+ "umount2", /* 52 */
+ "53", /* 53 */
+ "ioctl", /* 54 */
+ "fcntl", /* 55 */
+ "56", /* 56 */
+ "setpgid", /* 57 */
+ "58", /* 58 */
+ "59", /* 59 */
+ "umask", /* 60 */
+ "chroot", /* 61 */
+ "ustat", /* 62 */
+ "dup2", /* 63 */
+ "getppid", /* 64 */
+ "getpgrp", /* 65 */
+ "setsid", /* 66 */
+ "sigaction", /* 67 */
+ "68", /* 68 */
+ "69", /* 69 */
+ "setreuid", /* 70 */
+ "setregid", /* 71 */
+ "sigsuspend", /* 72 */
+ "sigpending", /* 73 */
+ "sethostname", /* 74 */
+ "setrlimit", /* 75 */
+ "getrlimit", /* 76 */
+ "getrusage", /* 77 */
+ "gettimeofday", /* 78 */
+ "settimeofday", /* 79 */
+ "getgroups", /* 80 */
+ "setgroups", /* 81 */
+ "select", /* 82 */
+ "symlink", /* 83 */
+ "84", /* 84 */
+ "readlink", /* 85 */
+ "uselib", /* 86 */
+ "swapon", /* 87 */
+ "reboot", /* 88 */
+ "readdir", /* 89 */
+ "mmap", /* 90 */
+ "munmap", /* 91 */
+ "truncate", /* 92 */
+ "ftruncate", /* 93 */
+ "fchmod", /* 94 */
+ "fchown", /* 95 */
+ "getpriority", /* 96 */
+ "setpriority", /* 97 */
+ "98", /* 98 */
+ "statfs", /* 99 */
+ "fstatfs", /* 100 */
+ "101", /* 101 */
+ "socketcall", /* 102 */
+ "syslog", /* 103 */
+ "setitimer", /* 104 */
+ "getitimer", /* 105 */
+ "stat", /* 106 */
+ "lstat", /* 107 */
+ "fstat", /* 108 */
+ "109", /* 109 */
+ "110", /* 110 */
+ "vhangup", /* 111 */
+ "112", /* 112 */
+ "syscall", /* 113 */
+ "wait4", /* 114 */
+ "swapoff", /* 115 */
+ "sysinfo", /* 116 */
+ "ipc", /* 117 */
+ "fsync", /* 118 */
+ "sigreturn", /* 119 */
+ "clone", /* 120 */
+ "setdomainname", /* 121 */
+ "uname", /* 122 */
+ "123", /* 123 */
+ "adjtimex", /* 124 */
+ "mprotect", /* 125 */
+ "sigprocmask", /* 126 */
+ "127", /* 127 */
+ "init_module", /* 128 */
+ "delete_module", /* 129 */
+ "130", /* 130 */
+ "quotactl", /* 131 */
+ "getpgid", /* 132 */
+ "fchdir", /* 133 */
+ "bdflush", /* 134 */
+ "sysfs", /* 135 */
+ "personality", /* 136 */
+ "137", /* 137 */
+ "setfsuid", /* 138 */
+ "setfsgid", /* 139 */
+ "_llseek", /* 140 */
+ "getdents", /* 141 */
+ "_newselect", /* 142 */
+ "flock", /* 143 */
+ "msync", /* 144 */
+ "readv", /* 145 */
+ "writev", /* 146 */
+ "getsid", /* 147 */
+ "fdatasync", /* 148 */
+ "_sysctl", /* 149 */
+ "mlock", /* 150 */
+ "munlock", /* 151 */
+ "mlockall", /* 152 */
+ "munlockall", /* 153 */
+ "sched_setparam", /* 154 */
+ "sched_getparam", /* 155 */
+ "sched_setscheduler", /* 156 */
+ "sched_getscheduler", /* 157 */
+ "sched_yield", /* 158 */
+ "sched_get_priority_max", /* 159 */
+ "sched_get_priority_min", /* 160 */
+ "sched_rr_get_interval", /* 161 */
+ "nanosleep", /* 162 */
+ "mremap", /* 163 */
+ "setresuid", /* 164 */
+ "getresuid", /* 165 */
+ "166", /* 166 */
+ "167", /* 167 */
+ "poll", /* 168 */
+ "nfsservctl", /* 169 */
+ "setresgid", /* 170 */
+ "getresgid", /* 171 */
+ "prctl", /* 172 */
+ "rt_sigreturn", /* 173 */
+ "rt_sigaction", /* 174 */
+ "rt_sigprocmask", /* 175 */
+ "rt_sigpending", /* 176 */
+ "rt_sigtimedwait", /* 177 */
+ "rt_sigqueueinfo", /* 178 */
+ "rt_sigsuspend", /* 179 */
+ "pread64", /* 180 */
+ "pwrite64", /* 181 */
+ "chown", /* 182 */
+ "getcwd", /* 183 */
+ "capget", /* 184 */
+ "capset", /* 185 */
+ "sigaltstack", /* 186 */
+ "sendfile", /* 187 */
+ "188", /* 188 */
+ "189", /* 189 */
+ "vfork", /* 190 */
+ "ugetrlimit", /* 191 */
+ "mmap2", /* 192 */
+ "truncate64", /* 193 */
+ "ftruncate64", /* 194 */
+ "stat64", /* 195 */
+ "lstat64", /* 196 */
+ "fstat64", /* 197 */
+ "lchown32", /* 198 */
+ "getuid32", /* 199 */
+ "getgid32", /* 200 */
+ "geteuid32", /* 201 */
+ "getegid32", /* 202 */
+ "setreuid32", /* 203 */
+ "setregid32", /* 204 */
+ "getgroups32", /* 205 */
+ "setgroups32", /* 206 */
+ "fchown32", /* 207 */
+ "setresuid32", /* 208 */
+ "getresuid32", /* 209 */
+ "setresgid32", /* 210 */
+ "getresgid32", /* 211 */
+ "chown32", /* 212 */
+ "setuid32", /* 213 */
+ "setgid32", /* 214 */
+ "setfsuid32", /* 215 */
+ "setfsgid32", /* 216 */
+ "getdents64", /* 217 */
+ "pivot_root", /* 218 */
+ "mincore", /* 219 */
+ "madvise", /* 220 */
+ "fcntl64", /* 221 */
+ "222", /* 222 */
+ "223", /* 223 */
+ "gettid", /* 224 */
+ "readahead", /* 225 */
+ "setxattr", /* 226 */
+ "lsetxattr", /* 227 */
+ "fsetxattr", /* 228 */
+ "getxattr", /* 229 */
+ "lgetxattr", /* 230 */
+ "fgetxattr", /* 231 */
+ "listxattr", /* 232 */
+ "llistxattr", /* 233 */
+ "flistxattr", /* 234 */
+ "removexattr", /* 235 */
+ "lremovexattr", /* 236 */
+ "fremovexattr", /* 237 */
+ "tkill", /* 238 */
+ "sendfile64", /* 239 */
+ "futex", /* 240 */
+ "sched_setaffinity", /* 241 */
+ "sched_getaffinity", /* 242 */
+ "io_setup", /* 243 */
+ "io_destroy", /* 244 */
+ "io_getevents", /* 245 */
+ "io_submit", /* 246 */
+ "io_cancel", /* 247 */
+ "exit_group", /* 248 */
+ "lookup_dcookie", /* 249 */
+ "epoll_create", /* 250 */
+ "epoll_ctl", /* 251 */
+ "epoll_wait", /* 252 */
+ "remap_file_pages", /* 253 */
+ "254", /* 254 */
+ "255", /* 255 */
+ "set_tid_address", /* 256 */
+ "timer_create", /* 257 */
+ "timer_settime", /* 258 */
+ "timer_gettime", /* 259 */
+ "timer_getoverrun", /* 260 */
+ "timer_delete", /* 261 */
+ "clock_settime", /* 262 */
+ "clock_gettime", /* 263 */
+ "clock_getres", /* 264 */
+ "clock_nanosleep", /* 265 */
+ "statfs64", /* 266 */
+ "fstatfs64", /* 267 */
+ "tgkill", /* 268 */
+ "utimes", /* 269 */
+ "arm_fadvise64_64", /* 270 */
+ "pciconfig_iobase", /* 271 */
+ "pciconfig_read", /* 272 */
+ "pciconfig_write", /* 273 */
+ "mq_open", /* 274 */
+ "mq_unlink", /* 275 */
+ "mq_timedsend", /* 276 */
+ "mq_timedreceive", /* 277 */
+ "mq_notify", /* 278 */
+ "mq_getsetattr", /* 279 */
+ "waitid", /* 280 */
+ "socket", /* 281 */
+ "bind", /* 282 */
+ "connect", /* 283 */
+ "listen", /* 284 */
+ "accept", /* 285 */
+ "getsockname", /* 286 */
+ "getpeername", /* 287 */
+ "socketpair", /* 288 */
+ "send", /* 289 */
+ "sendto", /* 290 */
+ "recv", /* 291 */
+ "recvfrom", /* 292 */
+ "shutdown", /* 293 */
+ "setsockopt", /* 294 */
+ "getsockopt", /* 295 */
+ "sendmsg", /* 296 */
+ "recvmsg", /* 297 */
+ "semop", /* 298 */
+ "semget", /* 299 */
+ "semctl", /* 300 */
+ "msgsnd", /* 301 */
+ "msgrcv", /* 302 */
+ "msgget", /* 303 */
+ "msgctl", /* 304 */
+ "shmat", /* 305 */
+ "shmdt", /* 306 */
+ "shmget", /* 307 */
+ "shmctl", /* 308 */
+ "add_key", /* 309 */
+ "request_key", /* 310 */
+ "keyctl", /* 311 */
+ "semtimedop", /* 312 */
+ "vserver", /* 313 */
+ "ioprio_set", /* 314 */
+ "ioprio_get", /* 315 */
+ "inotify_init", /* 316 */
+ "inotify_add_watch", /* 317 */
+ "inotify_rm_watch", /* 318 */
+ "mbind", /* 319 */
+ "get_mempolicy", /* 320 */
+ "set_mempolicy", /* 321 */
diff --git a/sysdeps/linux-gnu/arm/trace.c b/sysdeps/linux-gnu/arm/trace.c
new file mode 100644
index 0000000..10f7cc4
--- /dev/null
+++ b/sysdeps/linux-gnu/arm/trace.c
@@ -0,0 +1,131 @@
+#include "config.h"
+
+#include <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
index 0000000..5ca131a
--- /dev/null
+++ b/sysdeps/linux-gnu/breakpoint.c
@@ -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
index 0000000..a1e2a14
--- /dev/null
+++ b/sysdeps/linux-gnu/events.c
@@ -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
index 0000000..60d7531
--- /dev/null
+++ b/sysdeps/linux-gnu/i386/Makefile
@@ -0,0 +1,10 @@
+OBJ = trace.o regs.o plt.o
+
+all: arch.o
+
+arch.o: $(OBJ)
+ $(CC) -nostdlib -r -o arch.o $(OBJ)
+
+clean:
+ $(RM) $(OBJ) arch.o
+
diff --git a/sysdeps/linux-gnu/i386/arch.h b/sysdeps/linux-gnu/i386/arch.h
new file mode 100644
index 0000000..dc7383f
--- /dev/null
+++ b/sysdeps/linux-gnu/i386/arch.h
@@ -0,0 +1,6 @@
+#define BREAKPOINT_VALUE {0xcc}
+#define BREAKPOINT_LENGTH 1
+#define DECR_PC_AFTER_BREAK 1
+
+#define LT_ELFCLASS ELFCLASS32
+#define LT_ELF_MACHINE EM_386
diff --git a/sysdeps/linux-gnu/i386/plt.c b/sysdeps/linux-gnu/i386/plt.c
new file mode 100644
index 0000000..b53ff44
--- /dev/null
+++ b/sysdeps/linux-gnu/i386/plt.c
@@ -0,0 +1,12 @@
+#include <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
index 0000000..c3cbcb6
--- /dev/null
+++ b/sysdeps/linux-gnu/i386/ptrace.h
@@ -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
index 0000000..6777f17
--- /dev/null
+++ b/sysdeps/linux-gnu/i386/regs.c
@@ -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
index 0000000..5395f82
--- /dev/null
+++ b/sysdeps/linux-gnu/i386/signalent.h
@@ -0,0 +1,32 @@
+ "SIG_0", /* 0 */
+ "SIGHUP", /* 1 */
+ "SIGINT", /* 2 */
+ "SIGQUIT", /* 3 */
+ "SIGILL", /* 4 */
+ "SIGTRAP", /* 5 */
+ "SIGABRT", /* 6 */
+ "SIGBUS", /* 7 */
+ "SIGFPE", /* 8 */
+ "SIGKILL", /* 9 */
+ "SIGUSR1", /* 10 */
+ "SIGSEGV", /* 11 */
+ "SIGUSR2", /* 12 */
+ "SIGPIPE", /* 13 */
+ "SIGALRM", /* 14 */
+ "SIGTERM", /* 15 */
+ "SIGSTKFLT", /* 16 */
+ "SIGCHLD", /* 17 */
+ "SIGCONT", /* 18 */
+ "SIGSTOP", /* 19 */
+ "SIGTSTP", /* 20 */
+ "SIGTTIN", /* 21 */
+ "SIGTTOU", /* 22 */
+ "SIGURG", /* 23 */
+ "SIGXCPU", /* 24 */
+ "SIGXFSZ", /* 25 */
+ "SIGVTALRM", /* 26 */
+ "SIGPROF", /* 27 */
+ "SIGWINCH", /* 28 */
+ "SIGIO", /* 29 */
+ "SIGPWR", /* 30 */
+ "SIGSYS", /* 31 */
diff --git a/sysdeps/linux-gnu/i386/syscallent.h b/sysdeps/linux-gnu/i386/syscallent.h
new file mode 100644
index 0000000..8f4c887
--- /dev/null
+++ b/sysdeps/linux-gnu/i386/syscallent.h
@@ -0,0 +1,317 @@
+ "restart_syscall", /* 0 */
+ "exit", /* 1 */
+ "fork", /* 2 */
+ "read", /* 3 */
+ "write", /* 4 */
+ "open", /* 5 */
+ "close", /* 6 */
+ "waitpid", /* 7 */
+ "creat", /* 8 */
+ "link", /* 9 */
+ "unlink", /* 10 */
+ "execve", /* 11 */
+ "chdir", /* 12 */
+ "time", /* 13 */
+ "mknod", /* 14 */
+ "chmod", /* 15 */
+ "lchown", /* 16 */
+ "break", /* 17 */
+ "oldstat", /* 18 */
+ "lseek", /* 19 */
+ "getpid", /* 20 */
+ "mount", /* 21 */
+ "umount", /* 22 */
+ "setuid", /* 23 */
+ "getuid", /* 24 */
+ "stime", /* 25 */
+ "ptrace", /* 26 */
+ "alarm", /* 27 */
+ "oldfstat", /* 28 */
+ "pause", /* 29 */
+ "utime", /* 30 */
+ "stty", /* 31 */
+ "gtty", /* 32 */
+ "access", /* 33 */
+ "nice", /* 34 */
+ "ftime", /* 35 */
+ "sync", /* 36 */
+ "kill", /* 37 */
+ "rename", /* 38 */
+ "mkdir", /* 39 */
+ "rmdir", /* 40 */
+ "dup", /* 41 */
+ "pipe", /* 42 */
+ "times", /* 43 */
+ "prof", /* 44 */
+ "brk", /* 45 */
+ "setgid", /* 46 */
+ "getgid", /* 47 */
+ "signal", /* 48 */
+ "geteuid", /* 49 */
+ "getegid", /* 50 */
+ "acct", /* 51 */
+ "umount2", /* 52 */
+ "lock", /* 53 */
+ "ioctl", /* 54 */
+ "fcntl", /* 55 */
+ "mpx", /* 56 */
+ "setpgid", /* 57 */
+ "ulimit", /* 58 */
+ "oldolduname", /* 59 */
+ "umask", /* 60 */
+ "chroot", /* 61 */
+ "ustat", /* 62 */
+ "dup2", /* 63 */
+ "getppid", /* 64 */
+ "getpgrp", /* 65 */
+ "setsid", /* 66 */
+ "sigaction", /* 67 */
+ "sgetmask", /* 68 */
+ "ssetmask", /* 69 */
+ "setreuid", /* 70 */
+ "setregid", /* 71 */
+ "sigsuspend", /* 72 */
+ "sigpending", /* 73 */
+ "sethostname", /* 74 */
+ "setrlimit", /* 75 */
+ "getrlimit", /* 76 */
+ "getrusage", /* 77 */
+ "gettimeofday", /* 78 */
+ "settimeofday", /* 79 */
+ "getgroups", /* 80 */
+ "setgroups", /* 81 */
+ "select", /* 82 */
+ "symlink", /* 83 */
+ "oldlstat", /* 84 */
+ "readlink", /* 85 */
+ "uselib", /* 86 */
+ "swapon", /* 87 */
+ "reboot", /* 88 */
+ "readdir", /* 89 */
+ "mmap", /* 90 */
+ "munmap", /* 91 */
+ "truncate", /* 92 */
+ "ftruncate", /* 93 */
+ "fchmod", /* 94 */
+ "fchown", /* 95 */
+ "getpriority", /* 96 */
+ "setpriority", /* 97 */
+ "profil", /* 98 */
+ "statfs", /* 99 */
+ "fstatfs", /* 100 */
+ "ioperm", /* 101 */
+ "socketcall", /* 102 */
+ "syslog", /* 103 */
+ "setitimer", /* 104 */
+ "getitimer", /* 105 */
+ "stat", /* 106 */
+ "lstat", /* 107 */
+ "fstat", /* 108 */
+ "olduname", /* 109 */
+ "iopl", /* 110 */
+ "vhangup", /* 111 */
+ "idle", /* 112 */
+ "vm86old", /* 113 */
+ "wait4", /* 114 */
+ "swapoff", /* 115 */
+ "sysinfo", /* 116 */
+ "ipc", /* 117 */
+ "fsync", /* 118 */
+ "sigreturn", /* 119 */
+ "clone", /* 120 */
+ "setdomainname", /* 121 */
+ "uname", /* 122 */
+ "modify_ldt", /* 123 */
+ "adjtimex", /* 124 */
+ "mprotect", /* 125 */
+ "sigprocmask", /* 126 */
+ "create_module", /* 127 */
+ "init_module", /* 128 */
+ "delete_module", /* 129 */
+ "get_kernel_syms", /* 130 */
+ "quotactl", /* 131 */
+ "getpgid", /* 132 */
+ "fchdir", /* 133 */
+ "bdflush", /* 134 */
+ "sysfs", /* 135 */
+ "personality", /* 136 */
+ "afs_syscall", /* 137 */
+ "setfsuid", /* 138 */
+ "setfsgid", /* 139 */
+ "_llseek", /* 140 */
+ "getdents", /* 141 */
+ "_newselect", /* 142 */
+ "flock", /* 143 */
+ "msync", /* 144 */
+ "readv", /* 145 */
+ "writev", /* 146 */
+ "getsid", /* 147 */
+ "fdatasync", /* 148 */
+ "_sysctl", /* 149 */
+ "mlock", /* 150 */
+ "munlock", /* 151 */
+ "mlockall", /* 152 */
+ "munlockall", /* 153 */
+ "sched_setparam", /* 154 */
+ "sched_getparam", /* 155 */
+ "sched_setscheduler", /* 156 */
+ "sched_getscheduler", /* 157 */
+ "sched_yield", /* 158 */
+ "sched_get_priority_max", /* 159 */
+ "sched_get_priority_min", /* 160 */
+ "sched_rr_get_interval", /* 161 */
+ "nanosleep", /* 162 */
+ "mremap", /* 163 */
+ "setresuid", /* 164 */
+ "getresuid", /* 165 */
+ "vm86", /* 166 */
+ "query_module", /* 167 */
+ "poll", /* 168 */
+ "nfsservctl", /* 169 */
+ "setresgid", /* 170 */
+ "getresgid", /* 171 */
+ "prctl", /* 172 */
+ "rt_sigreturn", /* 173 */
+ "rt_sigaction", /* 174 */
+ "rt_sigprocmask", /* 175 */
+ "rt_sigpending", /* 176 */
+ "rt_sigtimedwait", /* 177 */
+ "rt_sigqueueinfo", /* 178 */
+ "rt_sigsuspend", /* 179 */
+ "pread64", /* 180 */
+ "pwrite64", /* 181 */
+ "chown", /* 182 */
+ "getcwd", /* 183 */
+ "capget", /* 184 */
+ "capset", /* 185 */
+ "sigaltstack", /* 186 */
+ "sendfile", /* 187 */
+ "getpmsg", /* 188 */
+ "putpmsg", /* 189 */
+ "vfork", /* 190 */
+ "ugetrlimit", /* 191 */
+ "mmap2", /* 192 */
+ "truncate64", /* 193 */
+ "ftruncate64", /* 194 */
+ "stat64", /* 195 */
+ "lstat64", /* 196 */
+ "fstat64", /* 197 */
+ "lchown32", /* 198 */
+ "getuid32", /* 199 */
+ "getgid32", /* 200 */
+ "geteuid32", /* 201 */
+ "getegid32", /* 202 */
+ "setreuid32", /* 203 */
+ "setregid32", /* 204 */
+ "getgroups32", /* 205 */
+ "setgroups32", /* 206 */
+ "fchown32", /* 207 */
+ "setresuid32", /* 208 */
+ "getresuid32", /* 209 */
+ "setresgid32", /* 210 */
+ "getresgid32", /* 211 */
+ "chown32", /* 212 */
+ "setuid32", /* 213 */
+ "setgid32", /* 214 */
+ "setfsuid32", /* 215 */
+ "setfsgid32", /* 216 */
+ "pivot_root", /* 217 */
+ "mincore", /* 218 */
+ "madvise1", /* 219 */
+ "getdents64", /* 220 */
+ "fcntl64", /* 221 */
+ "222", /* 222 */
+ "223", /* 223 */
+ "gettid", /* 224 */
+ "readahead", /* 225 */
+ "setxattr", /* 226 */
+ "lsetxattr", /* 227 */
+ "fsetxattr", /* 228 */
+ "getxattr", /* 229 */
+ "lgetxattr", /* 230 */
+ "fgetxattr", /* 231 */
+ "listxattr", /* 232 */
+ "llistxattr", /* 233 */
+ "flistxattr", /* 234 */
+ "removexattr", /* 235 */
+ "lremovexattr", /* 236 */
+ "fremovexattr", /* 237 */
+ "tkill", /* 238 */
+ "sendfile64", /* 239 */
+ "futex", /* 240 */
+ "sched_setaffinity", /* 241 */
+ "sched_getaffinity", /* 242 */
+ "set_thread_area", /* 243 */
+ "get_thread_area", /* 244 */
+ "io_setup", /* 245 */
+ "io_destroy", /* 246 */
+ "io_getevents", /* 247 */
+ "io_submit", /* 248 */
+ "io_cancel", /* 249 */
+ "fadvise64", /* 250 */
+ "251", /* 251 */
+ "exit_group", /* 252 */
+ "lookup_dcookie", /* 253 */
+ "epoll_create", /* 254 */
+ "epoll_ctl", /* 255 */
+ "epoll_wait", /* 256 */
+ "remap_file_pages", /* 257 */
+ "set_tid_address", /* 258 */
+ "timer_create", /* 259 */
+ "260", /* 260 */
+ "261", /* 261 */
+ "262", /* 262 */
+ "263", /* 263 */
+ "264", /* 264 */
+ "265", /* 265 */
+ "266", /* 266 */
+ "267", /* 267 */
+ "statfs64", /* 268 */
+ "fstatfs64", /* 269 */
+ "tgkill", /* 270 */
+ "utimes", /* 271 */
+ "fadvise64_64", /* 272 */
+ "vserver", /* 273 */
+ "mbind", /* 274 */
+ "get_mempolicy", /* 275 */
+ "set_mempolicy", /* 276 */
+ "mq_open", /* 277 */
+ "278", /* 278 */
+ "279", /* 279 */
+ "280", /* 280 */
+ "281", /* 281 */
+ "282", /* 282 */
+ "kexec_load", /* 283 */
+ "waitid", /* 284 */
+ "285", /* 285 */
+ "add_key", /* 286 */
+ "request_key", /* 287 */
+ "keyctl", /* 288 */
+ "ioprio_set", /* 289 */
+ "ioprio_get", /* 290 */
+ "inotify_init", /* 291 */
+ "inotify_add_watch", /* 292 */
+ "inotify_rm_watch", /* 293 */
+ "migrate_pages", /* 294 */
+ "openat", /* 295 */
+ "mkdirat", /* 296 */
+ "mknodat", /* 297 */
+ "fchownat", /* 298 */
+ "futimesat", /* 299 */
+ "fstatat64", /* 300 */
+ "unlinkat", /* 301 */
+ "renameat", /* 302 */
+ "linkat", /* 303 */
+ "symlinkat", /* 304 */
+ "readlinkat", /* 305 */
+ "fchmodat", /* 306 */
+ "faccessat", /* 307 */
+ "pselect6", /* 308 */
+ "ppoll", /* 309 */
+ "unshare", /* 310 */
+ "set_robust_list", /* 311 */
+ "get_robust_list", /* 312 */
+ "splice", /* 313 */
+ "sync_file_range", /* 314 */
+ "tee", /* 315 */
+ "vmsplice", /* 316 */
diff --git a/sysdeps/linux-gnu/i386/trace.c b/sysdeps/linux-gnu/i386/trace.c
new file mode 100644
index 0000000..76f1105
--- /dev/null
+++ b/sysdeps/linux-gnu/i386/trace.c
@@ -0,0 +1,85 @@
+#include "config.h"
+
+#include <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
index 0000000..4f0ef63
--- /dev/null
+++ b/sysdeps/linux-gnu/ia64/Makefile
@@ -0,0 +1,10 @@
+OBJ = trace.o regs.o plt.o breakpoint.o
+
+all: arch.o
+
+arch.o: $(OBJ)
+ $(LD) -r -o arch.o $(OBJ)
+
+clean:
+ $(RM) $(OBJ) arch.o
+
diff --git a/sysdeps/linux-gnu/ia64/arch.h b/sysdeps/linux-gnu/ia64/arch.h
new file mode 100644
index 0000000..673047c
--- /dev/null
+++ b/sysdeps/linux-gnu/ia64/arch.h
@@ -0,0 +1,13 @@
+#define ARCH_HAVE_DISABLE_BREAKPOINT 1
+#define ARCH_HAVE_ENABLE_BREAKPOINT 1
+
+#define BREAKPOINT_LENGTH 16
+#define BREAKPOINT_VALUE {0}
+#define DECR_PC_AFTER_BREAK 0
+
+#define LT_ELFCLASS ELFCLASS64
+#define LT_ELF_MACHINE EM_IA_64
+
+// ia64 actually does use .opd, but we don't need to do the
+// translation manually.
+#undef ARCH_SUPPORTS_OPD
diff --git a/sysdeps/linux-gnu/ia64/breakpoint.c b/sysdeps/linux-gnu/ia64/breakpoint.c
new file mode 100644
index 0000000..4f09173
--- /dev/null
+++ b/sysdeps/linux-gnu/ia64/breakpoint.c
@@ -0,0 +1,212 @@
+/* IA64 breakpoint support. Much of this clagged from gdb
+ * -Ian Wienand <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
index 0000000..7fd451b
--- /dev/null
+++ b/sysdeps/linux-gnu/ia64/plt.c
@@ -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
index 0000000..c3cbcb6
--- /dev/null
+++ b/sysdeps/linux-gnu/ia64/ptrace.h
@@ -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
index 0000000..d161d34
--- /dev/null
+++ b/sysdeps/linux-gnu/ia64/regs.c
@@ -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
index 0000000..5395f82
--- /dev/null
+++ b/sysdeps/linux-gnu/ia64/signalent.h
@@ -0,0 +1,32 @@
+ "SIG_0", /* 0 */
+ "SIGHUP", /* 1 */
+ "SIGINT", /* 2 */
+ "SIGQUIT", /* 3 */
+ "SIGILL", /* 4 */
+ "SIGTRAP", /* 5 */
+ "SIGABRT", /* 6 */
+ "SIGBUS", /* 7 */
+ "SIGFPE", /* 8 */
+ "SIGKILL", /* 9 */
+ "SIGUSR1", /* 10 */
+ "SIGSEGV", /* 11 */
+ "SIGUSR2", /* 12 */
+ "SIGPIPE", /* 13 */
+ "SIGALRM", /* 14 */
+ "SIGTERM", /* 15 */
+ "SIGSTKFLT", /* 16 */
+ "SIGCHLD", /* 17 */
+ "SIGCONT", /* 18 */
+ "SIGSTOP", /* 19 */
+ "SIGTSTP", /* 20 */
+ "SIGTTIN", /* 21 */
+ "SIGTTOU", /* 22 */
+ "SIGURG", /* 23 */
+ "SIGXCPU", /* 24 */
+ "SIGXFSZ", /* 25 */
+ "SIGVTALRM", /* 26 */
+ "SIGPROF", /* 27 */
+ "SIGWINCH", /* 28 */
+ "SIGIO", /* 29 */
+ "SIGPWR", /* 30 */
+ "SIGSYS", /* 31 */
diff --git a/sysdeps/linux-gnu/ia64/syscallent.h b/sysdeps/linux-gnu/ia64/syscallent.h
new file mode 100644
index 0000000..9bb4fb8
--- /dev/null
+++ b/sysdeps/linux-gnu/ia64/syscallent.h
@@ -0,0 +1,1303 @@
+ "0", /* 0 */
+ "1", /* 1 */
+ "2", /* 2 */
+ "3", /* 3 */
+ "4", /* 4 */
+ "5", /* 5 */
+ "6", /* 6 */
+ "7", /* 7 */
+ "8", /* 8 */
+ "9", /* 9 */
+ "10", /* 10 */
+ "11", /* 11 */
+ "12", /* 12 */
+ "13", /* 13 */
+ "14", /* 14 */
+ "15", /* 15 */
+ "16", /* 16 */
+ "17", /* 17 */
+ "18", /* 18 */
+ "19", /* 19 */
+ "20", /* 20 */
+ "21", /* 21 */
+ "22", /* 22 */
+ "23", /* 23 */
+ "24", /* 24 */
+ "25", /* 25 */
+ "26", /* 26 */
+ "27", /* 27 */
+ "28", /* 28 */
+ "29", /* 29 */
+ "30", /* 30 */
+ "31", /* 31 */
+ "32", /* 32 */
+ "33", /* 33 */
+ "34", /* 34 */
+ "35", /* 35 */
+ "36", /* 36 */
+ "37", /* 37 */
+ "38", /* 38 */
+ "39", /* 39 */
+ "40", /* 40 */
+ "41", /* 41 */
+ "42", /* 42 */
+ "43", /* 43 */
+ "44", /* 44 */
+ "45", /* 45 */
+ "46", /* 46 */
+ "47", /* 47 */
+ "48", /* 48 */
+ "49", /* 49 */
+ "50", /* 50 */
+ "51", /* 51 */
+ "52", /* 52 */
+ "53", /* 53 */
+ "54", /* 54 */
+ "55", /* 55 */
+ "56", /* 56 */
+ "57", /* 57 */
+ "58", /* 58 */
+ "59", /* 59 */
+ "60", /* 60 */
+ "61", /* 61 */
+ "62", /* 62 */
+ "63", /* 63 */
+ "64", /* 64 */
+ "65", /* 65 */
+ "66", /* 66 */
+ "67", /* 67 */
+ "68", /* 68 */
+ "69", /* 69 */
+ "70", /* 70 */
+ "71", /* 71 */
+ "72", /* 72 */
+ "73", /* 73 */
+ "74", /* 74 */
+ "75", /* 75 */
+ "76", /* 76 */
+ "77", /* 77 */
+ "78", /* 78 */
+ "79", /* 79 */
+ "80", /* 80 */
+ "81", /* 81 */
+ "82", /* 82 */
+ "83", /* 83 */
+ "84", /* 84 */
+ "85", /* 85 */
+ "86", /* 86 */
+ "87", /* 87 */
+ "88", /* 88 */
+ "89", /* 89 */
+ "90", /* 90 */
+ "91", /* 91 */
+ "92", /* 92 */
+ "93", /* 93 */
+ "94", /* 94 */
+ "95", /* 95 */
+ "96", /* 96 */
+ "97", /* 97 */
+ "98", /* 98 */
+ "99", /* 99 */
+ "100", /* 100 */
+ "101", /* 101 */
+ "102", /* 102 */
+ "103", /* 103 */
+ "104", /* 104 */
+ "105", /* 105 */
+ "106", /* 106 */
+ "107", /* 107 */
+ "108", /* 108 */
+ "109", /* 109 */
+ "110", /* 110 */
+ "111", /* 111 */
+ "112", /* 112 */
+ "113", /* 113 */
+ "114", /* 114 */
+ "115", /* 115 */
+ "116", /* 116 */
+ "117", /* 117 */
+ "118", /* 118 */
+ "119", /* 119 */
+ "120", /* 120 */
+ "121", /* 121 */
+ "122", /* 122 */
+ "123", /* 123 */
+ "124", /* 124 */
+ "125", /* 125 */
+ "126", /* 126 */
+ "127", /* 127 */
+ "128", /* 128 */
+ "129", /* 129 */
+ "130", /* 130 */
+ "131", /* 131 */
+ "132", /* 132 */
+ "133", /* 133 */
+ "134", /* 134 */
+ "135", /* 135 */
+ "136", /* 136 */
+ "137", /* 137 */
+ "138", /* 138 */
+ "139", /* 139 */
+ "140", /* 140 */
+ "141", /* 141 */
+ "142", /* 142 */
+ "143", /* 143 */
+ "144", /* 144 */
+ "145", /* 145 */
+ "146", /* 146 */
+ "147", /* 147 */
+ "148", /* 148 */
+ "149", /* 149 */
+ "150", /* 150 */
+ "151", /* 151 */
+ "152", /* 152 */
+ "153", /* 153 */
+ "154", /* 154 */
+ "155", /* 155 */
+ "156", /* 156 */
+ "157", /* 157 */
+ "158", /* 158 */
+ "159", /* 159 */
+ "160", /* 160 */
+ "161", /* 161 */
+ "162", /* 162 */
+ "163", /* 163 */
+ "164", /* 164 */
+ "165", /* 165 */
+ "166", /* 166 */
+ "167", /* 167 */
+ "168", /* 168 */
+ "169", /* 169 */
+ "170", /* 170 */
+ "171", /* 171 */
+ "172", /* 172 */
+ "173", /* 173 */
+ "174", /* 174 */
+ "175", /* 175 */
+ "176", /* 176 */
+ "177", /* 177 */
+ "178", /* 178 */
+ "179", /* 179 */
+ "180", /* 180 */
+ "181", /* 181 */
+ "182", /* 182 */
+ "183", /* 183 */
+ "184", /* 184 */
+ "185", /* 185 */
+ "186", /* 186 */
+ "187", /* 187 */
+ "188", /* 188 */
+ "189", /* 189 */
+ "190", /* 190 */
+ "191", /* 191 */
+ "192", /* 192 */
+ "193", /* 193 */
+ "194", /* 194 */
+ "195", /* 195 */
+ "196", /* 196 */
+ "197", /* 197 */
+ "198", /* 198 */
+ "199", /* 199 */
+ "200", /* 200 */
+ "201", /* 201 */
+ "202", /* 202 */
+ "203", /* 203 */
+ "204", /* 204 */
+ "205", /* 205 */
+ "206", /* 206 */
+ "207", /* 207 */
+ "208", /* 208 */
+ "209", /* 209 */
+ "210", /* 210 */
+ "211", /* 211 */
+ "212", /* 212 */
+ "213", /* 213 */
+ "214", /* 214 */
+ "215", /* 215 */
+ "216", /* 216 */
+ "217", /* 217 */
+ "218", /* 218 */
+ "219", /* 219 */
+ "220", /* 220 */
+ "221", /* 221 */
+ "222", /* 222 */
+ "223", /* 223 */
+ "224", /* 224 */
+ "225", /* 225 */
+ "226", /* 226 */
+ "227", /* 227 */
+ "228", /* 228 */
+ "229", /* 229 */
+ "230", /* 230 */
+ "231", /* 231 */
+ "232", /* 232 */
+ "233", /* 233 */
+ "234", /* 234 */
+ "235", /* 235 */
+ "236", /* 236 */
+ "237", /* 237 */
+ "238", /* 238 */
+ "239", /* 239 */
+ "240", /* 240 */
+ "241", /* 241 */
+ "242", /* 242 */
+ "243", /* 243 */
+ "244", /* 244 */
+ "245", /* 245 */
+ "246", /* 246 */
+ "247", /* 247 */
+ "248", /* 248 */
+ "249", /* 249 */
+ "250", /* 250 */
+ "251", /* 251 */
+ "252", /* 252 */
+ "253", /* 253 */
+ "254", /* 254 */
+ "255", /* 255 */
+ "256", /* 256 */
+ "257", /* 257 */
+ "258", /* 258 */
+ "259", /* 259 */
+ "260", /* 260 */
+ "261", /* 261 */
+ "262", /* 262 */
+ "263", /* 263 */
+ "264", /* 264 */
+ "265", /* 265 */
+ "266", /* 266 */
+ "267", /* 267 */
+ "268", /* 268 */
+ "269", /* 269 */
+ "270", /* 270 */
+ "271", /* 271 */
+ "272", /* 272 */
+ "273", /* 273 */
+ "274", /* 274 */
+ "275", /* 275 */
+ "276", /* 276 */
+ "277", /* 277 */
+ "278", /* 278 */
+ "279", /* 279 */
+ "280", /* 280 */
+ "281", /* 281 */
+ "282", /* 282 */
+ "283", /* 283 */
+ "284", /* 284 */
+ "285", /* 285 */
+ "286", /* 286 */
+ "287", /* 287 */
+ "288", /* 288 */
+ "289", /* 289 */
+ "290", /* 290 */
+ "291", /* 291 */
+ "292", /* 292 */
+ "293", /* 293 */
+ "294", /* 294 */
+ "295", /* 295 */
+ "296", /* 296 */
+ "297", /* 297 */
+ "298", /* 298 */
+ "299", /* 299 */
+ "300", /* 300 */
+ "301", /* 301 */
+ "302", /* 302 */
+ "303", /* 303 */
+ "304", /* 304 */
+ "305", /* 305 */
+ "306", /* 306 */
+ "307", /* 307 */
+ "308", /* 308 */
+ "309", /* 309 */
+ "310", /* 310 */
+ "311", /* 311 */
+ "312", /* 312 */
+ "313", /* 313 */
+ "314", /* 314 */
+ "315", /* 315 */
+ "316", /* 316 */
+ "317", /* 317 */
+ "318", /* 318 */
+ "319", /* 319 */
+ "320", /* 320 */
+ "321", /* 321 */
+ "322", /* 322 */
+ "323", /* 323 */
+ "324", /* 324 */
+ "325", /* 325 */
+ "326", /* 326 */
+ "327", /* 327 */
+ "328", /* 328 */
+ "329", /* 329 */
+ "330", /* 330 */
+ "331", /* 331 */
+ "332", /* 332 */
+ "333", /* 333 */
+ "334", /* 334 */
+ "335", /* 335 */
+ "336", /* 336 */
+ "337", /* 337 */
+ "338", /* 338 */
+ "339", /* 339 */
+ "340", /* 340 */
+ "341", /* 341 */
+ "342", /* 342 */
+ "343", /* 343 */
+ "344", /* 344 */
+ "345", /* 345 */
+ "346", /* 346 */
+ "347", /* 347 */
+ "348", /* 348 */
+ "349", /* 349 */
+ "350", /* 350 */
+ "351", /* 351 */
+ "352", /* 352 */
+ "353", /* 353 */
+ "354", /* 354 */
+ "355", /* 355 */
+ "356", /* 356 */
+ "357", /* 357 */
+ "358", /* 358 */
+ "359", /* 359 */
+ "360", /* 360 */
+ "361", /* 361 */
+ "362", /* 362 */
+ "363", /* 363 */
+ "364", /* 364 */
+ "365", /* 365 */
+ "366", /* 366 */
+ "367", /* 367 */
+ "368", /* 368 */
+ "369", /* 369 */
+ "370", /* 370 */
+ "371", /* 371 */
+ "372", /* 372 */
+ "373", /* 373 */
+ "374", /* 374 */
+ "375", /* 375 */
+ "376", /* 376 */
+ "377", /* 377 */
+ "378", /* 378 */
+ "379", /* 379 */
+ "380", /* 380 */
+ "381", /* 381 */
+ "382", /* 382 */
+ "383", /* 383 */
+ "384", /* 384 */
+ "385", /* 385 */
+ "386", /* 386 */
+ "387", /* 387 */
+ "388", /* 388 */
+ "389", /* 389 */
+ "390", /* 390 */
+ "391", /* 391 */
+ "392", /* 392 */
+ "393", /* 393 */
+ "394", /* 394 */
+ "395", /* 395 */
+ "396", /* 396 */
+ "397", /* 397 */
+ "398", /* 398 */
+ "399", /* 399 */
+ "400", /* 400 */
+ "401", /* 401 */
+ "402", /* 402 */
+ "403", /* 403 */
+ "404", /* 404 */
+ "405", /* 405 */
+ "406", /* 406 */
+ "407", /* 407 */
+ "408", /* 408 */
+ "409", /* 409 */
+ "410", /* 410 */
+ "411", /* 411 */
+ "412", /* 412 */
+ "413", /* 413 */
+ "414", /* 414 */
+ "415", /* 415 */
+ "416", /* 416 */
+ "417", /* 417 */
+ "418", /* 418 */
+ "419", /* 419 */
+ "420", /* 420 */
+ "421", /* 421 */
+ "422", /* 422 */
+ "423", /* 423 */
+ "424", /* 424 */
+ "425", /* 425 */
+ "426", /* 426 */
+ "427", /* 427 */
+ "428", /* 428 */
+ "429", /* 429 */
+ "430", /* 430 */
+ "431", /* 431 */
+ "432", /* 432 */
+ "433", /* 433 */
+ "434", /* 434 */
+ "435", /* 435 */
+ "436", /* 436 */
+ "437", /* 437 */
+ "438", /* 438 */
+ "439", /* 439 */
+ "440", /* 440 */
+ "441", /* 441 */
+ "442", /* 442 */
+ "443", /* 443 */
+ "444", /* 444 */
+ "445", /* 445 */
+ "446", /* 446 */
+ "447", /* 447 */
+ "448", /* 448 */
+ "449", /* 449 */
+ "450", /* 450 */
+ "451", /* 451 */
+ "452", /* 452 */
+ "453", /* 453 */
+ "454", /* 454 */
+ "455", /* 455 */
+ "456", /* 456 */
+ "457", /* 457 */
+ "458", /* 458 */
+ "459", /* 459 */
+ "460", /* 460 */
+ "461", /* 461 */
+ "462", /* 462 */
+ "463", /* 463 */
+ "464", /* 464 */
+ "465", /* 465 */
+ "466", /* 466 */
+ "467", /* 467 */
+ "468", /* 468 */
+ "469", /* 469 */
+ "470", /* 470 */
+ "471", /* 471 */
+ "472", /* 472 */
+ "473", /* 473 */
+ "474", /* 474 */
+ "475", /* 475 */
+ "476", /* 476 */
+ "477", /* 477 */
+ "478", /* 478 */
+ "479", /* 479 */
+ "480", /* 480 */
+ "481", /* 481 */
+ "482", /* 482 */
+ "483", /* 483 */
+ "484", /* 484 */
+ "485", /* 485 */
+ "486", /* 486 */
+ "487", /* 487 */
+ "488", /* 488 */
+ "489", /* 489 */
+ "490", /* 490 */
+ "491", /* 491 */
+ "492", /* 492 */
+ "493", /* 493 */
+ "494", /* 494 */
+ "495", /* 495 */
+ "496", /* 496 */
+ "497", /* 497 */
+ "498", /* 498 */
+ "499", /* 499 */
+ "500", /* 500 */
+ "501", /* 501 */
+ "502", /* 502 */
+ "503", /* 503 */
+ "504", /* 504 */
+ "505", /* 505 */
+ "506", /* 506 */
+ "507", /* 507 */
+ "508", /* 508 */
+ "509", /* 509 */
+ "510", /* 510 */
+ "511", /* 511 */
+ "512", /* 512 */
+ "513", /* 513 */
+ "514", /* 514 */
+ "515", /* 515 */
+ "516", /* 516 */
+ "517", /* 517 */
+ "518", /* 518 */
+ "519", /* 519 */
+ "520", /* 520 */
+ "521", /* 521 */
+ "522", /* 522 */
+ "523", /* 523 */
+ "524", /* 524 */
+ "525", /* 525 */
+ "526", /* 526 */
+ "527", /* 527 */
+ "528", /* 528 */
+ "529", /* 529 */
+ "530", /* 530 */
+ "531", /* 531 */
+ "532", /* 532 */
+ "533", /* 533 */
+ "534", /* 534 */
+ "535", /* 535 */
+ "536", /* 536 */
+ "537", /* 537 */
+ "538", /* 538 */
+ "539", /* 539 */
+ "540", /* 540 */
+ "541", /* 541 */
+ "542", /* 542 */
+ "543", /* 543 */
+ "544", /* 544 */
+ "545", /* 545 */
+ "546", /* 546 */
+ "547", /* 547 */
+ "548", /* 548 */
+ "549", /* 549 */
+ "550", /* 550 */
+ "551", /* 551 */
+ "552", /* 552 */
+ "553", /* 553 */
+ "554", /* 554 */
+ "555", /* 555 */
+ "556", /* 556 */
+ "557", /* 557 */
+ "558", /* 558 */
+ "559", /* 559 */
+ "560", /* 560 */
+ "561", /* 561 */
+ "562", /* 562 */
+ "563", /* 563 */
+ "564", /* 564 */
+ "565", /* 565 */
+ "566", /* 566 */
+ "567", /* 567 */
+ "568", /* 568 */
+ "569", /* 569 */
+ "570", /* 570 */
+ "571", /* 571 */
+ "572", /* 572 */
+ "573", /* 573 */
+ "574", /* 574 */
+ "575", /* 575 */
+ "576", /* 576 */
+ "577", /* 577 */
+ "578", /* 578 */
+ "579", /* 579 */
+ "580", /* 580 */
+ "581", /* 581 */
+ "582", /* 582 */
+ "583", /* 583 */
+ "584", /* 584 */
+ "585", /* 585 */
+ "586", /* 586 */
+ "587", /* 587 */
+ "588", /* 588 */
+ "589", /* 589 */
+ "590", /* 590 */
+ "591", /* 591 */
+ "592", /* 592 */
+ "593", /* 593 */
+ "594", /* 594 */
+ "595", /* 595 */
+ "596", /* 596 */
+ "597", /* 597 */
+ "598", /* 598 */
+ "599", /* 599 */
+ "600", /* 600 */
+ "601", /* 601 */
+ "602", /* 602 */
+ "603", /* 603 */
+ "604", /* 604 */
+ "605", /* 605 */
+ "606", /* 606 */
+ "607", /* 607 */
+ "608", /* 608 */
+ "609", /* 609 */
+ "610", /* 610 */
+ "611", /* 611 */
+ "612", /* 612 */
+ "613", /* 613 */
+ "614", /* 614 */
+ "615", /* 615 */
+ "616", /* 616 */
+ "617", /* 617 */
+ "618", /* 618 */
+ "619", /* 619 */
+ "620", /* 620 */
+ "621", /* 621 */
+ "622", /* 622 */
+ "623", /* 623 */
+ "624", /* 624 */
+ "625", /* 625 */
+ "626", /* 626 */
+ "627", /* 627 */
+ "628", /* 628 */
+ "629", /* 629 */
+ "630", /* 630 */
+ "631", /* 631 */
+ "632", /* 632 */
+ "633", /* 633 */
+ "634", /* 634 */
+ "635", /* 635 */
+ "636", /* 636 */
+ "637", /* 637 */
+ "638", /* 638 */
+ "639", /* 639 */
+ "640", /* 640 */
+ "641", /* 641 */
+ "642", /* 642 */
+ "643", /* 643 */
+ "644", /* 644 */
+ "645", /* 645 */
+ "646", /* 646 */
+ "647", /* 647 */
+ "648", /* 648 */
+ "649", /* 649 */
+ "650", /* 650 */
+ "651", /* 651 */
+ "652", /* 652 */
+ "653", /* 653 */
+ "654", /* 654 */
+ "655", /* 655 */
+ "656", /* 656 */
+ "657", /* 657 */
+ "658", /* 658 */
+ "659", /* 659 */
+ "660", /* 660 */
+ "661", /* 661 */
+ "662", /* 662 */
+ "663", /* 663 */
+ "664", /* 664 */
+ "665", /* 665 */
+ "666", /* 666 */
+ "667", /* 667 */
+ "668", /* 668 */
+ "669", /* 669 */
+ "670", /* 670 */
+ "671", /* 671 */
+ "672", /* 672 */
+ "673", /* 673 */
+ "674", /* 674 */
+ "675", /* 675 */
+ "676", /* 676 */
+ "677", /* 677 */
+ "678", /* 678 */
+ "679", /* 679 */
+ "680", /* 680 */
+ "681", /* 681 */
+ "682", /* 682 */
+ "683", /* 683 */
+ "684", /* 684 */
+ "685", /* 685 */
+ "686", /* 686 */
+ "687", /* 687 */
+ "688", /* 688 */
+ "689", /* 689 */
+ "690", /* 690 */
+ "691", /* 691 */
+ "692", /* 692 */
+ "693", /* 693 */
+ "694", /* 694 */
+ "695", /* 695 */
+ "696", /* 696 */
+ "697", /* 697 */
+ "698", /* 698 */
+ "699", /* 699 */
+ "700", /* 700 */
+ "701", /* 701 */
+ "702", /* 702 */
+ "703", /* 703 */
+ "704", /* 704 */
+ "705", /* 705 */
+ "706", /* 706 */
+ "707", /* 707 */
+ "708", /* 708 */
+ "709", /* 709 */
+ "710", /* 710 */
+ "711", /* 711 */
+ "712", /* 712 */
+ "713", /* 713 */
+ "714", /* 714 */
+ "715", /* 715 */
+ "716", /* 716 */
+ "717", /* 717 */
+ "718", /* 718 */
+ "719", /* 719 */
+ "720", /* 720 */
+ "721", /* 721 */
+ "722", /* 722 */
+ "723", /* 723 */
+ "724", /* 724 */
+ "725", /* 725 */
+ "726", /* 726 */
+ "727", /* 727 */
+ "728", /* 728 */
+ "729", /* 729 */
+ "730", /* 730 */
+ "731", /* 731 */
+ "732", /* 732 */
+ "733", /* 733 */
+ "734", /* 734 */
+ "735", /* 735 */
+ "736", /* 736 */
+ "737", /* 737 */
+ "738", /* 738 */
+ "739", /* 739 */
+ "740", /* 740 */
+ "741", /* 741 */
+ "742", /* 742 */
+ "743", /* 743 */
+ "744", /* 744 */
+ "745", /* 745 */
+ "746", /* 746 */
+ "747", /* 747 */
+ "748", /* 748 */
+ "749", /* 749 */
+ "750", /* 750 */
+ "751", /* 751 */
+ "752", /* 752 */
+ "753", /* 753 */
+ "754", /* 754 */
+ "755", /* 755 */
+ "756", /* 756 */
+ "757", /* 757 */
+ "758", /* 758 */
+ "759", /* 759 */
+ "760", /* 760 */
+ "761", /* 761 */
+ "762", /* 762 */
+ "763", /* 763 */
+ "764", /* 764 */
+ "765", /* 765 */
+ "766", /* 766 */
+ "767", /* 767 */
+ "768", /* 768 */
+ "769", /* 769 */
+ "770", /* 770 */
+ "771", /* 771 */
+ "772", /* 772 */
+ "773", /* 773 */
+ "774", /* 774 */
+ "775", /* 775 */
+ "776", /* 776 */
+ "777", /* 777 */
+ "778", /* 778 */
+ "779", /* 779 */
+ "780", /* 780 */
+ "781", /* 781 */
+ "782", /* 782 */
+ "783", /* 783 */
+ "784", /* 784 */
+ "785", /* 785 */
+ "786", /* 786 */
+ "787", /* 787 */
+ "788", /* 788 */
+ "789", /* 789 */
+ "790", /* 790 */
+ "791", /* 791 */
+ "792", /* 792 */
+ "793", /* 793 */
+ "794", /* 794 */
+ "795", /* 795 */
+ "796", /* 796 */
+ "797", /* 797 */
+ "798", /* 798 */
+ "799", /* 799 */
+ "800", /* 800 */
+ "801", /* 801 */
+ "802", /* 802 */
+ "803", /* 803 */
+ "804", /* 804 */
+ "805", /* 805 */
+ "806", /* 806 */
+ "807", /* 807 */
+ "808", /* 808 */
+ "809", /* 809 */
+ "810", /* 810 */
+ "811", /* 811 */
+ "812", /* 812 */
+ "813", /* 813 */
+ "814", /* 814 */
+ "815", /* 815 */
+ "816", /* 816 */
+ "817", /* 817 */
+ "818", /* 818 */
+ "819", /* 819 */
+ "820", /* 820 */
+ "821", /* 821 */
+ "822", /* 822 */
+ "823", /* 823 */
+ "824", /* 824 */
+ "825", /* 825 */
+ "826", /* 826 */
+ "827", /* 827 */
+ "828", /* 828 */
+ "829", /* 829 */
+ "830", /* 830 */
+ "831", /* 831 */
+ "832", /* 832 */
+ "833", /* 833 */
+ "834", /* 834 */
+ "835", /* 835 */
+ "836", /* 836 */
+ "837", /* 837 */
+ "838", /* 838 */
+ "839", /* 839 */
+ "840", /* 840 */
+ "841", /* 841 */
+ "842", /* 842 */
+ "843", /* 843 */
+ "844", /* 844 */
+ "845", /* 845 */
+ "846", /* 846 */
+ "847", /* 847 */
+ "848", /* 848 */
+ "849", /* 849 */
+ "850", /* 850 */
+ "851", /* 851 */
+ "852", /* 852 */
+ "853", /* 853 */
+ "854", /* 854 */
+ "855", /* 855 */
+ "856", /* 856 */
+ "857", /* 857 */
+ "858", /* 858 */
+ "859", /* 859 */
+ "860", /* 860 */
+ "861", /* 861 */
+ "862", /* 862 */
+ "863", /* 863 */
+ "864", /* 864 */
+ "865", /* 865 */
+ "866", /* 866 */
+ "867", /* 867 */
+ "868", /* 868 */
+ "869", /* 869 */
+ "870", /* 870 */
+ "871", /* 871 */
+ "872", /* 872 */
+ "873", /* 873 */
+ "874", /* 874 */
+ "875", /* 875 */
+ "876", /* 876 */
+ "877", /* 877 */
+ "878", /* 878 */
+ "879", /* 879 */
+ "880", /* 880 */
+ "881", /* 881 */
+ "882", /* 882 */
+ "883", /* 883 */
+ "884", /* 884 */
+ "885", /* 885 */
+ "886", /* 886 */
+ "887", /* 887 */
+ "888", /* 888 */
+ "889", /* 889 */
+ "890", /* 890 */
+ "891", /* 891 */
+ "892", /* 892 */
+ "893", /* 893 */
+ "894", /* 894 */
+ "895", /* 895 */
+ "896", /* 896 */
+ "897", /* 897 */
+ "898", /* 898 */
+ "899", /* 899 */
+ "900", /* 900 */
+ "901", /* 901 */
+ "902", /* 902 */
+ "903", /* 903 */
+ "904", /* 904 */
+ "905", /* 905 */
+ "906", /* 906 */
+ "907", /* 907 */
+ "908", /* 908 */
+ "909", /* 909 */
+ "910", /* 910 */
+ "911", /* 911 */
+ "912", /* 912 */
+ "913", /* 913 */
+ "914", /* 914 */
+ "915", /* 915 */
+ "916", /* 916 */
+ "917", /* 917 */
+ "918", /* 918 */
+ "919", /* 919 */
+ "920", /* 920 */
+ "921", /* 921 */
+ "922", /* 922 */
+ "923", /* 923 */
+ "924", /* 924 */
+ "925", /* 925 */
+ "926", /* 926 */
+ "927", /* 927 */
+ "928", /* 928 */
+ "929", /* 929 */
+ "930", /* 930 */
+ "931", /* 931 */
+ "932", /* 932 */
+ "933", /* 933 */
+ "934", /* 934 */
+ "935", /* 935 */
+ "936", /* 936 */
+ "937", /* 937 */
+ "938", /* 938 */
+ "939", /* 939 */
+ "940", /* 940 */
+ "941", /* 941 */
+ "942", /* 942 */
+ "943", /* 943 */
+ "944", /* 944 */
+ "945", /* 945 */
+ "946", /* 946 */
+ "947", /* 947 */
+ "948", /* 948 */
+ "949", /* 949 */
+ "950", /* 950 */
+ "951", /* 951 */
+ "952", /* 952 */
+ "953", /* 953 */
+ "954", /* 954 */
+ "955", /* 955 */
+ "956", /* 956 */
+ "957", /* 957 */
+ "958", /* 958 */
+ "959", /* 959 */
+ "960", /* 960 */
+ "961", /* 961 */
+ "962", /* 962 */
+ "963", /* 963 */
+ "964", /* 964 */
+ "965", /* 965 */
+ "966", /* 966 */
+ "967", /* 967 */
+ "968", /* 968 */
+ "969", /* 969 */
+ "970", /* 970 */
+ "971", /* 971 */
+ "972", /* 972 */
+ "973", /* 973 */
+ "974", /* 974 */
+ "975", /* 975 */
+ "976", /* 976 */
+ "977", /* 977 */
+ "978", /* 978 */
+ "979", /* 979 */
+ "980", /* 980 */
+ "981", /* 981 */
+ "982", /* 982 */
+ "983", /* 983 */
+ "984", /* 984 */
+ "985", /* 985 */
+ "986", /* 986 */
+ "987", /* 987 */
+ "988", /* 988 */
+ "989", /* 989 */
+ "990", /* 990 */
+ "991", /* 991 */
+ "992", /* 992 */
+ "993", /* 993 */
+ "994", /* 994 */
+ "995", /* 995 */
+ "996", /* 996 */
+ "997", /* 997 */
+ "998", /* 998 */
+ "999", /* 999 */
+ "1000", /* 1000 */
+ "1001", /* 1001 */
+ "1002", /* 1002 */
+ "1003", /* 1003 */
+ "1004", /* 1004 */
+ "1005", /* 1005 */
+ "1006", /* 1006 */
+ "1007", /* 1007 */
+ "1008", /* 1008 */
+ "1009", /* 1009 */
+ "1010", /* 1010 */
+ "1011", /* 1011 */
+ "1012", /* 1012 */
+ "1013", /* 1013 */
+ "1014", /* 1014 */
+ "1015", /* 1015 */
+ "1016", /* 1016 */
+ "1017", /* 1017 */
+ "1018", /* 1018 */
+ "1019", /* 1019 */
+ "1020", /* 1020 */
+ "1021", /* 1021 */
+ "1022", /* 1022 */
+ "1023", /* 1023 */
+ "ni_syscall", /* 1024 */
+ "exit", /* 1025 */
+ "read", /* 1026 */
+ "write", /* 1027 */
+ "open", /* 1028 */
+ "close", /* 1029 */
+ "creat", /* 1030 */
+ "link", /* 1031 */
+ "unlink", /* 1032 */
+ "execve", /* 1033 */
+ "chdir", /* 1034 */
+ "fchdir", /* 1035 */
+ "utimes", /* 1036 */
+ "mknod", /* 1037 */
+ "chmod", /* 1038 */
+ "chown", /* 1039 */
+ "lseek", /* 1040 */
+ "getpid", /* 1041 */
+ "getppid", /* 1042 */
+ "mount", /* 1043 */
+ "umount", /* 1044 */
+ "setuid", /* 1045 */
+ "getuid", /* 1046 */
+ "geteuid", /* 1047 */
+ "ptrace", /* 1048 */
+ "access", /* 1049 */
+ "sync", /* 1050 */
+ "fsync", /* 1051 */
+ "fdatasync", /* 1052 */
+ "kill", /* 1053 */
+ "rename", /* 1054 */
+ "mkdir", /* 1055 */
+ "rmdir", /* 1056 */
+ "dup", /* 1057 */
+ "pipe", /* 1058 */
+ "times", /* 1059 */
+ "brk", /* 1060 */
+ "setgid", /* 1061 */
+ "getgid", /* 1062 */
+ "getegid", /* 1063 */
+ "acct", /* 1064 */
+ "ioctl", /* 1065 */
+ "fcntl", /* 1066 */
+ "umask", /* 1067 */
+ "chroot", /* 1068 */
+ "ustat", /* 1069 */
+ "dup2", /* 1070 */
+ "setreuid", /* 1071 */
+ "setregid", /* 1072 */
+ "getresuid", /* 1073 */
+ "setresuid", /* 1074 */
+ "getresgid", /* 1075 */
+ "setresgid", /* 1076 */
+ "getgroups", /* 1077 */
+ "setgroups", /* 1078 */
+ "getpgid", /* 1079 */
+ "setpgid", /* 1080 */
+ "setsid", /* 1081 */
+ "getsid", /* 1082 */
+ "sethostname", /* 1083 */
+ "setrlimit", /* 1084 */
+ "getrlimit", /* 1085 */
+ "getrusage", /* 1086 */
+ "gettimeofday", /* 1087 */
+ "settimeofday", /* 1088 */
+ "select", /* 1089 */
+ "poll", /* 1090 */
+ "symlink", /* 1091 */
+ "readlink", /* 1092 */
+ "uselib", /* 1093 */
+ "swapon", /* 1094 */
+ "swapoff", /* 1095 */
+ "reboot", /* 1096 */
+ "truncate", /* 1097 */
+ "ftruncate", /* 1098 */
+ "fchmod", /* 1099 */
+ "fchown", /* 1100 */
+ "getpriority", /* 1101 */
+ "setpriority", /* 1102 */
+ "statfs", /* 1103 */
+ "fstatfs", /* 1104 */
+ "gettid", /* 1105 */
+ "semget", /* 1106 */
+ "semop", /* 1107 */
+ "semctl", /* 1108 */
+ "msgget", /* 1109 */
+ "msgsnd", /* 1110 */
+ "msgrcv", /* 1111 */
+ "msgctl", /* 1112 */
+ "shmget", /* 1113 */
+ "shmat", /* 1114 */
+ "shmdt", /* 1115 */
+ "shmctl", /* 1116 */
+ "syslog", /* 1117 */
+ "setitimer", /* 1118 */
+ "getitimer", /* 1119 */
+ "1120", /* 1120 */
+ "1121", /* 1121 */
+ "1122", /* 1122 */
+ "vhangup", /* 1123 */
+ "lchown", /* 1124 */
+ "remap_file_pages", /* 1125 */
+ "wait4", /* 1126 */
+ "sysinfo", /* 1127 */
+ "clone", /* 1128 */
+ "setdomainname", /* 1129 */
+ "uname", /* 1130 */
+ "adjtimex", /* 1131 */
+ "1132", /* 1132 */
+ "init_module", /* 1133 */
+ "delete_module", /* 1134 */
+ "1135", /* 1135 */
+ "1136", /* 1136 */
+ "quotactl", /* 1137 */
+ "bdflush", /* 1138 */
+ "sysfs", /* 1139 */
+ "personality", /* 1140 */
+ "afs_syscall", /* 1141 */
+ "setfsuid", /* 1142 */
+ "setfsgid", /* 1143 */
+ "getdents", /* 1144 */
+ "flock", /* 1145 */
+ "readv", /* 1146 */
+ "writev", /* 1147 */
+ "pread64", /* 1148 */
+ "pwrite64", /* 1149 */
+ "_sysctl", /* 1150 */
+ "mmap", /* 1151 */
+ "munmap", /* 1152 */
+ "mlock", /* 1153 */
+ "mlockall", /* 1154 */
+ "mprotect", /* 1155 */
+ "mremap", /* 1156 */
+ "msync", /* 1157 */
+ "munlock", /* 1158 */
+ "munlockall", /* 1159 */
+ "sched_getparam", /* 1160 */
+ "sched_setparam", /* 1161 */
+ "sched_getscheduler", /* 1162 */
+ "sched_setscheduler", /* 1163 */
+ "sched_yield", /* 1164 */
+ "sched_get_priority_max", /* 1165 */
+ "sched_get_priority_min", /* 1166 */
+ "sched_rr_get_interval", /* 1167 */
+ "nanosleep", /* 1168 */
+ "nfsservctl", /* 1169 */
+ "prctl", /* 1170 */
+ "1171", /* 1171 */
+ "mmap2", /* 1172 */
+ "pciconfig_read", /* 1173 */
+ "pciconfig_write", /* 1174 */
+ "perfmonctl", /* 1175 */
+ "sigaltstack", /* 1176 */
+ "rt_sigaction", /* 1177 */
+ "rt_sigpending", /* 1178 */
+ "rt_sigprocmask", /* 1179 */
+ "rt_sigqueueinfo", /* 1180 */
+ "rt_sigreturn", /* 1181 */
+ "rt_sigsuspend", /* 1182 */
+ "rt_sigtimedwait", /* 1183 */
+ "getcwd", /* 1184 */
+ "capget", /* 1185 */
+ "capset", /* 1186 */
+ "sendfile", /* 1187 */
+ "getpmsg", /* 1188 */
+ "putpmsg", /* 1189 */
+ "socket", /* 1190 */
+ "bind", /* 1191 */
+ "connect", /* 1192 */
+ "listen", /* 1193 */
+ "accept", /* 1194 */
+ "getsockname", /* 1195 */
+ "getpeername", /* 1196 */
+ "socketpair", /* 1197 */
+ "send", /* 1198 */
+ "sendto", /* 1199 */
+ "recv", /* 1200 */
+ "recvfrom", /* 1201 */
+ "shutdown", /* 1202 */
+ "setsockopt", /* 1203 */
+ "getsockopt", /* 1204 */
+ "sendmsg", /* 1205 */
+ "recvmsg", /* 1206 */
+ "pivot_root", /* 1207 */
+ "mincore", /* 1208 */
+ "madvise", /* 1209 */
+ "stat", /* 1210 */
+ "lstat", /* 1211 */
+ "fstat", /* 1212 */
+ "clone2", /* 1213 */
+ "getdents64", /* 1214 */
+ "getunwind", /* 1215 */
+ "readahead", /* 1216 */
+ "setxattr", /* 1217 */
+ "lsetxattr", /* 1218 */
+ "fsetxattr", /* 1219 */
+ "getxattr", /* 1220 */
+ "lgetxattr", /* 1221 */
+ "fgetxattr", /* 1222 */
+ "listxattr", /* 1223 */
+ "llistxattr", /* 1224 */
+ "flistxattr", /* 1225 */
+ "removexattr", /* 1226 */
+ "lremovexattr", /* 1227 */
+ "fremovexattr", /* 1228 */
+ "tkill", /* 1229 */
+ "futex", /* 1230 */
+ "sched_setaffinity", /* 1231 */
+ "sched_getaffinity", /* 1232 */
+ "set_tid_address", /* 1233 */
+ "fadvise64", /* 1234 */
+ "tgkill", /* 1235 */
+ "exit_group", /* 1236 */
+ "lookup_dcookie", /* 1237 */
+ "io_setup", /* 1238 */
+ "io_destroy", /* 1239 */
+ "io_getevents", /* 1240 */
+ "io_submit", /* 1241 */
+ "io_cancel", /* 1242 */
+ "epoll_create", /* 1243 */
+ "epoll_ctl", /* 1244 */
+ "epoll_wait", /* 1245 */
+ "restart_syscall", /* 1246 */
+ "semtimedop", /* 1247 */
+ "timer_create", /* 1248 */
+ "timer_settime", /* 1249 */
+ "timer_gettime", /* 1250 */
+ "timer_getoverrun", /* 1251 */
+ "timer_delete", /* 1252 */
+ "clock_settime", /* 1253 */
+ "clock_gettime", /* 1254 */
+ "clock_getres", /* 1255 */
+ "clock_nanosleep", /* 1256 */
+ "fstatfs64", /* 1257 */
+ "statfs64", /* 1258 */
+ "mbind", /* 1259 */
+ "get_mempolicy", /* 1260 */
+ "set_mempolicy", /* 1261 */
+ "mq_open", /* 1262 */
+ "mq_unlink", /* 1263 */
+ "mq_timedsend", /* 1264 */
+ "mq_timedreceive", /* 1265 */
+ "mq_notify", /* 1266 */
+ "mq_getsetattr", /* 1267 */
+ "kexec_load", /* 1268 */
+ "vserver", /* 1269 */
+ "waitid", /* 1270 */
+ "add_key", /* 1271 */
+ "request_key", /* 1272 */
+ "keyctl", /* 1273 */
+ "ioprio_set", /* 1274 */
+ "ioprio_get", /* 1275 */
+ "1276", /* 1276 */
+ "inotify_init", /* 1277 */
+ "inotify_add_watch", /* 1278 */
+ "inotify_rm_watch", /* 1279 */
+ "migrate_pages", /* 1280 */
+ "openat", /* 1281 */
+ "mkdirat", /* 1282 */
+ "mknodat", /* 1283 */
+ "fchownat", /* 1284 */
+ "futimesat", /* 1285 */
+ "newfstatat", /* 1286 */
+ "unlinkat", /* 1287 */
+ "renameat", /* 1288 */
+ "linkat", /* 1289 */
+ "symlinkat", /* 1290 */
+ "readlinkat", /* 1291 */
+ "fchmodat", /* 1292 */
+ "faccessat", /* 1293 */
+ "1294", /* 1294 */
+ "1295", /* 1295 */
+ "unshare", /* 1296 */
+ "splice", /* 1297 */
+ "set_robust_list", /* 1298 */
+ "get_robust_list", /* 1299 */
+ "sync_file_range", /* 1300 */
+ "tee", /* 1301 */
+ "vmsplice", /* 1302 */
diff --git a/sysdeps/linux-gnu/ia64/trace.c b/sysdeps/linux-gnu/ia64/trace.c
new file mode 100644
index 0000000..799e0ff
--- /dev/null
+++ b/sysdeps/linux-gnu/ia64/trace.c
@@ -0,0 +1,268 @@
+#include "config.h"
+
+#include <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
index 0000000..60d7531
--- /dev/null
+++ b/sysdeps/linux-gnu/m68k/Makefile
@@ -0,0 +1,10 @@
+OBJ = trace.o regs.o plt.o
+
+all: arch.o
+
+arch.o: $(OBJ)
+ $(CC) -nostdlib -r -o arch.o $(OBJ)
+
+clean:
+ $(RM) $(OBJ) arch.o
+
diff --git a/sysdeps/linux-gnu/m68k/arch.h b/sysdeps/linux-gnu/m68k/arch.h
new file mode 100644
index 0000000..1790d09
--- /dev/null
+++ b/sysdeps/linux-gnu/m68k/arch.h
@@ -0,0 +1,6 @@
+#define BREAKPOINT_VALUE { 0x4e, 0x4f }
+#define BREAKPOINT_LENGTH 2
+#define DECR_PC_AFTER_BREAK 2
+
+#define LT_ELFCLASS ELFCLASS32
+#define LT_ELF_MACHINE EM_68K
diff --git a/sysdeps/linux-gnu/m68k/plt.c b/sysdeps/linux-gnu/m68k/plt.c
new file mode 100644
index 0000000..508d7fc
--- /dev/null
+++ b/sysdeps/linux-gnu/m68k/plt.c
@@ -0,0 +1,13 @@
+#include <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
index 0000000..c3cbcb6
--- /dev/null
+++ b/sysdeps/linux-gnu/m68k/ptrace.h
@@ -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
index 0000000..959a60e
--- /dev/null
+++ b/sysdeps/linux-gnu/m68k/regs.c
@@ -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
index 0000000..5395f82
--- /dev/null
+++ b/sysdeps/linux-gnu/m68k/signalent.h
@@ -0,0 +1,32 @@
+ "SIG_0", /* 0 */
+ "SIGHUP", /* 1 */
+ "SIGINT", /* 2 */
+ "SIGQUIT", /* 3 */
+ "SIGILL", /* 4 */
+ "SIGTRAP", /* 5 */
+ "SIGABRT", /* 6 */
+ "SIGBUS", /* 7 */
+ "SIGFPE", /* 8 */
+ "SIGKILL", /* 9 */
+ "SIGUSR1", /* 10 */
+ "SIGSEGV", /* 11 */
+ "SIGUSR2", /* 12 */
+ "SIGPIPE", /* 13 */
+ "SIGALRM", /* 14 */
+ "SIGTERM", /* 15 */
+ "SIGSTKFLT", /* 16 */
+ "SIGCHLD", /* 17 */
+ "SIGCONT", /* 18 */
+ "SIGSTOP", /* 19 */
+ "SIGTSTP", /* 20 */
+ "SIGTTIN", /* 21 */
+ "SIGTTOU", /* 22 */
+ "SIGURG", /* 23 */
+ "SIGXCPU", /* 24 */
+ "SIGXFSZ", /* 25 */
+ "SIGVTALRM", /* 26 */
+ "SIGPROF", /* 27 */
+ "SIGWINCH", /* 28 */
+ "SIGIO", /* 29 */
+ "SIGPWR", /* 30 */
+ "SIGSYS", /* 31 */
diff --git a/sysdeps/linux-gnu/m68k/syscallent.h b/sysdeps/linux-gnu/m68k/syscallent.h
new file mode 100644
index 0000000..4d65b39
--- /dev/null
+++ b/sysdeps/linux-gnu/m68k/syscallent.h
@@ -0,0 +1,282 @@
+ "0", /* 0 */
+ "exit", /* 1 */
+ "fork", /* 2 */
+ "read", /* 3 */
+ "write", /* 4 */
+ "open", /* 5 */
+ "close", /* 6 */
+ "waitpid", /* 7 */
+ "creat", /* 8 */
+ "link", /* 9 */
+ "unlink", /* 10 */
+ "execve", /* 11 */
+ "chdir", /* 12 */
+ "time", /* 13 */
+ "mknod", /* 14 */
+ "chmod", /* 15 */
+ "chown", /* 16 */
+ "break", /* 17 */
+ "oldstat", /* 18 */
+ "lseek", /* 19 */
+ "getpid", /* 20 */
+ "mount", /* 21 */
+ "umount", /* 22 */
+ "setuid", /* 23 */
+ "getuid", /* 24 */
+ "stime", /* 25 */
+ "ptrace", /* 26 */
+ "alarm", /* 27 */
+ "oldfstat", /* 28 */
+ "pause", /* 29 */
+ "utime", /* 30 */
+ "stty", /* 31 */
+ "gtty", /* 32 */
+ "access", /* 33 */
+ "nice", /* 34 */
+ "ftime", /* 35 */
+ "sync", /* 36 */
+ "kill", /* 37 */
+ "rename", /* 38 */
+ "mkdir", /* 39 */
+ "rmdir", /* 40 */
+ "dup", /* 41 */
+ "pipe", /* 42 */
+ "times", /* 43 */
+ "prof", /* 44 */
+ "brk", /* 45 */
+ "setgid", /* 46 */
+ "getgid", /* 47 */
+ "signal", /* 48 */
+ "geteuid", /* 49 */
+ "getegid", /* 50 */
+ "acct", /* 51 */
+ "umount2", /* 52 */
+ "lock", /* 53 */
+ "ioctl", /* 54 */
+ "fcntl", /* 55 */
+ "mpx", /* 56 */
+ "setpgid", /* 57 */
+ "ulimit", /* 58 */
+ "oldolduname", /* 59 */
+ "umask", /* 60 */
+ "chroot", /* 61 */
+ "ustat", /* 62 */
+ "dup2", /* 63 */
+ "getppid", /* 64 */
+ "getpgrp", /* 65 */
+ "setsid", /* 66 */
+ "sigaction", /* 67 */
+ "sgetmask", /* 68 */
+ "ssetmask", /* 69 */
+ "setreuid", /* 70 */
+ "setregid", /* 71 */
+ "sigsuspend", /* 72 */
+ "sigpending", /* 73 */
+ "sethostname", /* 74 */
+ "setrlimit", /* 75 */
+ "getrlimit", /* 76 */
+ "getrusage", /* 77 */
+ "gettimeofday", /* 78 */
+ "settimeofday", /* 79 */
+ "getgroups", /* 80 */
+ "setgroups", /* 81 */
+ "select", /* 82 */
+ "symlink", /* 83 */
+ "oldlstat", /* 84 */
+ "readlink", /* 85 */
+ "uselib", /* 86 */
+ "swapon", /* 87 */
+ "reboot", /* 88 */
+ "readdir", /* 89 */
+ "mmap", /* 90 */
+ "munmap", /* 91 */
+ "truncate", /* 92 */
+ "ftruncate", /* 93 */
+ "fchmod", /* 94 */
+ "fchown", /* 95 */
+ "getpriority", /* 96 */
+ "setpriority", /* 97 */
+ "profil", /* 98 */
+ "statfs", /* 99 */
+ "fstatfs", /* 100 */
+ "ioperm", /* 101 */
+ "socketcall", /* 102 */
+ "syslog", /* 103 */
+ "setitimer", /* 104 */
+ "getitimer", /* 105 */
+ "stat", /* 106 */
+ "lstat", /* 107 */
+ "fstat", /* 108 */
+ "olduname", /* 109 */
+ "110", /* 110 */
+ "vhangup", /* 111 */
+ "112", /* 112 */
+ "113", /* 113 */
+ "wait4", /* 114 */
+ "swapoff", /* 115 */
+ "sysinfo", /* 116 */
+ "ipc", /* 117 */
+ "fsync", /* 118 */
+ "sigreturn", /* 119 */
+ "clone", /* 120 */
+ "setdomainname", /* 121 */
+ "uname", /* 122 */
+ "cacheflush", /* 123 */
+ "adjtimex", /* 124 */
+ "mprotect", /* 125 */
+ "sigprocmask", /* 126 */
+ "create_module", /* 127 */
+ "init_module", /* 128 */
+ "delete_module", /* 129 */
+ "get_kernel_syms", /* 130 */
+ "quotactl", /* 131 */
+ "getpgid", /* 132 */
+ "fchdir", /* 133 */
+ "bdflush", /* 134 */
+ "sysfs", /* 135 */
+ "personality", /* 136 */
+ "afs_syscall", /* 137 */
+ "setfsuid", /* 138 */
+ "setfsgid", /* 139 */
+ "_llseek", /* 140 */
+ "getdents", /* 141 */
+ "_newselect", /* 142 */
+ "flock", /* 143 */
+ "msync", /* 144 */
+ "readv", /* 145 */
+ "writev", /* 146 */
+ "getsid", /* 147 */
+ "fdatasync", /* 148 */
+ "_sysctl", /* 149 */
+ "mlock", /* 150 */
+ "munlock", /* 151 */
+ "mlockall", /* 152 */
+ "munlockall", /* 153 */
+ "sched_setparam", /* 154 */
+ "sched_getparam", /* 155 */
+ "sched_setscheduler", /* 156 */
+ "sched_getscheduler", /* 157 */
+ "sched_yield", /* 158 */
+ "sched_get_priority_max", /* 159 */
+ "sched_get_priority_min", /* 160 */
+ "sched_rr_get_interval", /* 161 */
+ "nanosleep", /* 162 */
+ "mremap", /* 163 */
+ "setresuid", /* 164 */
+ "getresuid", /* 165 */
+ "getpagesize", /* 166 */
+ "query_module", /* 167 */
+ "poll", /* 168 */
+ "nfsservctl", /* 169 */
+ "setresgid", /* 170 */
+ "getresgid", /* 171 */
+ "prctl", /* 172 */
+ "rt_sigreturn", /* 173 */
+ "rt_sigaction", /* 174 */
+ "rt_sigprocmask", /* 175 */
+ "rt_sigpending", /* 176 */
+ "rt_sigtimedwait", /* 177 */
+ "rt_sigqueueinfo", /* 178 */
+ "rt_sigsuspend", /* 179 */
+ "pread64", /* 180 */
+ "pwrite64", /* 181 */
+ "lchown", /* 182 */
+ "getcwd", /* 183 */
+ "capget", /* 184 */
+ "capset", /* 185 */
+ "sigaltstack", /* 186 */
+ "sendfile", /* 187 */
+ "getpmsg", /* 188 */
+ "putpmsg", /* 189 */
+ "vfork", /* 190 */
+ "ugetrlimit", /* 191 */
+ "mmap2", /* 192 */
+ "truncate64", /* 193 */
+ "ftruncate64", /* 194 */
+ "stat64", /* 195 */
+ "lstat64", /* 196 */
+ "fstat64", /* 197 */
+ "chown32", /* 198 */
+ "getuid32", /* 199 */
+ "getgid32", /* 200 */
+ "geteuid32", /* 201 */
+ "getegid32", /* 202 */
+ "setreuid32", /* 203 */
+ "setregid32", /* 204 */
+ "getgroups32", /* 205 */
+ "setgroups32", /* 206 */
+ "fchown32", /* 207 */
+ "setresuid32", /* 208 */
+ "getresuid32", /* 209 */
+ "setresgid32", /* 210 */
+ "getresgid32", /* 211 */
+ "lchown32", /* 212 */
+ "setuid32", /* 213 */
+ "setgid32", /* 214 */
+ "setfsuid32", /* 215 */
+ "setfsgid32", /* 216 */
+ "pivot_root", /* 217 */
+ "218", /* 218 */
+ "219", /* 219 */
+ "getdents64", /* 220 */
+ "gettid", /* 221 */
+ "tkill", /* 222 */
+ "setxattr", /* 223 */
+ "lsetxattr", /* 224 */
+ "fsetxattr", /* 225 */
+ "getxattr", /* 226 */
+ "lgetxattr", /* 227 */
+ "fgetxattr", /* 228 */
+ "listxattr", /* 229 */
+ "llistxattr", /* 230 */
+ "flistxattr", /* 231 */
+ "removexattr", /* 232 */
+ "lremovexattr", /* 233 */
+ "fremovexattr", /* 234 */
+ "futex", /* 235 */
+ "sendfile64", /* 236 */
+ "mincore", /* 237 */
+ "madvise", /* 238 */
+ "fcntl64", /* 239 */
+ "readahead", /* 240 */
+ "io_setup", /* 241 */
+ "io_destroy", /* 242 */
+ "io_getevents", /* 243 */
+ "io_submit", /* 244 */
+ "io_cancel", /* 245 */
+ "fadvise64", /* 246 */
+ "exit_group", /* 247 */
+ "lookup_dcookie", /* 248 */
+ "epoll_create", /* 249 */
+ "epoll_ctl", /* 250 */
+ "epoll_wait", /* 251 */
+ "remap_file_pages", /* 252 */
+ "set_tid_address", /* 253 */
+ "timer_create", /* 254 */
+ "timer_settime", /* 255 */
+ "timer_gettime", /* 256 */
+ "timer_getoverrun", /* 257 */
+ "timer_delete", /* 258 */
+ "clock_settime", /* 259 */
+ "clock_gettime", /* 260 */
+ "clock_getres", /* 261 */
+ "clock_nanosleep", /* 262 */
+ "statfs64", /* 263 */
+ "fstatfs64", /* 264 */
+ "tgkill", /* 265 */
+ "utimes", /* 266 */
+ "fadvise64_64", /* 267 */
+ "mbind", /* 268 */
+ "get_mempolicy", /* 269 */
+ "set_mempolicy", /* 270 */
+ "mq_open", /* 271 */
+ "mq_unlink", /* 272 */
+ "mq_timedsend", /* 273 */
+ "mq_timedreceive", /* 274 */
+ "mq_notify", /* 275 */
+ "mq_getsetattr", /* 276 */
+ "waitid", /* 277 */
+ "vserver", /* 278 */
+ "add_key", /* 279 */
+ "request_key", /* 280 */
+ "keyctl", /* 281 */
diff --git a/sysdeps/linux-gnu/m68k/trace.c b/sysdeps/linux-gnu/m68k/trace.c
new file mode 100644
index 0000000..2f89fdf
--- /dev/null
+++ b/sysdeps/linux-gnu/m68k/trace.c
@@ -0,0 +1,89 @@
+#include "config.h"
+
+#include <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
index 0000000..b4f5eb2
--- /dev/null
+++ b/sysdeps/linux-gnu/mipsel/Doxyfile
@@ -0,0 +1,275 @@
+# Doxyfile 1.5.1
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+PROJECT_NAME = ltrace-mipsel
+PROJECT_NUMBER =
+OUTPUT_DIRECTORY =
+CREATE_SUBDIRS = NO
+OUTPUT_LANGUAGE = English
+USE_WINDOWS_ENCODING = NO
+BRIEF_MEMBER_DESC = YES
+REPEAT_BRIEF = YES
+ABBREVIATE_BRIEF = "The $name class" \
+ "The $name widget" \
+ "The $name file" \
+ is \
+ provides \
+ specifies \
+ contains \
+ represents \
+ a \
+ an \
+ the
+ALWAYS_DETAILED_SEC = NO
+INLINE_INHERITED_MEMB = NO
+FULL_PATH_NAMES = YES
+STRIP_FROM_PATH =
+STRIP_FROM_INC_PATH =
+SHORT_NAMES = NO
+JAVADOC_AUTOBRIEF = NO
+MULTILINE_CPP_IS_BRIEF = NO
+DETAILS_AT_TOP = NO
+INHERIT_DOCS = YES
+SEPARATE_MEMBER_PAGES = NO
+TAB_SIZE = 8
+ALIASES =
+OPTIMIZE_OUTPUT_FOR_C = NO
+OPTIMIZE_OUTPUT_JAVA = NO
+BUILTIN_STL_SUPPORT = NO
+DISTRIBUTE_GROUP_DOC = NO
+SUBGROUPING = YES
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+EXTRACT_ALL = YES
+EXTRACT_PRIVATE = YES
+EXTRACT_STATIC = YES
+EXTRACT_LOCAL_CLASSES = YES
+EXTRACT_LOCAL_METHODS = YES
+HIDE_UNDOC_MEMBERS = NO
+HIDE_UNDOC_CLASSES = NO
+HIDE_FRIEND_COMPOUNDS = NO
+HIDE_IN_BODY_DOCS = NO
+INTERNAL_DOCS = NO
+CASE_SENSE_NAMES = YES
+HIDE_SCOPE_NAMES = NO
+SHOW_INCLUDE_FILES = YES
+INLINE_INFO = YES
+SORT_MEMBER_DOCS = YES
+SORT_BRIEF_DOCS = YES
+SORT_BY_SCOPE_NAME = YES
+GENERATE_TODOLIST = YES
+GENERATE_TESTLIST = YES
+GENERATE_BUGLIST = YES
+GENERATE_DEPRECATEDLIST= YES
+ENABLED_SECTIONS =
+MAX_INITIALIZER_LINES = 30
+SHOW_USED_FILES = YES
+SHOW_DIRECTORIES = NO
+FILE_VERSION_FILTER =
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+QUIET = NO
+WARNINGS = YES
+WARN_IF_UNDOCUMENTED = YES
+WARN_IF_DOC_ERROR = YES
+WARN_NO_PARAMDOC = NO
+WARN_FORMAT = "$file:$line: $text"
+WARN_LOGFILE =
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+INPUT = .
+FILE_PATTERNS = *.c \
+ *.cc \
+ *.cxx \
+ *.cpp \
+ *.c++ \
+ *.d \
+ *.java \
+ *.ii \
+ *.ixx \
+ *.ipp \
+ *.i++ \
+ *.inl \
+ *.h \
+ *.hh \
+ *.hxx \
+ *.hpp \
+ *.h++ \
+ *.idl \
+ *.odl \
+ *.cs \
+ *.php \
+ *.php3 \
+ *.inc \
+ *.m \
+ *.mm \
+ *.dox \
+ *.py \
+ *.C \
+ *.CC \
+ *.C++ \
+ *.II \
+ *.I++ \
+ *.H \
+ *.HH \
+ *.H++ \
+ *.CS \
+ *.PHP \
+ *.PHP3 \
+ *.M \
+ *.MM \
+ *.PY
+RECURSIVE = NO
+EXCLUDE =
+EXCLUDE_SYMLINKS = NO
+EXCLUDE_PATTERNS =
+EXAMPLE_PATH =
+EXAMPLE_PATTERNS = *
+EXAMPLE_RECURSIVE = NO
+IMAGE_PATH =
+INPUT_FILTER =
+FILTER_PATTERNS =
+FILTER_SOURCE_FILES = NO
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+SOURCE_BROWSER = YES
+INLINE_SOURCES = YES
+STRIP_CODE_COMMENTS = YES
+REFERENCED_BY_RELATION = YES
+REFERENCES_RELATION = YES
+REFERENCES_LINK_SOURCE = YES
+USE_HTAGS = NO
+VERBATIM_HEADERS = YES
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+ALPHABETICAL_INDEX = NO
+COLS_IN_ALPHA_INDEX = 5
+IGNORE_PREFIX =
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+GENERATE_HTML = YES
+HTML_OUTPUT = html
+HTML_FILE_EXTENSION = .html
+HTML_HEADER =
+HTML_FOOTER =
+HTML_STYLESHEET =
+HTML_ALIGN_MEMBERS = YES
+GENERATE_HTMLHELP = NO
+CHM_FILE =
+HHC_LOCATION =
+GENERATE_CHI = NO
+BINARY_TOC = NO
+TOC_EXPAND = NO
+DISABLE_INDEX = NO
+ENUM_VALUES_PER_LINE = 4
+GENERATE_TREEVIEW = NO
+TREEVIEW_WIDTH = 250
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+GENERATE_LATEX = NO
+LATEX_OUTPUT = latex
+LATEX_CMD_NAME = latex
+MAKEINDEX_CMD_NAME = makeindex
+COMPACT_LATEX = NO
+PAPER_TYPE = a4wide
+EXTRA_PACKAGES =
+LATEX_HEADER =
+PDF_HYPERLINKS = NO
+USE_PDFLATEX = NO
+LATEX_BATCHMODE = NO
+LATEX_HIDE_INDICES = NO
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+GENERATE_RTF = NO
+RTF_OUTPUT = rtf
+COMPACT_RTF = NO
+RTF_HYPERLINKS = NO
+RTF_STYLESHEET_FILE =
+RTF_EXTENSIONS_FILE =
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+GENERATE_MAN = NO
+MAN_OUTPUT = man
+MAN_EXTENSION = .3
+MAN_LINKS = NO
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+GENERATE_XML = NO
+XML_OUTPUT = xml
+XML_SCHEMA =
+XML_DTD =
+XML_PROGRAMLISTING = YES
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+GENERATE_AUTOGEN_DEF = NO
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+GENERATE_PERLMOD = NO
+PERLMOD_LATEX = NO
+PERLMOD_PRETTY = YES
+PERLMOD_MAKEVAR_PREFIX =
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+ENABLE_PREPROCESSING = YES
+MACRO_EXPANSION = NO
+EXPAND_ONLY_PREDEF = NO
+SEARCH_INCLUDES = YES
+INCLUDE_PATH =
+INCLUDE_FILE_PATTERNS =
+PREDEFINED =
+EXPAND_AS_DEFINED =
+SKIP_FUNCTION_MACROS = YES
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+TAGFILES =
+GENERATE_TAGFILE =
+ALLEXTERNALS = NO
+EXTERNAL_GROUPS = YES
+PERL_PATH = /usr/bin/perl
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+CLASS_DIAGRAMS = YES
+HIDE_UNDOC_RELATIONS = YES
+HAVE_DOT = YES
+CLASS_GRAPH = YES
+COLLABORATION_GRAPH = YES
+GROUP_GRAPHS = YES
+UML_LOOK = YES
+TEMPLATE_RELATIONS = YES
+INCLUDE_GRAPH = YES
+INCLUDED_BY_GRAPH = YES
+CALL_GRAPH = YES
+CALLER_GRAPH = YES
+GRAPHICAL_HIERARCHY = YES
+DIRECTORY_GRAPH = YES
+DOT_IMAGE_FORMAT = png
+DOT_PATH =
+DOTFILE_DIRS =
+MAX_DOT_GRAPH_WIDTH = 1024
+MAX_DOT_GRAPH_HEIGHT = 1024
+MAX_DOT_GRAPH_DEPTH = 1000
+DOT_TRANSPARENT = NO
+DOT_MULTI_TARGETS = NO
+GENERATE_LEGEND = YES
+DOT_CLEANUP = NO
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine
+#---------------------------------------------------------------------------
+SEARCHENGINE = NO
diff --git a/sysdeps/linux-gnu/mipsel/Makefile b/sysdeps/linux-gnu/mipsel/Makefile
new file mode 100644
index 0000000..44f4aae
--- /dev/null
+++ b/sysdeps/linux-gnu/mipsel/Makefile
@@ -0,0 +1,22 @@
+.PHONY: all deps clean docs
+
+OBJ = trace.o regs.o plt.o
+SRC=$(OBJ:.o=.c)
+
+all: arch.o
+
+deps:
+ $(CC) $(CFLAGS) $(CPPFLAGS) -M $(SRC) > .depends
+
+arch.o: $(OBJ) arch.h
+ $(CC) -nostdlib -r -o arch.o $(OBJ)
+
+clean:
+ -rm -f $(OBJ) arch.o
+ -rm -rf html
+
+docs:
+ doxygen
+
+
+-include .depends
diff --git a/sysdeps/linux-gnu/mipsel/arch.h b/sysdeps/linux-gnu/mipsel/arch.h
new file mode 100644
index 0000000..dd0ca35
--- /dev/null
+++ b/sysdeps/linux-gnu/mipsel/arch.h
@@ -0,0 +1,9 @@
+#define BREAKPOINT_VALUE { 0x0d, 0x00, 0x00, 0x00 }
+#define BREAKPOINT_LENGTH 4
+#define DECR_PC_AFTER_BREAK 0
+
+#define LT_ELFCLASS ELFCLASS32
+#define LT_ELF_MACHINE EM_MIPS
+
+#define PLTs_INIT_BY_HERE "_start"
+#define E_ENTRY_NAME "_start"
diff --git a/sysdeps/linux-gnu/mipsel/mipsel.h b/sysdeps/linux-gnu/mipsel/mipsel.h
new file mode 100644
index 0000000..a63cafd
--- /dev/null
+++ b/sysdeps/linux-gnu/mipsel/mipsel.h
@@ -0,0 +1,11 @@
+#ifndef MIPSEL_h
+#define MIPSEL_h
+// linux-2.4.30/arch/mips/kernel/ptrace.c for these offsets.
+#define off_v0 2
+#define off_pc 64
+#define off_a0 4
+#define off_a3 7
+#define off_lr 31
+#define off_sp 29
+
+#endif // MIPSEL_h
diff --git a/sysdeps/linux-gnu/mipsel/plt.c b/sysdeps/linux-gnu/mipsel/plt.c
new file mode 100644
index 0000000..003171b
--- /dev/null
+++ b/sysdeps/linux-gnu/mipsel/plt.c
@@ -0,0 +1,72 @@
+#include <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
index 0000000..c3cbcb6
--- /dev/null
+++ b/sysdeps/linux-gnu/mipsel/ptrace.h
@@ -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
index 0000000..a7a6de1
--- /dev/null
+++ b/sysdeps/linux-gnu/mipsel/regs.c
@@ -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
index 0000000..6bb1ff6
--- /dev/null
+++ b/sysdeps/linux-gnu/mipsel/signalent.h
@@ -0,0 +1,32 @@
+"SIG_0", /* 0 */
+ "SIGHUP", // 1 /* Hangup (POSIX). */
+ "SIGINT", // 2 /* Interrupt (ANSI). */
+ "SIGQUIT", // 3 /* Quit (POSIX). */
+ "SIGILL", // 4 /* Illegal instruction (ANSI). */
+ "SIGTRAP", // 5 /* Trace trap (POSIX). */
+ "SIGIOT", // 6 /* IOT trap (4.2 BSD). */
+ "SIGEMT", // 7
+ "SIGFPE", // 8 /* Floating-point exception (ANSI). */
+ "SIGKILL", // 9 /* Kill, unblockable (POSIX). */
+ "SIGBUS", // 10 /* BUS error (4.2 BSD). */
+ "SIGSEGV", // 11 /* Segmentation violation (ANSI). */
+ "SIGSYS", // 12
+ "SIGPIPE", // 13 /* Broken pipe (POSIX). */
+ "SIGALRM", // 14 /* Alarm clock (POSIX). */
+ "SIGTERM", // 15 /* Termination (ANSI). */
+ "SIGUSR1", // 16 /* User-defined signal 1 (POSIX). */
+ "SIGUSR2", // 17 /* User-defined signal 2 (POSIX). */
+ "SIGCHLD", // 18 /* Child status has changed (POSIX). */
+ "SIGPWR", // 19 /* Power failure restart (System V). */
+ "SIGWINCH", // 20 /* Window size change (4.3 BSD, Sun). */
+ "SIGURG", // 21 /* Urgent condition on socket (4.2 BSD). */
+ "SIGIO", // 22 /* I/O now possible (4.2 BSD). */
+ "SIGSTOP", // 23 /* Stop, unblockable (POSIX). */
+ "SIGTSTP", // 24 /* Keyboard stop (POSIX). */
+ "SIGCONT", // 25 /* Continue (POSIX). */
+ "SIGTTIN", // 26 /* Background read from tty (POSIX). */
+ "SIGTTOU", // 27 /* Background write to tty (POSIX). */
+ "SIGVTALRM", // 28 /* Virtual alarm clock (4.2 BSD). */
+ "SIGPROF", // 29 /* Profiling alarm clock (4.2 BSD). */
+ "SIGXCPU", // 30 /* CPU limit exceeded (4.2 BSD). */
+ "SIGXFSZ", // 31 /* File size limit exceeded (4.2 BSD). */
diff --git a/sysdeps/linux-gnu/mipsel/syscallent.h b/sysdeps/linux-gnu/mipsel/syscallent.h
new file mode 100644
index 0000000..bed43fe
--- /dev/null
+++ b/sysdeps/linux-gnu/mipsel/syscallent.h
@@ -0,0 +1,241 @@
+ "0", /*Linux + 0*/
+ "exit", /*Linux + 1*/
+ "fork", /*Linux + 2*/
+ "read", /*Linux + 3*/
+ "write", /*Linux + 4*/
+ "open", /*Linux + 5*/
+ "close", /*Linux + 6*/
+ "waitpid", /*Linux + 7*/
+ "creat", /*Linux + 8*/
+ "link", /*Linux + 9*/
+ "unlink", /*Linux + 10*/
+ "execve", /*Linux + 11*/
+ "chdir", /*Linux + 12*/
+ "time", /*Linux + 13*/
+ "mknod", /*Linux + 14*/
+ "chmod", /*Linux + 15*/
+ "lchown", /*Linux + 16*/
+ "break", /*Linux + 17*/
+ "unused18", /*Linux + 18*/
+ "lseek", /*Linux + 19*/
+ "getpid", /*Linux + 20*/
+ "mount", /*Linux + 21*/
+ "umount", /*Linux + 22*/
+ "setuid", /*Linux + 23*/
+ "getuid", /*Linux + 24*/
+ "stime", /*Linux + 25*/
+ "ptrace", /*Linux + 26*/
+ "alarm", /*Linux + 27*/
+ "unused28", /*Linux + 28*/
+ "pause", /*Linux + 29*/
+ "utime", /*Linux + 30*/
+ "stty", /*Linux + 31*/
+ "gtty", /*Linux + 32*/
+ "access", /*Linux + 33*/
+ "nice", /*Linux + 34*/
+ "ftime", /*Linux + 35*/
+ "sync", /*Linux + 36*/
+ "kill", /*Linux + 37*/
+ "rename", /*Linux + 38*/
+ "mkdir", /*Linux + 39*/
+ "rmdir", /*Linux + 40*/
+ "dup", /*Linux + 41*/
+ "pipe", /*Linux + 42*/
+ "times", /*Linux + 43*/
+ "prof", /*Linux + 44*/
+ "brk", /*Linux + 45*/
+ "setgid", /*Linux + 46*/
+ "getgid", /*Linux + 47*/
+ "signal", /*Linux + 48*/
+ "geteuid", /*Linux + 49*/
+ "getegid", /*Linux + 50*/
+ "acct", /*Linux + 51*/
+ "umount2", /*Linux + 52*/
+ "lock", /*Linux + 53*/
+ "ioctl", /*Linux + 54*/
+ "fcntl", /*Linux + 55*/
+ "mpx", /*Linux + 56*/
+ "setpgid", /*Linux + 57*/
+ "ulimit", /*Linux + 58*/
+ "unused59", /*Linux + 59*/
+ "umask", /*Linux + 60*/
+ "chroot", /*Linux + 61*/
+ "ustat", /*Linux + 62*/
+ "dup2", /*Linux + 63*/
+ "getppid", /*Linux + 64*/
+ "getpgrp", /*Linux + 65*/
+ "setsid", /*Linux + 66*/
+ "sigaction", /*Linux + 67*/
+ "sgetmask", /*Linux + 68*/
+ "ssetmask", /*Linux + 69*/
+ "setreuid", /*Linux + 70*/
+ "setregid", /*Linux + 71*/
+ "sigsuspend", /*Linux + 72*/
+ "sigpending", /*Linux + 73*/
+ "sethostname", /*Linux + 74*/
+ "setrlimit", /*Linux + 75*/
+ "getrlimit", /*Linux + 76*/
+ "getrusage", /*Linux + 77*/
+ "gettimeofday", /*Linux + 78*/
+ "settimeofday", /*Linux + 79*/
+ "getgroups", /*Linux + 80*/
+ "setgroups", /*Linux + 81*/
+ "reserved82", /*Linux + 82*/
+ "symlink", /*Linux + 83*/
+ "unused84", /*Linux + 84*/
+ "readlink", /*Linux + 85*/
+ "uselib", /*Linux + 86*/
+ "swapon", /*Linux + 87*/
+ "reboot", /*Linux + 88*/
+ "readdir", /*Linux + 89*/
+ "mmap", /*Linux + 90*/
+ "munmap", /*Linux + 91*/
+ "truncate", /*Linux + 92*/
+ "ftruncate", /*Linux + 93*/
+ "fchmod", /*Linux + 94*/
+ "fchown", /*Linux + 95*/
+ "getpriority", /*Linux + 96*/
+ "setpriority", /*Linux + 97*/
+ "profil", /*Linux + 98*/
+ "statfs", /*Linux + 99*/
+ "fstatfs", /*Linux + 100*/
+ "ioperm", /*Linux + 101*/
+ "socketcall", /*Linux + 102*/
+ "syslog", /*Linux + 103*/
+ "setitimer", /*Linux + 104*/
+ "getitimer", /*Linux + 105*/
+ "stat", /*Linux + 106*/
+ "lstat", /*Linux + 107*/
+ "fstat", /*Linux + 108*/
+ "unused109", /*Linux + 109*/
+ "iopl", /*Linux + 110*/
+ "vhangup", /*Linux + 111*/
+ "idle", /*Linux + 112*/
+ "vm86", /*Linux + 113*/
+ "wait4", /*Linux + 114*/
+ "swapoff", /*Linux + 115*/
+ "sysinfo", /*Linux + 116*/
+ "ipc", /*Linux + 117*/
+ "fsync", /*Linux + 118*/
+ "sigreturn", /*Linux + 119*/
+ "clone", /*Linux + 120*/
+ "setdomainname", /*Linux + 121*/
+ "uname", /*Linux + 122*/
+ "modify_ldt", /*Linux + 123*/
+ "adjtimex", /*Linux + 124*/
+ "mprotect", /*Linux + 125*/
+ "sigprocmask", /*Linux + 126*/
+ "create_module", /*Linux + 127*/
+ "init_module", /*Linux + 128*/
+ "delete_module", /*Linux + 129*/
+ "get_kernel_syms", /*Linux + 130*/
+ "quotactl", /*Linux + 131*/
+ "getpgid", /*Linux + 132*/
+ "fchdir", /*Linux + 133*/
+ "bdflush", /*Linux + 134*/
+ "sysfs", /*Linux + 135*/
+ "personality", /*Linux + 136*/
+ "afs_syscall", /*Linux + 137*/ /* Syscall for Andrew File System */
+ "setfsuid", /*Linux + 138*/
+ "setfsgid", /*Linux + 139*/
+ "_llseek", /*Linux + 140*/
+ "getdents", /*Linux + 141*/
+ "_newselect", /*Linux + 142*/
+ "flock", /*Linux + 143*/
+ "msync", /*Linux + 144*/
+ "readv", /*Linux + 145*/
+ "writev", /*Linux + 146*/
+ "cacheflush", /*Linux + 147*/
+ "cachectl", /*Linux + 148*/
+ "sysmips", /*Linux + 149*/
+ "unused150", /*Linux + 150*/
+ "getsid", /*Linux + 151*/
+ "fdatasync", /*Linux + 152*/
+ "_sysctl", /*Linux + 153*/
+ "mlock", /*Linux + 154*/
+ "munlock", /*Linux + 155*/
+ "mlockall", /*Linux + 156*/
+ "munlockall", /*Linux + 157*/
+ "sched_setparam", /*Linux + 158*/
+ "sched_getparam", /*Linux + 159*/
+ "sched_setscheduler", /*Linux + 160*/
+ "sched_getscheduler", /*Linux + 161*/
+ "sched_yield", /*Linux + 162*/
+ "sched_get_priority_max", /*Linux + 163*/
+ "sched_get_priority_min", /*Linux + 164*/
+ "sched_rr_get_interval", /*Linux + 165*/
+ "nanosleep", /*Linux + 166*/
+ "mremap", /*Linux + 167*/
+ "accept", /*Linux + 168*/
+ "bind", /*Linux + 169*/
+ "connect", /*Linux + 170*/
+ "getpeername", /*Linux + 171*/
+ "getsockname", /*Linux + 172*/
+ "getsockopt", /*Linux + 173*/
+ "listen", /*Linux + 174*/
+ "recv", /*Linux + 175*/
+ "recvfrom", /*Linux + 176*/
+ "recvmsg", /*Linux + 177*/
+ "send", /*Linux + 178*/
+ "sendmsg", /*Linux + 179*/
+ "sendto", /*Linux + 180*/
+ "setsockopt", /*Linux + 181*/
+ "shutdown", /*Linux + 182*/
+ "socket", /*Linux + 183*/
+ "socketpair", /*Linux + 184*/
+ "setresuid", /*Linux + 185*/
+ "getresuid", /*Linux + 186*/
+ "query_module", /*Linux + 187*/
+ "poll", /*Linux + 188*/
+ "nfsservctl", /*Linux + 189*/
+ "setresgid", /*Linux + 190*/
+ "getresgid", /*Linux + 191*/
+ "prctl", /*Linux + 192*/
+ "rt_sigreturn", /*Linux + 193*/
+ "rt_sigaction", /*Linux + 194*/
+ "rt_sigprocmask", /*Linux + 195*/
+ "rt_sigpending", /*Linux + 196*/
+ "rt_sigtimedwait", /*Linux + 197*/
+ "rt_sigqueueinfo", /*Linux + 198*/
+ "rt_sigsuspend", /*Linux + 199*/
+ "pread", /*Linux + 200*/
+ "pwrite", /*Linux + 201*/
+ "chown", /*Linux + 202*/
+ "getcwd", /*Linux + 203*/
+ "capget", /*Linux + 204*/
+ "capset", /*Linux + 205*/
+ "sigaltstack", /*Linux + 206*/
+ "sendfile", /*Linux + 207*/
+ "getpmsg", /*Linux + 208*/
+ "putpmsg", /*Linux + 209*/
+ "mmap2", /*Linux + 210*/
+ "truncate64", /*Linux + 211*/
+ "ftruncate64", /*Linux + 212*/
+ "stat64", /*Linux + 213*/
+ "lstat64", /*Linux + 214*/
+ "fstat64", /*Linux + 215*/
+ "pivot_root", /*Linux + 216*/
+ "mincore", /*Linux + 217*/
+ "madvise", /*Linux + 218*/
+ "getdents64", /*Linux + 219*/
+ "fcntl64", /*Linux + 220*/
+ "security", /*Linux + 221*/
+ "gettid", /*Linux + 222*/
+ "readahead", /*Linux + 223*/
+ "setxattr", /*Linux + 224*/
+ "lsetxattr", /*Linux + 225*/
+ "fsetxattr", /*Linux + 226*/
+ "getxattr", /*Linux + 227*/
+ "lgetxattr", /*Linux + 228*/
+ "fgetxattr", /*Linux + 229*/
+ "listxattr", /*Linux + 230*/
+ "llistxattr", /*Linux + 231*/
+ "flistxattr", /*Linux + 232*/
+ "removexattr", /*Linux + 233*/
+ "lremovexattr", /*Linux + 234*/
+ "fremovexattr", /*Linux + 235*/
+ "tkill", /*Linux + 236*/
+ "sendfile64", /*Linux + 237*/
+ "futex", /*Linux + 238*/
+ "sched_setaffinity", /*Linux + 239*/
+ "sched_getaffinity", /*Linux + 240*/
diff --git a/sysdeps/linux-gnu/mipsel/trace.c b/sysdeps/linux-gnu/mipsel/trace.c
new file mode 100644
index 0000000..ff94930
--- /dev/null
+++ b/sysdeps/linux-gnu/mipsel/trace.c
@@ -0,0 +1,167 @@
+#include "config.h"
+
+#include <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
index 0000000..316d81f
--- /dev/null
+++ b/sysdeps/linux-gnu/mksignalent
@@ -0,0 +1,33 @@
+#!/usr/bin/awk -f
+
+# hack expression to generate arch/signalent.h from <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
index 0000000..e0c3ec7
--- /dev/null
+++ b/sysdeps/linux-gnu/mksyscallent
@@ -0,0 +1,45 @@
+#!/usr/bin/awk -f
+
+# hack expression to generate arch/syscallent.h from <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
index 0000000..73416d9
--- /dev/null
+++ b/sysdeps/linux-gnu/mksyscallent_s390
@@ -0,0 +1,38 @@
+#!/usr/bin/perl
+#
+# Generate syscall table for s390/s390x
+#
+# Use this on arch/s390/kernel/syscall.s after removing the first few
+# nonsyscall lines.
+#
+# cat syscall.s | mksyscallent_s390 > syscalls31.h
+# cat syscall.s | mksyscallent_s390 -x > syscalls64.h
+#
+
+use Getopt::Std;
+use integer;
+getopts('x');
+$i = 0;
+$s390x = 0;
+$opt_x and $s390x = 1;
+
+while (<>) {
+ chomp;
+
+ if ($s390x==1) {
+ s/^SYSCALL\([^,]*,//;
+ } else {
+ s/^SYSCALL\(//;
+ }
+
+ s/,.*//;
+ s/^sys_//;
+ s/^s390[x]*_//;
+ s/_glue$//;
+ s/^ni_syscall.*/$i/i;
+ $len = 32 - length();
+ $tab = $len / 8;
+ $space = $len % 8;
+ print " \"$_\"," ," " x $space , "\t" x $tab, " \/* $i \*\/\n";
+ $i++;
+}
diff --git a/sysdeps/linux-gnu/ppc/Makefile b/sysdeps/linux-gnu/ppc/Makefile
new file mode 100644
index 0000000..60d7531
--- /dev/null
+++ b/sysdeps/linux-gnu/ppc/Makefile
@@ -0,0 +1,10 @@
+OBJ = trace.o regs.o plt.o
+
+all: arch.o
+
+arch.o: $(OBJ)
+ $(CC) -nostdlib -r -o arch.o $(OBJ)
+
+clean:
+ $(RM) $(OBJ) arch.o
+
diff --git a/sysdeps/linux-gnu/ppc/arch.h b/sysdeps/linux-gnu/ppc/arch.h
new file mode 100644
index 0000000..711b4a3
--- /dev/null
+++ b/sysdeps/linux-gnu/ppc/arch.h
@@ -0,0 +1,24 @@
+#define BREAKPOINT_VALUE { 0x7f, 0xe0, 0x00, 0x08 }
+#define BREAKPOINT_LENGTH 4
+#define DECR_PC_AFTER_BREAK 0
+
+#define LT_ELFCLASS ELFCLASS32
+#define LT_ELF_MACHINE EM_PPC
+
+#ifdef __powerpc64__ // Says 'ltrace' is 64 bits, says nothing about target.
+#define LT_ELFCLASS2 ELFCLASS64
+#define LT_ELF_MACHINE2 EM_PPC64
+#define ARCH_SUPPORTS_OPD
+#endif
+
+#define PLT_REINITALISATION_BP "_start"
+
+/* Start of arch-specific functions. */
+#define ARCH_HAVE_UMOVELONG
+
+#define PPC_NOP { 0x60, 0x00, 0x00, 0x00 }
+#define PPC_NOP_LENGTH 4
+
+#if (PPC_NOP_LENGTH != BREAKPOINT_LENGTH)
+#error "Length of the breakpoint value not equal to the length of a nop instruction"
+#endif
diff --git a/sysdeps/linux-gnu/ppc/plt.c b/sysdeps/linux-gnu/ppc/plt.c
new file mode 100644
index 0000000..31830fb
--- /dev/null
+++ b/sysdeps/linux-gnu/ppc/plt.c
@@ -0,0 +1,54 @@
+#include <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
index 0000000..c3cbcb6
--- /dev/null
+++ b/sysdeps/linux-gnu/ppc/ptrace.h
@@ -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
index 0000000..eca58ff
--- /dev/null
+++ b/sysdeps/linux-gnu/ppc/regs.c
@@ -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
index 0000000..d58a36c
--- /dev/null
+++ b/sysdeps/linux-gnu/ppc/signalent.h
@@ -0,0 +1,32 @@
+"SIG_0", /* 0 */
+ "SIGHUP", /* 1 */
+ "SIGINT", /* 2 */
+ "SIGQUIT", /* 3 */
+ "SIGILL", /* 4 */
+ "SIGTRAP", /* 5 */
+ "SIGABRT", /* 6 */
+ "SIGBUS", /* 7 */
+ "SIGFPE", /* 8 */
+ "SIGKILL", /* 9 */
+ "SIGUSR1", /* 10 */
+ "SIGSEGV", /* 11 */
+ "SIGUSR2", /* 12 */
+ "SIGPIPE", /* 13 */
+ "SIGALRM", /* 14 */
+ "SIGTERM", /* 15 */
+ "SIGSTKFLT", /* 16 */
+ "SIGCHLD", /* 17 */
+ "SIGCONT", /* 18 */
+ "SIGSTOP", /* 19 */
+ "SIGTSTP", /* 20 */
+ "SIGTTIN", /* 21 */
+ "SIGTTOU", /* 22 */
+ "SIGURG", /* 23 */
+ "SIGXCPU", /* 24 */
+ "SIGXFSZ", /* 25 */
+ "SIGVTALRM", /* 26 */
+ "SIGPROF", /* 27 */
+ "SIGWINCH", /* 28 */
+ "SIGIO", /* 29 */
+ "SIGPWR", /* 30 */
+ "SIGSYS", /* 31 */
diff --git a/sysdeps/linux-gnu/ppc/syscallent.h b/sysdeps/linux-gnu/ppc/syscallent.h
new file mode 100644
index 0000000..5ce5739
--- /dev/null
+++ b/sysdeps/linux-gnu/ppc/syscallent.h
@@ -0,0 +1,272 @@
+"0", /* 0 */
+ "exit", /* 1 */
+ "fork", /* 2 */
+ "read", /* 3 */
+ "write", /* 4 */
+ "open", /* 5 */
+ "close", /* 6 */
+ "waitpid", /* 7 */
+ "creat", /* 8 */
+ "link", /* 9 */
+ "unlink", /* 10 */
+ "execve", /* 11 */
+ "chdir", /* 12 */
+ "time", /* 13 */
+ "mknod", /* 14 */
+ "chmod", /* 15 */
+ "lchown", /* 16 */
+ "break", /* 17 */
+ "oldstat", /* 18 */
+ "lseek", /* 19 */
+ "getpid", /* 20 */
+ "mount", /* 21 */
+ "umount", /* 22 */
+ "setuid", /* 23 */
+ "getuid", /* 24 */
+ "stime", /* 25 */
+ "ptrace", /* 26 */
+ "alarm", /* 27 */
+ "oldfstat", /* 28 */
+ "pause", /* 29 */
+ "utime", /* 30 */
+ "stty", /* 31 */
+ "gtty", /* 32 */
+ "access", /* 33 */
+ "nice", /* 34 */
+ "ftime", /* 35 */
+ "sync", /* 36 */
+ "kill", /* 37 */
+ "rename", /* 38 */
+ "mkdir", /* 39 */
+ "rmdir", /* 40 */
+ "dup", /* 41 */
+ "pipe", /* 42 */
+ "times", /* 43 */
+ "prof", /* 44 */
+ "brk", /* 45 */
+ "setgid", /* 46 */
+ "getgid", /* 47 */
+ "signal", /* 48 */
+ "geteuid", /* 49 */
+ "getegid", /* 50 */
+ "acct", /* 51 */
+ "umount2", /* 52 */
+ "lock", /* 53 */
+ "ioctl", /* 54 */
+ "fcntl", /* 55 */
+ "mpx", /* 56 */
+ "setpgid", /* 57 */
+ "ulimit", /* 58 */
+ "oldolduname", /* 59 */
+ "umask", /* 60 */
+ "chroot", /* 61 */
+ "ustat", /* 62 */
+ "dup2", /* 63 */
+ "getppid", /* 64 */
+ "getpgrp", /* 65 */
+ "setsid", /* 66 */
+ "sigaction", /* 67 */
+ "sgetmask", /* 68 */
+ "ssetmask", /* 69 */
+ "setreuid", /* 70 */
+ "setregid", /* 71 */
+ "sigsuspend", /* 72 */
+ "sigpending", /* 73 */
+ "sethostname", /* 74 */
+ "setrlimit", /* 75 */
+ "getrlimit", /* 76 */
+ "getrusage", /* 77 */
+ "gettimeofday", /* 78 */
+ "settimeofday", /* 79 */
+ "getgroups", /* 80 */
+ "setgroups", /* 81 */
+ "select", /* 82 */
+ "symlink", /* 83 */
+ "oldlstat", /* 84 */
+ "readlink", /* 85 */
+ "uselib", /* 86 */
+ "swapon", /* 87 */
+ "reboot", /* 88 */
+ "readdir", /* 89 */
+ "mmap", /* 90 */
+ "munmap", /* 91 */
+ "truncate", /* 92 */
+ "ftruncate", /* 93 */
+ "fchmod", /* 94 */
+ "fchown", /* 95 */
+ "getpriority", /* 96 */
+ "setpriority", /* 97 */
+ "profil", /* 98 */
+ "statfs", /* 99 */
+ "fstatfs", /* 100 */
+ "ioperm", /* 101 */
+ "socketcall", /* 102 */
+ "syslog", /* 103 */
+ "setitimer", /* 104 */
+ "getitimer", /* 105 */
+ "stat", /* 106 */
+ "lstat", /* 107 */
+ "fstat", /* 108 */
+ "olduname", /* 109 */
+ "iopl", /* 110 */
+ "vhangup", /* 111 */
+ "idle", /* 112 */
+ "vm86", /* 113 */
+ "wait4", /* 114 */
+ "swapoff", /* 115 */
+ "sysinfo", /* 116 */
+ "ipc", /* 117 */
+ "fsync", /* 118 */
+ "sigreturn", /* 119 */
+ "clone", /* 120 */
+ "setdomainname", /* 121 */
+ "uname", /* 122 */
+ "modify_ldt", /* 123 */
+ "adjtimex", /* 124 */
+ "mprotect", /* 125 */
+ "sigprocmask", /* 126 */
+ "create_module", /* 127 */
+ "init_module", /* 128 */
+ "delete_module", /* 129 */
+ "get_kernel_syms", /* 130 */
+ "quotactl", /* 131 */
+ "getpgid", /* 132 */
+ "fchdir", /* 133 */
+ "bdflush", /* 134 */
+ "sysfs", /* 135 */
+ "personality", /* 136 */
+ "afs_syscall", /* 137 */
+ "setfsuid", /* 138 */
+ "setfsgid", /* 139 */
+ "_llseek", /* 140 */
+ "getdents", /* 141 */
+ "_newselect", /* 142 */
+ "flock", /* 143 */
+ "msync", /* 144 */
+ "readv", /* 145 */
+ "writev", /* 146 */
+ "getsid", /* 147 */
+ "fdatasync", /* 148 */
+ "_sysctl", /* 149 */
+ "mlock", /* 150 */
+ "munlock", /* 151 */
+ "mlockall", /* 152 */
+ "munlockall", /* 153 */
+ "sched_setparam", /* 154 */
+ "sched_getparam", /* 155 */
+ "sched_setscheduler", /* 156 */
+ "sched_getscheduler", /* 157 */
+ "sched_yield", /* 158 */
+ "sched_get_priority_max", /* 159 */
+ "sched_get_priority_min", /* 160 */
+ "sched_rr_get_interval", /* 161 */
+ "nanosleep", /* 162 */
+ "mremap", /* 163 */
+ "setresuid", /* 164 */
+ "getresuid", /* 165 */
+ "query_module", /* 166 */
+ "poll", /* 167 */
+ "nfsservctl", /* 168 */
+ "setresgid", /* 169 */
+ "getresgid", /* 170 */
+ "prctl", /* 171 */
+ "rt_sigreturn", /* 172 */
+ "rt_sigaction", /* 173 */
+ "rt_sigprocmask", /* 174 */
+ "rt_sigpending", /* 175 */
+ "rt_sigtimedwait", /* 176 */
+ "rt_sigqueueinfo", /* 177 */
+ "rt_sigsuspend", /* 178 */
+ "pread", /* 179 */
+ "pwrite", /* 180 */
+ "chown", /* 181 */
+ "getcwd", /* 182 */
+ "capget", /* 183 */
+ "capset", /* 184 */
+ "sigaltstack", /* 185 */
+ "sendfile", /* 186 */
+ "getpmsg", /* 187 */
+ "putpmsg", /* 188 */
+ "vfork", /* 189 */
+ "ugetrlimit", /* 190 */
+ "readahead", /* 191 */
+ "mmap2", /* 192 */
+ "truncate64", /* 193 */
+ "ftruncate64", /* 194 */
+ "stat64", /* 195 */
+ "lstat64", /* 196 */
+ "fstat64", /* 197 */
+ "pciconfig_read", /* 198 */
+ "pciconfig_write", /* 199 */
+ "pciconfig_iobase", /* 200 */
+ "multiplexer", /* 201 */
+ "getdents64", /* 202 */
+ "pivot_root", /* 203 */
+ "fcntl64", /* 204 */
+ "madvise", /* 205 */
+ "mincore", /* 206 */
+ "gettid", /* 207 */
+ "tkill", /* 208 */
+ "setxattr", /* 209 */
+ "lsetxattr", /* 210 */
+ "fsetxattr", /* 211 */
+ "getxattr", /* 212 */
+ "lgetxattr", /* 213 */
+ "fgetxattr", /* 214 */
+ "listxattr", /* 215 */
+ "llistxattr", /* 216 */
+ "flistxattr", /* 217 */
+ "removexattr", /* 218 */
+ "lremovexattr", /* 219 */
+ "fremovexattr", /* 220 */
+ "futex", /* 221 */
+ "sched_setaffinity", /* 222 */
+ "sched_getaffinity", /* 223 */
+ "224", /* 224 */
+ "tuxcall", /* 225 */
+ "sendfile64", /* 226 */
+ "io_setup", /* 227 */
+ "io_destroy", /* 228 */
+ "io_getevents", /* 229 */
+ "io_submit", /* 230 */
+ "io_cancel", /* 231 */
+ "set_tid_address", /* 232 */
+ "fadvise64", /* 233 */
+ "exit_group", /* 234 */
+ "lookup_dcookie", /* 235 */
+ "epoll_create", /* 236 */
+ "epoll_ctl", /* 237 */
+ "epoll_wait", /* 238 */
+ "remap_file_pages", /* 239 */
+ "timer_create", /* 240 */
+ "timer_settime", /* 241 */
+ "timer_gettime", /* 242 */
+ "timer_getoverrun", /* 243 */
+ "timer_delete", /* 244 */
+ "clock_settime", /* 245 */
+ "clock_gettime", /* 246 */
+ "clock_getres", /* 247 */
+ "clock_nanosleep", /* 248 */
+ "swapcontext", /* 249 */
+ "tgkill", /* 250 */
+ "utimes", /* 251 */
+ "statfs64", /* 252 */
+ "fstatfs64", /* 253 */
+ "fadvise64_64", /* 254 */
+ "rtas", /* 255 */
+ "mq_open", /* 262 */
+ "mq_unlink", /* 263 */
+ "mq_timedsend", /* 264 */
+ "mq_timedreceive", /* 265 */
+ "mq_notify", /* 266 */
+ "mq_getsetattr", /* 267 */
+ "kexec_load", /* 268 */
+ "add_key", /* 269 */
+ "request_key", /* 270 */
+ "keyctl", /* 271 */
+ "waitid", /* 272 */
+ "ioprio_set", /* 273 */
+ "ioprio_get", /* 274 */
+ "inotify_init", /* 275 */
+ "inotify_add_watch", /* 276 */
+ "inotify_rm_watch", /* 277 */
diff --git a/sysdeps/linux-gnu/ppc/trace.c b/sysdeps/linux-gnu/ppc/trace.c
new file mode 100644
index 0000000..81fb71d
--- /dev/null
+++ b/sysdeps/linux-gnu/ppc/trace.c
@@ -0,0 +1,155 @@
+#include "config.h"
+
+#include <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
index 0000000..4251c1d
--- /dev/null
+++ b/sysdeps/linux-gnu/proc.c
@@ -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
index 0000000..cea1b45
--- /dev/null
+++ b/sysdeps/linux-gnu/s390/Makefile
@@ -0,0 +1,13 @@
+#
+# S/390 version
+# Copyright (C) 2001 IBM Poughkeepsie, IBM Corporation
+#
+OBJ = trace.o regs.o plt.o
+
+all: arch.o
+
+arch.o: $(OBJ)
+ $(CC) -nostdlib -r -o arch.o $(OBJ)
+
+clean:
+ $(RM) $(OBJ) arch.o
diff --git a/sysdeps/linux-gnu/s390/arch.h b/sysdeps/linux-gnu/s390/arch.h
new file mode 100644
index 0000000..03690b8
--- /dev/null
+++ b/sysdeps/linux-gnu/s390/arch.h
@@ -0,0 +1,18 @@
+/*
+** S/390 version
+** (C) Copyright 2001 IBM Poughkeepsie, IBM Corporation
+*/
+
+#define BREAKPOINT_VALUE { 0x00, 0x01 }
+#define BREAKPOINT_LENGTH 2
+#define DECR_PC_AFTER_BREAK 2
+
+#ifdef __s390x__
+#define LT_ELFCLASS ELFCLASS64
+#define LT_ELF_MACHINE EM_S390
+#define LT_ELFCLASS2 ELFCLASS32
+#define LT_ELF_MACHINE2 EM_S390
+#else
+#define LT_ELFCLASS ELFCLASS32
+#define LT_ELF_MACHINE EM_S390
+#endif
diff --git a/sysdeps/linux-gnu/s390/plt.c b/sysdeps/linux-gnu/s390/plt.c
new file mode 100644
index 0000000..85a1dd1
--- /dev/null
+++ b/sysdeps/linux-gnu/s390/plt.c
@@ -0,0 +1,12 @@
+#include <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
index 0000000..c3cbcb6
--- /dev/null
+++ b/sysdeps/linux-gnu/s390/ptrace.h
@@ -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
index 0000000..169893e
--- /dev/null
+++ b/sysdeps/linux-gnu/s390/regs.c
@@ -0,0 +1,75 @@
+/*
+** S/390 version
+** Copyright (C) 2001 IBM Poughkeepsie, IBM Corporation
+*/
+
+#include "config.h"
+
+#include <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
index 0000000..35b74f1
--- /dev/null
+++ b/sysdeps/linux-gnu/s390/signalent.h
@@ -0,0 +1,33 @@
+"SIG_0", /* 0 */
+ "SIGHUP", /* 1 */
+ "SIGINT", /* 2 */
+ "SIGQUIT", /* 3 */
+ "SIGILL", /* 4 */
+ "SIGTRAP", /* 5 */
+ "SIGABRT", /* 6 */
+ "SIGBUS", /* 7 */
+ "SIGFPE", /* 8 */
+ "SIGKILL", /* 9 */
+ "SIGUSR1", /* 10 */
+ "SIGSEGV", /* 11 */
+ "SIGUSR2", /* 12 */
+ "SIGPIPE", /* 13 */
+ "SIGALRM", /* 14 */
+ "SIGTERM", /* 15 */
+ "SIGSTKFLT", /* 16 */
+ "SIGCHLD", /* 17 */
+ "SIGCONT", /* 18 */
+ "SIGSTOP", /* 19 */
+ "SIGTSTP", /* 20 */
+ "SIGTTIN", /* 21 */
+ "SIGTTOU", /* 22 */
+ "SIGURG", /* 23 */
+ "SIGXCPU", /* 24 */
+ "SIGXFSZ", /* 25 */
+ "SIGVTALRM", /* 26 */
+ "SIGPROF", /* 27 */
+ "SIGWINCH", /* 28 */
+ "SIGIO", /* 29 */
+ "SIGPWR", /* 30 */
+ "SIGUNUSED", /* 31 */
+ "SIGRTMIN", /* 32 */
diff --git a/sysdeps/linux-gnu/s390/signalent1.h b/sysdeps/linux-gnu/s390/signalent1.h
new file mode 100644
index 0000000..b5b6ca8
--- /dev/null
+++ b/sysdeps/linux-gnu/s390/signalent1.h
@@ -0,0 +1 @@
+#include "s390/signalent.h"
diff --git a/sysdeps/linux-gnu/s390/syscallent.h b/sysdeps/linux-gnu/s390/syscallent.h
new file mode 100644
index 0000000..5a35d93
--- /dev/null
+++ b/sysdeps/linux-gnu/s390/syscallent.h
@@ -0,0 +1,5 @@
+#ifdef __s390x__
+#include "s390/syscalls64.h"
+#else
+#include "s390/syscalls31.h"
+#endif
diff --git a/sysdeps/linux-gnu/s390/syscallent1.h b/sysdeps/linux-gnu/s390/syscallent1.h
new file mode 100644
index 0000000..c9fdc81
--- /dev/null
+++ b/sysdeps/linux-gnu/s390/syscallent1.h
@@ -0,0 +1 @@
+#include "s390/syscalls31.h"
diff --git a/sysdeps/linux-gnu/s390/syscalls31.h b/sysdeps/linux-gnu/s390/syscalls31.h
new file mode 100644
index 0000000..42631eb
--- /dev/null
+++ b/sysdeps/linux-gnu/s390/syscalls31.h
@@ -0,0 +1,310 @@
+ "0", /* 0 */
+ "exit", /* 1 */
+ "fork", /* 2 */
+ "read", /* 3 */
+ "write", /* 4 */
+ "open", /* 5 */
+ "close", /* 6 */
+ "restart_syscall", /* 7 */
+ "creat", /* 8 */
+ "link", /* 9 */
+ "unlink", /* 10 */
+ "execve", /* 11 */
+ "chdir", /* 12 */
+ "time", /* 13 */
+ "mknod", /* 14 */
+ "chmod", /* 15 */
+ "lchown16", /* 16 */
+ "17", /* 17 */
+ "18", /* 18 */
+ "lseek", /* 19 */
+ "getpid", /* 20 */
+ "mount", /* 21 */
+ "oldumount", /* 22 */
+ "setuid16", /* 23 */
+ "getuid16", /* 24 */
+ "stime", /* 25 */
+ "ptrace", /* 26 */
+ "alarm", /* 27 */
+ "28", /* 28 */
+ "pause", /* 29 */
+ "utime", /* 30 */
+ "31", /* 31 */
+ "32", /* 32 */
+ "access", /* 33 */
+ "nice", /* 34 */
+ "35", /* 35 */
+ "sync", /* 36 */
+ "kill", /* 37 */
+ "rename", /* 38 */
+ "mkdir", /* 39 */
+ "rmdir", /* 40 */
+ "dup", /* 41 */
+ "pipe", /* 42 */
+ "times", /* 43 */
+ "44", /* 44 */
+ "brk", /* 45 */
+ "setgid16", /* 46 */
+ "getgid16", /* 47 */
+ "signal", /* 48 */
+ "geteuid16", /* 49 */
+ "getegid16", /* 50 */
+ "acct", /* 51 */
+ "umount", /* 52 */
+ "53", /* 53 */
+ "ioctl", /* 54 */
+ "fcntl", /* 55 */
+ "56", /* 56 */
+ "setpgid", /* 57 */
+ "58", /* 58 */
+ "59", /* 59 */
+ "umask", /* 60 */
+ "chroot", /* 61 */
+ "ustat", /* 62 */
+ "dup2", /* 63 */
+ "getppid", /* 64 */
+ "getpgrp", /* 65 */
+ "setsid", /* 66 */
+ "sigaction", /* 67 */
+ "68", /* 68 */
+ "69", /* 69 */
+ "setreuid16", /* 70 */
+ "setregid16", /* 71 */
+ "sigsuspend", /* 72 */
+ "sigpending", /* 73 */
+ "sethostname", /* 74 */
+ "setrlimit", /* 75 */
+ "old_getrlimit", /* 76 */
+ "getrusage", /* 77 */
+ "gettimeofday", /* 78 */
+ "settimeofday", /* 79 */
+ "getgroups16", /* 80 */
+ "setgroups16", /* 81 */
+ "82", /* 82 */
+ "symlink", /* 83 */
+ "84", /* 84 */
+ "readlink", /* 85 */
+ "uselib", /* 86 */
+ "swapon", /* 87 */
+ "reboot", /* 88 */
+ "89", /* 89 */
+ "old_mmap", /* 90 */
+ "munmap", /* 91 */
+ "truncate", /* 92 */
+ "ftruncate", /* 93 */
+ "fchmod", /* 94 */
+ "fchown16", /* 95 */
+ "getpriority", /* 96 */
+ "setpriority", /* 97 */
+ "98", /* 98 */
+ "statfs", /* 99 */
+ "fstatfs", /* 100 */
+ "101", /* 101 */
+ "socketcall", /* 102 */
+ "syslog", /* 103 */
+ "setitimer", /* 104 */
+ "getitimer", /* 105 */
+ "newstat", /* 106 */
+ "newlstat", /* 107 */
+ "newfstat", /* 108 */
+ "109", /* 109 */
+ "lookup_dcookie", /* 110 */
+ "vhangup", /* 111 */
+ "112", /* 112 */
+ "113", /* 113 */
+ "wait4", /* 114 */
+ "swapoff", /* 115 */
+ "sysinfo", /* 116 */
+ "ipc", /* 117 */
+ "fsync", /* 118 */
+ "sigreturn", /* 119 */
+ "clone", /* 120 */
+ "setdomainname", /* 121 */
+ "newuname", /* 122 */
+ "123", /* 123 */
+ "adjtimex", /* 124 */
+ "mprotect", /* 125 */
+ "sigprocmask", /* 126 */
+ "127", /* 127 */
+ "init_module", /* 128 */
+ "delete_module", /* 129 */
+ "130", /* 130 */
+ "quotactl", /* 131 */
+ "getpgid", /* 132 */
+ "fchdir", /* 133 */
+ "bdflush", /* 134 */
+ "sysfs", /* 135 */
+ "personality", /* 136 */
+ "137", /* 137 */
+ "setfsuid16", /* 138 */
+ "setfsgid16", /* 139 */
+ "llseek", /* 140 */
+ "getdents", /* 141 */
+ "select", /* 142 */
+ "flock", /* 143 */
+ "msync", /* 144 */
+ "readv", /* 145 */
+ "writev", /* 146 */
+ "getsid", /* 147 */
+ "fdatasync", /* 148 */
+ "sysctl", /* 149 */
+ "mlock", /* 150 */
+ "munlock", /* 151 */
+ "mlockall", /* 152 */
+ "munlockall", /* 153 */
+ "sched_setparam", /* 154 */
+ "sched_getparam", /* 155 */
+ "sched_setscheduler", /* 156 */
+ "sched_getscheduler", /* 157 */
+ "sched_yield", /* 158 */
+ "sched_get_priority_max", /* 159 */
+ "sched_get_priority_min", /* 160 */
+ "sched_rr_get_interval", /* 161 */
+ "nanosleep", /* 162 */
+ "mremap", /* 163 */
+ "setresuid16", /* 164 */
+ "getresuid16", /* 165 */
+ "166", /* 166 */
+ "167", /* 167 */
+ "poll", /* 168 */
+ "nfsservctl", /* 169 */
+ "setresgid16", /* 170 */
+ "getresgid16", /* 171 */
+ "prctl", /* 172 */
+ "rt_sigreturn", /* 173 */
+ "rt_sigaction", /* 174 */
+ "rt_sigprocmask", /* 175 */
+ "rt_sigpending", /* 176 */
+ "rt_sigtimedwait", /* 177 */
+ "rt_sigqueueinfo", /* 178 */
+ "rt_sigsuspend", /* 179 */
+ "pread64", /* 180 */
+ "pwrite64", /* 181 */
+ "chown16", /* 182 */
+ "getcwd", /* 183 */
+ "capget", /* 184 */
+ "capset", /* 185 */
+ "sigaltstack", /* 186 */
+ "sendfile", /* 187 */
+ "188", /* 188 */
+ "189", /* 189 */
+ "vfork", /* 190 */
+ "getrlimit", /* 191 */
+ "mmap2", /* 192 */
+ "truncate64", /* 193 */
+ "ftruncate64", /* 194 */
+ "stat64", /* 195 */
+ "lstat64", /* 196 */
+ "fstat64", /* 197 */
+ "lchown", /* 198 */
+ "getuid", /* 199 */
+ "getgid", /* 200 */
+ "geteuid", /* 201 */
+ "getegid", /* 202 */
+ "setreuid", /* 203 */
+ "setregid", /* 204 */
+ "getgroups", /* 205 */
+ "setgroups", /* 206 */
+ "fchown", /* 207 */
+ "setresuid", /* 208 */
+ "getresuid", /* 209 */
+ "setresgid", /* 210 */
+ "getresgid", /* 211 */
+ "chown", /* 212 */
+ "setuid", /* 213 */
+ "setgid", /* 214 */
+ "setfsuid", /* 215 */
+ "setfsgid", /* 216 */
+ "pivot_root", /* 217 */
+ "mincore", /* 218 */
+ "madvise", /* 219 */
+ "getdents64", /* 220 */
+ "fcntl64", /* 221 */
+ "readahead", /* 222 */
+ "sendfile64", /* 223 */
+ "setxattr", /* 224 */
+ "lsetxattr", /* 225 */
+ "fsetxattr", /* 226 */
+ "getxattr", /* 227 */
+ "lgetxattr", /* 228 */
+ "fgetxattr", /* 229 */
+ "listxattr", /* 230 */
+ "llistxattr", /* 231 */
+ "flistxattr", /* 232 */
+ "removexattr", /* 233 */
+ "lremovexattr", /* 234 */
+ "fremovexattr", /* 235 */
+ "gettid", /* 236 */
+ "tkill", /* 237 */
+ "futex", /* 238 */
+ "sched_setaffinity", /* 239 */
+ "sched_getaffinity", /* 240 */
+ "tgkill", /* 241 */
+ "242", /* 242 */
+ "io_setup", /* 243 */
+ "io_destroy", /* 244 */
+ "io_getevents", /* 245 */
+ "io_submit", /* 246 */
+ "io_cancel", /* 247 */
+ "exit_group", /* 248 */
+ "epoll_create", /* 249 */
+ "epoll_ctl", /* 250 */
+ "epoll_wait", /* 251 */
+ "set_tid_address", /* 252 */
+ "fadvise64", /* 253 */
+ "timer_create", /* 254 */
+ "timer_settime", /* 255 */
+ "timer_gettime", /* 256 */
+ "timer_getoverrun", /* 257 */
+ "timer_delete", /* 258 */
+ "clock_settime", /* 259 */
+ "clock_gettime", /* 260 */
+ "clock_getres", /* 261 */
+ "clock_nanosleep", /* 262 */
+ "263", /* 263 */
+ "fadvise64_64", /* 264 */
+ "statfs64", /* 265 */
+ "fstatfs64", /* 266 */
+ "remap_file_pages", /* 267 */
+ "268", /* 268 */
+ "269", /* 269 */
+ "270", /* 270 */
+ "mq_open", /* 271 */
+ "mq_unlink", /* 272 */
+ "mq_timedsend", /* 273 */
+ "mq_timedreceive", /* 274 */
+ "mq_notify", /* 275 */
+ "mq_getsetattr", /* 276 */
+ "kexec_load", /* 277 */
+ "add_key", /* 278 */
+ "request_key", /* 279 */
+ "keyctl", /* 280 */
+ "waitid", /* 281 */
+ "ioprio_set", /* 282 */
+ "ioprio_get", /* 283 */
+ "inotify_init", /* 284 */
+ "inotify_add_watch", /* 285 */
+ "inotify_rm_watch", /* 286 */
+ "287", /* 287 */
+ "openat", /* 288 */
+ "mkdirat", /* 289 */
+ "mknodat", /* 290 */
+ "fchownat", /* 291 */
+ "futimesat", /* 292 */
+ "fstatat64", /* 293 */
+ "unlinkat", /* 294 */
+ "renameat", /* 295 */
+ "linkat", /* 296 */
+ "symlinkat", /* 297 */
+ "readlinkat", /* 298 */
+ "fchmodat", /* 299 */
+ "faccessat", /* 300 */
+ "pselect6", /* 301 */
+ "ppoll", /* 302 */
+ "unshare", /* 303 */
+ "set_robust_list", /* 304 */
+ "get_robust_list", /* 305 */
+ "splice", /* 306 */
+ "sync_file_range", /* 307 */
+ "tee", /* 308 */
+ "vmsplice", /* 309 */
diff --git a/sysdeps/linux-gnu/s390/syscalls64.h b/sysdeps/linux-gnu/s390/syscalls64.h
new file mode 100644
index 0000000..97be52c
--- /dev/null
+++ b/sysdeps/linux-gnu/s390/syscalls64.h
@@ -0,0 +1,310 @@
+ "0", /* 0 */
+ "exit", /* 1 */
+ "fork", /* 2 */
+ "read", /* 3 */
+ "write", /* 4 */
+ "open", /* 5 */
+ "close", /* 6 */
+ "restart_syscall", /* 7 */
+ "creat", /* 8 */
+ "link", /* 9 */
+ "unlink", /* 10 */
+ "execve", /* 11 */
+ "chdir", /* 12 */
+ "13", /* 13 */
+ "mknod", /* 14 */
+ "chmod", /* 15 */
+ "16", /* 16 */
+ "17", /* 17 */
+ "18", /* 18 */
+ "lseek", /* 19 */
+ "getpid", /* 20 */
+ "mount", /* 21 */
+ "oldumount", /* 22 */
+ "23", /* 23 */
+ "24", /* 24 */
+ "25", /* 25 */
+ "ptrace", /* 26 */
+ "alarm", /* 27 */
+ "28", /* 28 */
+ "pause", /* 29 */
+ "utime", /* 30 */
+ "31", /* 31 */
+ "32", /* 32 */
+ "access", /* 33 */
+ "nice", /* 34 */
+ "35", /* 35 */
+ "sync", /* 36 */
+ "kill", /* 37 */
+ "rename", /* 38 */
+ "mkdir", /* 39 */
+ "rmdir", /* 40 */
+ "dup", /* 41 */
+ "pipe", /* 42 */
+ "times", /* 43 */
+ "44", /* 44 */
+ "brk", /* 45 */
+ "46", /* 46 */
+ "47", /* 47 */
+ "signal", /* 48 */
+ "49", /* 49 */
+ "50", /* 50 */
+ "acct", /* 51 */
+ "umount", /* 52 */
+ "53", /* 53 */
+ "ioctl", /* 54 */
+ "fcntl", /* 55 */
+ "56", /* 56 */
+ "setpgid", /* 57 */
+ "58", /* 58 */
+ "59", /* 59 */
+ "umask", /* 60 */
+ "chroot", /* 61 */
+ "ustat", /* 62 */
+ "dup2", /* 63 */
+ "getppid", /* 64 */
+ "getpgrp", /* 65 */
+ "setsid", /* 66 */
+ "sigaction", /* 67 */
+ "68", /* 68 */
+ "69", /* 69 */
+ "70", /* 70 */
+ "71", /* 71 */
+ "sigsuspend", /* 72 */
+ "sigpending", /* 73 */
+ "sethostname", /* 74 */
+ "setrlimit", /* 75 */
+ "getrlimit", /* 76 */
+ "getrusage", /* 77 */
+ "gettimeofday", /* 78 */
+ "settimeofday", /* 79 */
+ "80", /* 80 */
+ "81", /* 81 */
+ "82", /* 82 */
+ "symlink", /* 83 */
+ "84", /* 84 */
+ "readlink", /* 85 */
+ "uselib", /* 86 */
+ "swapon", /* 87 */
+ "reboot", /* 88 */
+ "89", /* 89 */
+ "old_mmap", /* 90 */
+ "munmap", /* 91 */
+ "truncate", /* 92 */
+ "ftruncate", /* 93 */
+ "fchmod", /* 94 */
+ "95", /* 95 */
+ "getpriority", /* 96 */
+ "setpriority", /* 97 */
+ "98", /* 98 */
+ "statfs", /* 99 */
+ "fstatfs", /* 100 */
+ "101", /* 101 */
+ "socketcall", /* 102 */
+ "syslog", /* 103 */
+ "setitimer", /* 104 */
+ "getitimer", /* 105 */
+ "newstat", /* 106 */
+ "newlstat", /* 107 */
+ "newfstat", /* 108 */
+ "109", /* 109 */
+ "lookup_dcookie", /* 110 */
+ "vhangup", /* 111 */
+ "112", /* 112 */
+ "113", /* 113 */
+ "wait4", /* 114 */
+ "swapoff", /* 115 */
+ "sysinfo", /* 116 */
+ "ipc", /* 117 */
+ "fsync", /* 118 */
+ "sigreturn", /* 119 */
+ "clone", /* 120 */
+ "setdomainname", /* 121 */
+ "newuname", /* 122 */
+ "123", /* 123 */
+ "adjtimex", /* 124 */
+ "mprotect", /* 125 */
+ "sigprocmask", /* 126 */
+ "127", /* 127 */
+ "init_module", /* 128 */
+ "delete_module", /* 129 */
+ "130", /* 130 */
+ "quotactl", /* 131 */
+ "getpgid", /* 132 */
+ "fchdir", /* 133 */
+ "bdflush", /* 134 */
+ "sysfs", /* 135 */
+ "personality", /* 136 */
+ "137", /* 137 */
+ "138", /* 138 */
+ "139", /* 139 */
+ "llseek", /* 140 */
+ "getdents", /* 141 */
+ "select", /* 142 */
+ "flock", /* 143 */
+ "msync", /* 144 */
+ "readv", /* 145 */
+ "writev", /* 146 */
+ "getsid", /* 147 */
+ "fdatasync", /* 148 */
+ "sysctl", /* 149 */
+ "mlock", /* 150 */
+ "munlock", /* 151 */
+ "mlockall", /* 152 */
+ "munlockall", /* 153 */
+ "sched_setparam", /* 154 */
+ "sched_getparam", /* 155 */
+ "sched_setscheduler", /* 156 */
+ "sched_getscheduler", /* 157 */
+ "sched_yield", /* 158 */
+ "sched_get_priority_max", /* 159 */
+ "sched_get_priority_min", /* 160 */
+ "sched_rr_get_interval", /* 161 */
+ "nanosleep", /* 162 */
+ "mremap", /* 163 */
+ "164", /* 164 */
+ "165", /* 165 */
+ "166", /* 166 */
+ "167", /* 167 */
+ "poll", /* 168 */
+ "nfsservctl", /* 169 */
+ "170", /* 170 */
+ "171", /* 171 */
+ "prctl", /* 172 */
+ "rt_sigreturn", /* 173 */
+ "rt_sigaction", /* 174 */
+ "rt_sigprocmask", /* 175 */
+ "rt_sigpending", /* 176 */
+ "rt_sigtimedwait", /* 177 */
+ "rt_sigqueueinfo", /* 178 */
+ "rt_sigsuspend", /* 179 */
+ "pread64", /* 180 */
+ "pwrite64", /* 181 */
+ "182", /* 182 */
+ "getcwd", /* 183 */
+ "capget", /* 184 */
+ "capset", /* 185 */
+ "sigaltstack", /* 186 */
+ "sendfile64", /* 187 */
+ "188", /* 188 */
+ "189", /* 189 */
+ "vfork", /* 190 */
+ "getrlimit", /* 191 */
+ "mmap2", /* 192 */
+ "193", /* 193 */
+ "194", /* 194 */
+ "195", /* 195 */
+ "196", /* 196 */
+ "197", /* 197 */
+ "lchown", /* 198 */
+ "getuid", /* 199 */
+ "getgid", /* 200 */
+ "geteuid", /* 201 */
+ "getegid", /* 202 */
+ "setreuid", /* 203 */
+ "setregid", /* 204 */
+ "getgroups", /* 205 */
+ "setgroups", /* 206 */
+ "fchown", /* 207 */
+ "setresuid", /* 208 */
+ "getresuid", /* 209 */
+ "setresgid", /* 210 */
+ "getresgid", /* 211 */
+ "chown", /* 212 */
+ "setuid", /* 213 */
+ "setgid", /* 214 */
+ "setfsuid", /* 215 */
+ "setfsgid", /* 216 */
+ "pivot_root", /* 217 */
+ "mincore", /* 218 */
+ "madvise", /* 219 */
+ "getdents64", /* 220 */
+ "221", /* 221 */
+ "readahead", /* 222 */
+ "223", /* 223 */
+ "setxattr", /* 224 */
+ "lsetxattr", /* 225 */
+ "fsetxattr", /* 226 */
+ "getxattr", /* 227 */
+ "lgetxattr", /* 228 */
+ "fgetxattr", /* 229 */
+ "listxattr", /* 230 */
+ "llistxattr", /* 231 */
+ "flistxattr", /* 232 */
+ "removexattr", /* 233 */
+ "lremovexattr", /* 234 */
+ "fremovexattr", /* 235 */
+ "gettid", /* 236 */
+ "tkill", /* 237 */
+ "futex", /* 238 */
+ "sched_setaffinity", /* 239 */
+ "sched_getaffinity", /* 240 */
+ "tgkill", /* 241 */
+ "242", /* 242 */
+ "io_setup", /* 243 */
+ "io_destroy", /* 244 */
+ "io_getevents", /* 245 */
+ "io_submit", /* 246 */
+ "io_cancel", /* 247 */
+ "exit_group", /* 248 */
+ "epoll_create", /* 249 */
+ "epoll_ctl", /* 250 */
+ "epoll_wait", /* 251 */
+ "set_tid_address", /* 252 */
+ "fadvise64_64", /* 253 */
+ "timer_create", /* 254 */
+ "timer_settime", /* 255 */
+ "timer_gettime", /* 256 */
+ "timer_getoverrun", /* 257 */
+ "timer_delete", /* 258 */
+ "clock_settime", /* 259 */
+ "clock_gettime", /* 260 */
+ "clock_getres", /* 261 */
+ "clock_nanosleep", /* 262 */
+ "263", /* 263 */
+ "264", /* 264 */
+ "statfs64", /* 265 */
+ "fstatfs64", /* 266 */
+ "remap_file_pages", /* 267 */
+ "268", /* 268 */
+ "269", /* 269 */
+ "270", /* 270 */
+ "mq_open", /* 271 */
+ "mq_unlink", /* 272 */
+ "mq_timedsend", /* 273 */
+ "mq_timedreceive", /* 274 */
+ "mq_notify", /* 275 */
+ "mq_getsetattr", /* 276 */
+ "kexec_load", /* 277 */
+ "add_key", /* 278 */
+ "request_key", /* 279 */
+ "keyctl", /* 280 */
+ "waitid", /* 281 */
+ "ioprio_set", /* 282 */
+ "ioprio_get", /* 283 */
+ "inotify_init", /* 284 */
+ "inotify_add_watch", /* 285 */
+ "inotify_rm_watch", /* 286 */
+ "287", /* 287 */
+ "openat", /* 288 */
+ "mkdirat", /* 289 */
+ "mknodat", /* 290 */
+ "fchownat", /* 291 */
+ "futimesat", /* 292 */
+ "newfstatat", /* 293 */
+ "unlinkat", /* 294 */
+ "renameat", /* 295 */
+ "linkat", /* 296 */
+ "symlinkat", /* 297 */
+ "readlinkat", /* 298 */
+ "fchmodat", /* 299 */
+ "faccessat", /* 300 */
+ "pselect6", /* 301 */
+ "ppoll", /* 302 */
+ "unshare", /* 303 */
+ "set_robust_list", /* 304 */
+ "get_robust_list", /* 305 */
+ "splice", /* 306 */
+ "sync_file_range", /* 307 */
+ "tee", /* 308 */
+ "vmsplice", /* 309 */
diff --git a/sysdeps/linux-gnu/s390/trace.c b/sysdeps/linux-gnu/s390/trace.c
new file mode 100644
index 0000000..9df2437
--- /dev/null
+++ b/sysdeps/linux-gnu/s390/trace.c
@@ -0,0 +1,198 @@
+/*
+** S390 specific part of trace.c
+**
+** Other routines are in ../trace.c and need to be combined
+** at link time with this code.
+**
+** Copyright (C) 2001,2005 IBM Corp.
+*/
+
+#include "config.h"
+
+#include <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
index 0000000..b3914e5
--- /dev/null
+++ b/sysdeps/linux-gnu/sparc/Makefile
@@ -0,0 +1,9 @@
+OBJ = regs.o trace.o plt.o
+
+all: arch.o
+
+arch.o: $(OBJ)
+ $(CC) -nostdlib -r -o arch.o $(OBJ)
+
+clean:
+ $(RM) $(OBJ) arch.o
diff --git a/sysdeps/linux-gnu/sparc/arch.h b/sysdeps/linux-gnu/sparc/arch.h
new file mode 100644
index 0000000..75251b8
--- /dev/null
+++ b/sysdeps/linux-gnu/sparc/arch.h
@@ -0,0 +1,8 @@
+#define BREAKPOINT_VALUE {0x91, 0xd0, 0x20, 0x01}
+#define BREAKPOINT_LENGTH 4
+#define DECR_PC_AFTER_BREAK 0
+
+#define LT_ELFCLASS ELFCLASS32
+#define LT_ELF_MACHINE EM_SPARC
+#define LT_ELFCLASS2 ELFCLASS32
+#define LT_ELF_MACHINE2 EM_SPARC32PLUS
diff --git a/sysdeps/linux-gnu/sparc/plt.c b/sysdeps/linux-gnu/sparc/plt.c
new file mode 100644
index 0000000..f9e6d80
--- /dev/null
+++ b/sysdeps/linux-gnu/sparc/plt.c
@@ -0,0 +1,12 @@
+#include <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
index 0000000..bbaf01a
--- /dev/null
+++ b/sysdeps/linux-gnu/sparc/ptrace.h
@@ -0,0 +1,21 @@
+#undef PTRACE_GETREGS
+#undef PTRACE_SETREGS
+#undef PTRACE_GETFPREGS
+#undef PTRACE_SETFPREGS
+#include <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
index 0000000..49d2729
--- /dev/null
+++ b/sysdeps/linux-gnu/sparc/regs.c
@@ -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
index 0000000..d30f69e
--- /dev/null
+++ b/sysdeps/linux-gnu/sparc/signalent.h
@@ -0,0 +1,32 @@
+"SIG_0", /* 0 */
+ "SIGHUP", /* 1 */
+ "SIGINT", /* 2 */
+ "SIGQUIT", /* 3 */
+ "SIGILL", /* 4 */
+ "SIGTRAP", /* 5 */
+ "SIGABRT", /* 6 */
+ "SIGEMT", /* 7 */
+ "SIGFPE", /* 8 */
+ "SIGKILL", /* 9 */
+ "SIGBUS", /* 10 */
+ "SIGSEGV", /* 11 */
+ "SIGSYS", /* 12 */
+ "SIGPIPE", /* 13 */
+ "SIGALRM", /* 14 */
+ "SIGTERM", /* 15 */
+ "SIGURG", /* 16 */
+ "SIGSTOP", /* 17 */
+ "SIGTSTP", /* 18 */
+ "SIGCONT", /* 19 */
+ "SIGCHLD", /* 20 */
+ "SIGTTIN", /* 21 */
+ "SIGTTOU", /* 22 */
+ "SIGIO", /* 23 */
+ "SIGXCPU", /* 24 */
+ "SIGXFSZ", /* 25 */
+ "SIGVTALRM", /* 26 */
+ "SIGPROF", /* 27 */
+ "SIGWINCH", /* 28 */
+ "SIGLOST", /* 29 */
+ "SIGUSR1", /* 30 */
+ "SIGUSR2", /* 31 */
diff --git a/sysdeps/linux-gnu/sparc/syscallent.h b/sysdeps/linux-gnu/sparc/syscallent.h
new file mode 100644
index 0000000..96eeec9
--- /dev/null
+++ b/sysdeps/linux-gnu/sparc/syscallent.h
@@ -0,0 +1,284 @@
+"0", /* 0 */
+ "exit", /* 1 */
+ "fork", /* 2 */
+ "read", /* 3 */
+ "write", /* 4 */
+ "open", /* 5 */
+ "close", /* 6 */
+ "wait4", /* 7 */
+ "creat", /* 8 */
+ "link", /* 9 */
+ "unlink", /* 10 */
+ "execv", /* 11 */
+ "chdir", /* 12 */
+ "chown", /* 13 */
+ "mknod", /* 14 */
+ "chmod", /* 15 */
+ "lchown", /* 16 */
+ "brk", /* 17 */
+ "perfctr", /* 18 */
+ "lseek", /* 19 */
+ "getpid", /* 20 */
+ "capget", /* 21 */
+ "capset", /* 22 */
+ "setuid", /* 23 */
+ "getuid", /* 24 */
+ "25", /* 25 */
+ "ptrace", /* 26 */
+ "alarm", /* 27 */
+ "sigaltstack", /* 28 */
+ "pause", /* 29 */
+ "utime", /* 30 */
+ "lchown32", /* 31 */
+ "fchown32", /* 32 */
+ "access", /* 33 */
+ "nice", /* 34 */
+ "chown32", /* 35 */
+ "sync", /* 36 */
+ "kill", /* 37 */
+ "stat", /* 38 */
+ "sendfile", /* 39 */
+ "lstat", /* 40 */
+ "dup", /* 41 */
+ "pipe", /* 42 */
+ "times", /* 43 */
+ "getuid32", /* 44 */
+ "umount2", /* 45 */
+ "setgid", /* 46 */
+ "getgid", /* 47 */
+ "signal", /* 48 */
+ "geteuid", /* 49 */
+ "getegid", /* 50 */
+ "acct", /* 51 */
+ "memory_ordering", /* 52 */
+ "getgid32", /* 53 */
+ "ioctl", /* 54 */
+ "reboot", /* 55 */
+ "mmap2", /* 56 */
+ "symlink", /* 57 */
+ "readlink", /* 58 */
+ "execve", /* 59 */
+ "umask", /* 60 */
+ "chroot", /* 61 */
+ "fstat", /* 62 */
+ "fstat64", /* 63 */
+ "getpagesize", /* 64 */
+ "msync", /* 65 */
+ "vfork", /* 66 */
+ "pread64", /* 67 */
+ "pwrite64", /* 68 */
+ "geteuid32", /* 69 */
+ "getegid32", /* 70 */
+ "mmap", /* 71 */
+ "setreuid32", /* 72 */
+ "munmap", /* 73 */
+ "mprotect", /* 74 */
+ "madvise", /* 75 */
+ "vhangup", /* 76 */
+ "truncate64", /* 77 */
+ "mincore", /* 78 */
+ "getgroups", /* 79 */
+ "setgroups", /* 80 */
+ "getpgrp", /* 81 */
+ "setgroups32", /* 82 */
+ "setitimer", /* 83 */
+ "ftruncate64", /* 84 */
+ "swapon", /* 85 */
+ "getitimer", /* 86 */
+ "setuid32", /* 87 */
+ "sethostname", /* 88 */
+ "setgid32", /* 89 */
+ "dup2", /* 90 */
+ "setfsuid32", /* 91 */
+ "fcntl", /* 92 */
+ "select", /* 93 */
+ "setfsgid32", /* 94 */
+ "fsync", /* 95 */
+ "setpriority", /* 96 */
+ "socket", /* 97 */
+ "connect", /* 98 */
+ "accept", /* 99 */
+ "getpriority", /* 100 */
+ "rt_sigreturn", /* 101 */
+ "rt_sigaction", /* 102 */
+ "rt_sigprocmask", /* 103 */
+ "rt_sigpending", /* 104 */
+ "rt_sigtimedwait", /* 105 */
+ "rt_sigqueueinfo", /* 106 */
+ "rt_sigsuspend", /* 107 */
+ "setresuid32", /* 108 */
+ "getresuid32", /* 109 */
+ "setresgid32", /* 110 */
+ "getresgid32", /* 111 */
+ "setregid32", /* 112 */
+ "recvmsg", /* 113 */
+ "sendmsg", /* 114 */
+ "getgroups32", /* 115 */
+ "gettimeofday", /* 116 */
+ "getrusage", /* 117 */
+ "getsockopt", /* 118 */
+ "getcwd", /* 119 */
+ "readv", /* 120 */
+ "writev", /* 121 */
+ "settimeofday", /* 122 */
+ "fchown", /* 123 */
+ "fchmod", /* 124 */
+ "recvfrom", /* 125 */
+ "setreuid", /* 126 */
+ "setregid", /* 127 */
+ "rename", /* 128 */
+ "truncate", /* 129 */
+ "ftruncate", /* 130 */
+ "flock", /* 131 */
+ "lstat64", /* 132 */
+ "sendto", /* 133 */
+ "shutdown", /* 134 */
+ "socketpair", /* 135 */
+ "mkdir", /* 136 */
+ "rmdir", /* 137 */
+ "utimes", /* 138 */
+ "stat64", /* 139 */
+ "sendfile64", /* 140 */
+ "getpeername", /* 141 */
+ "futex", /* 142 */
+ "gettid", /* 143 */
+ "getrlimit", /* 144 */
+ "setrlimit", /* 145 */
+ "pivot_root", /* 146 */
+ "prctl", /* 147 */
+ "pciconfig_read", /* 148 */
+ "pciconfig_write", /* 149 */
+ "getsockname", /* 150 */
+ "inotify_init", /* 151 */
+ "inotify_add_watch", /* 152 */
+ "poll", /* 153 */
+ "getdents64", /* 154 */
+ "fcntl64", /* 155 */
+ "inotify_rm_watch", /* 156 */
+ "statfs", /* 157 */
+ "fstatfs", /* 158 */
+ "umount", /* 159 */
+ "sched_set_affinity", /* 160 */
+ "sched_get_affinity", /* 161 */
+ "getdomainname", /* 162 */
+ "setdomainname", /* 163 */
+ "utrap_install", /* 164 */
+ "quotactl", /* 165 */
+ "set_tid_address", /* 166 */
+ "mount", /* 167 */
+ "ustat", /* 168 */
+ "setxattr", /* 169 */
+ "lsetxattr", /* 170 */
+ "fsetxattr", /* 171 */
+ "getxattr", /* 172 */
+ "lgetxattr", /* 173 */
+ "getdents", /* 174 */
+ "setsid", /* 175 */
+ "fchdir", /* 176 */
+ "fgetxattr", /* 177 */
+ "listxattr", /* 178 */
+ "llistxattr", /* 179 */
+ "flistxattr", /* 180 */
+ "removexattr", /* 181 */
+ "lremovexattr", /* 182 */
+ "sigpending", /* 183 */
+ "query_module", /* 184 */
+ "setpgid", /* 185 */
+ "fremovexattr", /* 186 */
+ "tkill", /* 187 */
+ "exit_group", /* 188 */
+ "uname", /* 189 */
+ "init_module", /* 190 */
+ "personality", /* 191 */
+ "remap_file_pages", /* 192 */
+ "epoll_create", /* 193 */
+ "epoll_ctl", /* 194 */
+ "epoll_wait", /* 195 */
+ "ioprio_set", /* 196 */
+ "getppid", /* 197 */
+ "sigaction", /* 198 */
+ "sgetmask", /* 199 */
+ "ssetmask", /* 200 */
+ "sigsuspend", /* 201 */
+ "oldlstat", /* 202 */
+ "uselib", /* 203 */
+ "readdir", /* 204 */
+ "readahead", /* 205 */
+ "socketcall", /* 206 */
+ "syslog", /* 207 */
+ "lookup_dcookie", /* 208 */
+ "fadvise64", /* 209 */
+ "fadvise64_64", /* 210 */
+ "tgkill", /* 211 */
+ "waitpid", /* 212 */
+ "swapoff", /* 213 */
+ "sysinfo", /* 214 */
+ "ipc", /* 215 */
+ "sigreturn", /* 216 */
+ "clone", /* 217 */
+ "ioprio_get", /* 218 */
+ "adjtimex", /* 219 */
+ "sigprocmask", /* 220 */
+ "create_module", /* 221 */
+ "delete_module", /* 222 */
+ "get_kernel_syms", /* 223 */
+ "getpgid", /* 224 */
+ "bdflush", /* 225 */
+ "sysfs", /* 226 */
+ "afs_syscall", /* 227 */
+ "setfsuid", /* 228 */
+ "setfsgid", /* 229 */
+ "_newselect", /* 230 */
+ "time", /* 231 */
+ "232", /* 232 */
+ "stime", /* 233 */
+ "statfs64", /* 234 */
+ "fstatfs64", /* 235 */
+ "_llseek", /* 236 */
+ "mlock", /* 237 */
+ "munlock", /* 238 */
+ "mlockall", /* 239 */
+ "munlockall", /* 240 */
+ "sched_setparam", /* 241 */
+ "sched_getparam", /* 242 */
+ "sched_setscheduler", /* 243 */
+ "sched_getscheduler", /* 244 */
+ "sched_yield", /* 245 */
+ "sched_get_priority_max", /* 246 */
+ "sched_get_priority_min", /* 247 */
+ "sched_rr_get_interval", /* 248 */
+ "nanosleep", /* 249 */
+ "mremap", /* 250 */
+ "_sysctl", /* 251 */
+ "getsid", /* 252 */
+ "fdatasync", /* 253 */
+ "nfsservctl", /* 254 */
+ "aplib", /* 255 */
+ "clock_settime", /* 256 */
+ "clock_gettime", /* 257 */
+ "clock_getres", /* 258 */
+ "clock_nanosleep", /* 259 */
+ "sched_getaffinity", /* 260 */
+ "sched_setaffinity", /* 261 */
+ "timer_settime", /* 262 */
+ "timer_gettime", /* 263 */
+ "timer_getoverrun", /* 264 */
+ "timer_delete", /* 265 */
+ "timer_create", /* 266 */
+ "vserver", /* 267 */
+ "io_setup", /* 268 */
+ "io_destroy", /* 269 */
+ "io_submit", /* 270 */
+ "io_cancel", /* 271 */
+ "io_getevents", /* 272 */
+ "mq_open", /* 273 */
+ "mq_unlink", /* 274 */
+ "mq_timedsend", /* 275 */
+ "mq_timedreceive", /* 276 */
+ "mq_notify", /* 277 */
+ "mq_getsetattr", /* 278 */
+ "waitid", /* 279 */
+ "setaltroot", /* 280 */
+ "add_key", /* 281 */
+ "request_key", /* 282 */
+ "keyctl", /* 283 */
diff --git a/sysdeps/linux-gnu/sparc/trace.c b/sysdeps/linux-gnu/sparc/trace.c
new file mode 100644
index 0000000..7f05b55
--- /dev/null
+++ b/sysdeps/linux-gnu/sparc/trace.c
@@ -0,0 +1,81 @@
+#include "config.h"
+
+#include <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
index 0000000..df5b090
--- /dev/null
+++ b/sysdeps/linux-gnu/trace.c
@@ -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
index 0000000..0a19c97
--- /dev/null
+++ b/sysdeps/linux-gnu/x86_64/Makefile
@@ -0,0 +1,9 @@
+OBJ = trace.o regs.o plt.o
+
+all: arch.o
+
+arch.o: $(OBJ)
+ $(CC) -nostdlib -r -o arch.o $(OBJ)
+
+clean:
+ $(RM) $(OBJ) arch.o
diff --git a/sysdeps/linux-gnu/x86_64/arch.h b/sysdeps/linux-gnu/x86_64/arch.h
new file mode 100644
index 0000000..255395c
--- /dev/null
+++ b/sysdeps/linux-gnu/x86_64/arch.h
@@ -0,0 +1,12 @@
+#define BREAKPOINT_VALUE {0xcc}
+#define BREAKPOINT_LENGTH 1
+#define DECR_PC_AFTER_BREAK 1
+
+#define LT_ELFCLASS ELFCLASS64
+#define LT_ELF_MACHINE EM_X86_64
+#define LT_ELFCLASS2 ELFCLASS32
+#define LT_ELF_MACHINE2 EM_386
+
+/* __NR_fork, __NR_clone, __NR_clone2, __NR_vfork and __NR_execve
+ from asm-i386/unistd.h. */
+#define FORK_EXEC_SYSCALLS , { 2, 120, -1, 190, 11 }
diff --git a/sysdeps/linux-gnu/x86_64/ffcheck.c b/sysdeps/linux-gnu/x86_64/ffcheck.c
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/sysdeps/linux-gnu/x86_64/ffcheck.c
diff --git a/sysdeps/linux-gnu/x86_64/plt.c b/sysdeps/linux-gnu/x86_64/plt.c
new file mode 100644
index 0000000..b53ff44
--- /dev/null
+++ b/sysdeps/linux-gnu/x86_64/plt.c
@@ -0,0 +1,12 @@
+#include <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
index 0000000..c3cbcb6
--- /dev/null
+++ b/sysdeps/linux-gnu/x86_64/ptrace.h
@@ -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
index 0000000..ed1f118
--- /dev/null
+++ b/sysdeps/linux-gnu/x86_64/regs.c
@@ -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
index 0000000..d58a36c
--- /dev/null
+++ b/sysdeps/linux-gnu/x86_64/signalent.h
@@ -0,0 +1,32 @@
+"SIG_0", /* 0 */
+ "SIGHUP", /* 1 */
+ "SIGINT", /* 2 */
+ "SIGQUIT", /* 3 */
+ "SIGILL", /* 4 */
+ "SIGTRAP", /* 5 */
+ "SIGABRT", /* 6 */
+ "SIGBUS", /* 7 */
+ "SIGFPE", /* 8 */
+ "SIGKILL", /* 9 */
+ "SIGUSR1", /* 10 */
+ "SIGSEGV", /* 11 */
+ "SIGUSR2", /* 12 */
+ "SIGPIPE", /* 13 */
+ "SIGALRM", /* 14 */
+ "SIGTERM", /* 15 */
+ "SIGSTKFLT", /* 16 */
+ "SIGCHLD", /* 17 */
+ "SIGCONT", /* 18 */
+ "SIGSTOP", /* 19 */
+ "SIGTSTP", /* 20 */
+ "SIGTTIN", /* 21 */
+ "SIGTTOU", /* 22 */
+ "SIGURG", /* 23 */
+ "SIGXCPU", /* 24 */
+ "SIGXFSZ", /* 25 */
+ "SIGVTALRM", /* 26 */
+ "SIGPROF", /* 27 */
+ "SIGWINCH", /* 28 */
+ "SIGIO", /* 29 */
+ "SIGPWR", /* 30 */
+ "SIGSYS", /* 31 */
diff --git a/sysdeps/linux-gnu/x86_64/signalent1.h b/sysdeps/linux-gnu/x86_64/signalent1.h
new file mode 100644
index 0000000..5ead946
--- /dev/null
+++ b/sysdeps/linux-gnu/x86_64/signalent1.h
@@ -0,0 +1 @@
+#include "i386/signalent.h"
diff --git a/sysdeps/linux-gnu/x86_64/syscallent.h b/sysdeps/linux-gnu/x86_64/syscallent.h
new file mode 100644
index 0000000..5e5f88a
--- /dev/null
+++ b/sysdeps/linux-gnu/x86_64/syscallent.h
@@ -0,0 +1,256 @@
+"read", /* 0 */
+ "write", /* 1 */
+ "open", /* 2 */
+ "close", /* 3 */
+ "stat", /* 4 */
+ "fstat", /* 5 */
+ "lstat", /* 6 */
+ "poll", /* 7 */
+ "lseek", /* 8 */
+ "mmap", /* 9 */
+ "mprotect", /* 10 */
+ "munmap", /* 11 */
+ "brk", /* 12 */
+ "rt_sigaction", /* 13 */
+ "rt_sigprocmask", /* 14 */
+ "rt_sigreturn", /* 15 */
+ "ioctl", /* 16 */
+ "pread", /* 17 */
+ "pwrite", /* 18 */
+ "readv", /* 19 */
+ "writev", /* 20 */
+ "access", /* 21 */
+ "pipe", /* 22 */
+ "select", /* 23 */
+ "sched_yield", /* 24 */
+ "mremap", /* 25 */
+ "msync", /* 26 */
+ "mincore", /* 27 */
+ "madvise", /* 28 */
+ "shmget", /* 29 */
+ "shmat", /* 30 */
+ "shmctl", /* 31 */
+ "dup", /* 32 */
+ "dup2", /* 33 */
+ "pause", /* 34 */
+ "nanosleep", /* 35 */
+ "getitimer", /* 36 */
+ "alarm", /* 37 */
+ "setitimer", /* 38 */
+ "getpid", /* 39 */
+ "sendfile", /* 40 */
+ "socket", /* 41 */
+ "connect", /* 42 */
+ "accept", /* 43 */
+ "sendto", /* 44 */
+ "recvfrom", /* 45 */
+ "sendmsg", /* 46 */
+ "recvmsg", /* 47 */
+ "shutdown", /* 48 */
+ "bind", /* 49 */
+ "listen", /* 50 */
+ "getsockname", /* 51 */
+ "getpeername", /* 52 */
+ "socketpair", /* 53 */
+ "setsockopt", /* 54 */
+ "getsockopt", /* 55 */
+ "clone", /* 56 */
+ "fork", /* 57 */
+ "vfork", /* 58 */
+ "execve", /* 59 */
+ "exit", /* 60 */
+ "wait4", /* 61 */
+ "kill", /* 62 */
+ "uname", /* 63 */
+ "semget", /* 64 */
+ "semop", /* 65 */
+ "semctl", /* 66 */
+ "shmdt", /* 67 */
+ "msgget", /* 68 */
+ "msgsnd", /* 69 */
+ "msgrcv", /* 70 */
+ "msgctl", /* 71 */
+ "fcntl", /* 72 */
+ "flock", /* 73 */
+ "fsync", /* 74 */
+ "fdatasync", /* 75 */
+ "truncate", /* 76 */
+ "ftruncate", /* 77 */
+ "getdents", /* 78 */
+ "getcwd", /* 79 */
+ "chdir", /* 80 */
+ "fchdir", /* 81 */
+ "rename", /* 82 */
+ "mkdir", /* 83 */
+ "rmdir", /* 84 */
+ "creat", /* 85 */
+ "link", /* 86 */
+ "unlink", /* 87 */
+ "symlink", /* 88 */
+ "readlink", /* 89 */
+ "chmod", /* 90 */
+ "fchmod", /* 91 */
+ "chown", /* 92 */
+ "fchown", /* 93 */
+ "lchown", /* 94 */
+ "umask", /* 95 */
+ "gettimeofday", /* 96 */
+ "getrlimit", /* 97 */
+ "getrusage", /* 98 */
+ "sysinfo", /* 99 */
+ "times", /* 100 */
+ "ptrace", /* 101 */
+ "getuid", /* 102 */
+ "syslog", /* 103 */
+ "getgid", /* 104 */
+ "setuid", /* 105 */
+ "setgid", /* 106 */
+ "geteuid", /* 107 */
+ "getegid", /* 108 */
+ "setpgid", /* 109 */
+ "getppid", /* 110 */
+ "getpgrp", /* 111 */
+ "setsid", /* 112 */
+ "setreuid", /* 113 */
+ "setregid", /* 114 */
+ "getgroups", /* 115 */
+ "setgroups", /* 116 */
+ "setresuid", /* 117 */
+ "getresuid", /* 118 */
+ "setresgid", /* 119 */
+ "getresgid", /* 120 */
+ "getpgid", /* 121 */
+ "setfsuid", /* 122 */
+ "setfsgid", /* 123 */
+ "getsid", /* 124 */
+ "capget", /* 125 */
+ "capset", /* 126 */
+ "rt_sigpending", /* 127 */
+ "rt_sigtimedwait", /* 128 */
+ "rt_sigqueueinfo", /* 129 */
+ "rt_sigsuspend", /* 130 */
+ "sigaltstack", /* 131 */
+ "utime", /* 132 */
+ "mknod", /* 133 */
+ "uselib", /* 134 */
+ "personality", /* 135 */
+ "ustat", /* 136 */
+ "statfs", /* 137 */
+ "fstatfs", /* 138 */
+ "sysfs", /* 139 */
+ "getpriority", /* 140 */
+ "setpriority", /* 141 */
+ "sched_setparam", /* 142 */
+ "sched_getparam", /* 143 */
+ "sched_setscheduler", /* 144 */
+ "sched_getscheduler", /* 145 */
+ "sched_get_priority_max", /* 146 */
+ "sched_get_priority_min", /* 147 */
+ "sched_rr_get_interval", /* 148 */
+ "mlock", /* 149 */
+ "munlock", /* 150 */
+ "mlockall", /* 151 */
+ "munlockall", /* 152 */
+ "vhangup", /* 153 */
+ "modify_ldt", /* 154 */
+ "pivot_root", /* 155 */
+ "_sysctl", /* 156 */
+ "prctl", /* 157 */
+ "arch_prctl", /* 158 */
+ "adjtimex", /* 159 */
+ "setrlimit", /* 160 */
+ "chroot", /* 161 */
+ "sync", /* 162 */
+ "acct", /* 163 */
+ "settimeofday", /* 164 */
+ "mount", /* 165 */
+ "umount2", /* 166 */
+ "swapon", /* 167 */
+ "swapoff", /* 168 */
+ "reboot", /* 169 */
+ "sethostname", /* 170 */
+ "setdomainname", /* 171 */
+ "iopl", /* 172 */
+ "ioperm", /* 173 */
+ "create_module", /* 174 */
+ "init_module", /* 175 */
+ "delete_module", /* 176 */
+ "get_kernel_syms", /* 177 */
+ "query_module", /* 178 */
+ "quotactl", /* 179 */
+ "nfsservctl", /* 180 */
+ "getpmsg", /* 181 */
+ "putpmsg", /* 182 */
+ "afs_syscall", /* 183 */
+ "tuxcall", /* 184 */
+ "security", /* 185 */
+ "gettid", /* 186 */
+ "readahead", /* 187 */
+ "setxattr", /* 188 */
+ "lsetxattr", /* 189 */
+ "fsetxattr", /* 190 */
+ "getxattr", /* 191 */
+ "lgetxattr", /* 192 */
+ "fgetxattr", /* 193 */
+ "listxattr", /* 194 */
+ "llistxattr", /* 195 */
+ "flistxattr", /* 196 */
+ "removexattr", /* 197 */
+ "lremovexattr", /* 198 */
+ "fremovexattr", /* 199 */
+ "tkill", /* 200 */
+ "time", /* 201 */
+ "futex", /* 202 */
+ "sched_setaffinity", /* 203 */
+ "sched_getaffinity", /* 204 */
+ "set_thread_area", /* 205 */
+ "io_setup", /* 206 */
+ "io_destroy", /* 207 */
+ "io_getevents", /* 208 */
+ "io_submit", /* 209 */
+ "io_cancel", /* 210 */
+ "get_thread_area", /* 211 */
+ "lookup_dcookie", /* 212 */
+ "epoll_create", /* 213 */
+ "epoll_ctl", /* 214 */
+ "epoll_wait", /* 215 */
+ "remap_file_pages", /* 216 */
+ "getdents64", /* 217 */
+ "set_tid_address", /* 218 */
+ "restart_syscall", /* 219 */
+ "semtimedop", /* 220 */
+ "fadvise64", /* 221 */
+ "timer_create", /* 222 */
+ "timer_settime", /* 223 */
+ "timer_gettime", /* 224 */
+ "timer_getoverrun", /* 225 */
+ "timer_delete", /* 226 */
+ "clock_settime", /* 227 */
+ "clock_gettime", /* 228 */
+ "clock_getres", /* 229 */
+ "clock_nanosleep", /* 230 */
+ "exit_group", /* 231 */
+ "epoll_wait", /* 232 */
+ "epoll_ctl", /* 233 */
+ "tgkill", /* 234 */
+ "utimes", /* 235 */
+ "vserver", /* 236 */
+ "mbind", /* 237 */
+ "set_mempolicy", /* 238 */
+ "get_mempolicy", /* 239 */
+ "mq_open", /* 240 */
+ "mq_unlink", /* 241 */
+ "mq_timedsend", /* 242 */
+ "mq_timedreceive", /* 243 */
+ "mq_notify", /* 244 */
+ "mq_getsetattr", /* 245 */
+ "kexec_load", /* 246 */
+ "waitid", /* 247 */
+ "add_key", /* 248 */
+ "request_key", /* 249 */
+ "keyctl", /* 250 */
+ "ioprio_set", /* 251 */
+ "ioprio_get", /* 252 */
+ "inotify_init", /* 253 */
+ "inotify_add_watch", /* 254 */
+ "inotify_rm_watch", /* 255 */
diff --git a/sysdeps/linux-gnu/x86_64/syscallent1.h b/sysdeps/linux-gnu/x86_64/syscallent1.h
new file mode 100644
index 0000000..d8dd9f7
--- /dev/null
+++ b/sysdeps/linux-gnu/x86_64/syscallent1.h
@@ -0,0 +1 @@
+#include "i386/syscallent.h"
diff --git a/sysdeps/linux-gnu/x86_64/trace.c b/sysdeps/linux-gnu/x86_64/trace.c
new file mode 100644
index 0000000..189734d
--- /dev/null
+++ b/sysdeps/linux-gnu/x86_64/trace.c
@@ -0,0 +1,144 @@
+#include "config.h"
+
+#include <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
index 0000000..b78807e
--- /dev/null
+++ b/testsuite/Makefile
@@ -0,0 +1,71 @@
+# Copyright (C) 1992 - 2001 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 1, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+AUTOMAKE_OPTIONS = dejagnu
+EXPECT = expect
+RUNTEST = runtest
+CC = @CC@
+
+srcdir = .
+RUNTESTDEFAULTFLAGS = --srcdir $(srcdir)
+
+CLEANFILES = *.log *.sum site.bak setval.tmp site.exp
+
+SUBDIRS = ltrace.main ltrace.minor ltrace.torture
+
+#all: all-recursive
+
+.SUFFIXES:
+
+check-DEJAGNU: site.exp
+ EXPECT=$(EXPECT); export EXPECT;
+ @$(RUNTEST) $(RUNTESTDEFAULTFLAGS) $(RUNTESTFLAGS);
+
+site.exp:
+ @echo 'Making a new site.exp file...'
+ @echo '## these variables are automatically generated by make ##' >site.tmp
+ @echo '# Do not edit here. If you wish to override these values' >>site.tmp
+ @echo '# edit the last section' >>site.tmp
+ @echo 'set srcdir $(srcdir)' >>site.tmp
+ @echo "set objdir `pwd`" >>site.tmp
+ @echo '## All variables above are generated by configure. Do Not Edit ##' >>site.tmp
+ @test ! -f site.exp || \
+ sed '1,/^## All variables above are.*##/ d' site.exp >> site.tmp
+ @-rm -f site.bak
+ @test ! -f site.exp || mv site.exp site.bak
+ @mv site.tmp site.exp
+
+check: check-DEJAGNU
+
+clean:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ echo "Making clean in $$subdir"; \
+ (cd $$subdir && $(MAKE) clean ) done;
+
+ -rm -f $(CLEANFILES)
+
+distclean:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ echo "Making clean in $$subdir"; \
+ (cd $$subdir && $(MAKE) distclean ) done;
+ -rm -f $(CLEANFILES)
+
+.PHONY: $(RECURSIVE_TARGETS) check clean distclean realclean
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/testsuite/README b/testsuite/README
new file mode 100644
index 0000000..63d2b3b
--- /dev/null
+++ b/testsuite/README
@@ -0,0 +1,244 @@
+ README for ltrace testsuite
+ 18, October, 2005 by Yao Qi <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
index 0000000..29d28a2
--- /dev/null
+++ b/testsuite/config/unix.exp
@@ -0,0 +1 @@
+load_lib ltrace.exp
diff --git a/testsuite/lib/compiler.c b/testsuite/lib/compiler.c
new file mode 100644
index 0000000..e6b1ec6
--- /dev/null
+++ b/testsuite/lib/compiler.c
@@ -0,0 +1,58 @@
+/* This test file is part of GDB, the GNU debugger.
+
+ Copyright 1995, 1997, 1999, 2003, 2004 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ */
+
+/* Sometimes the behavior of a test depends upon the compiler used to
+ compile the test program. A test script can call get_compiler_info
+ to figure out the compiler version and test_compiler_info to test it.
+
+ get_compiler_info runs the preprocessor on this file and then eval's
+ the result. This sets various symbols for use by test_compiler_info.
+
+ TODO: make compiler_info a local variable for get_compiler_info and
+ test_compiler_info.
+
+ TODO: all clients should use test_compiler_info and should not
+ use gcc_compiled, hp_cc_compiler, or hp_aCC_compiler.
+
+ */
+
+/* Note the semicolon at the end of this line. Older versions of
+ hp c++ have a bug in string preprocessing: if the last token on a
+ line is a string, then the preprocessor concatenates the next line
+ onto the current line and eats the newline! That messes up TCL of
+ course. That happens with HP aC++ A.03.13, but it no longer happens
+ with HP aC++ A.03.45. */
+
+set compiler_info "unknown" ;
+
+#if defined (__GNUC__)
+#if defined (__GNUC_PATCHLEVEL__)
+/* Only GCC versions >= 3.0 define the __GNUC_PATCHLEVEL__ macro. */
+set compiler_info [join {gcc __GNUC__ __GNUC_MINOR__ __GNUC_PATCHLEVEL__} -]
+#else
+set compiler_info [join {gcc __GNUC__ __GNUC_MINOR__ "unknown"} -]
+#endif
+#endif
+
+#if defined (__xlc__)
+/* IBM'x xlc compiler. NOTE: __xlc__ expands to a double quoted string of four
+ numbers seperated by '.'s: currently "7.0.0.0" */
+set need_a_set [regsub -all {\.} [join {xlc __xlc__} -] - compiler_info]
+#endif
diff --git a/testsuite/lib/compiler.cc b/testsuite/lib/compiler.cc
new file mode 100644
index 0000000..7068462
--- /dev/null
+++ b/testsuite/lib/compiler.cc
@@ -0,0 +1,45 @@
+/* This test file is part of GDB, the GNU debugger.
+
+ Copyright 1995, 1999, 2003, 2004 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ */
+
+/* This file is exactly like compiler.c. I could just use compiler.c if
+ I could be sure that every C++ compiler accepted extensions of ".c". */
+
+/* Note the semicolon at the end of this line. Older versions of
+ hp c++ have a bug in string preprocessing: if the last token on a
+ line is a string, then the preprocessor concatenates the next line
+ onto the current line and eats the newline! That messes up TCL of
+ course. That happens with HP aC++ A.03.13, but it no longer happens
+ with HP aC++ A.03.45. */
+
+set compiler_info "unknown" ;
+
+#if defined (__GNUC__)
+#if defined (__GNUC_PATCHLEVEL__)
+/* Only GCC versions >= 3.0 define the __GNUC_PATCHLEVEL__ macro. */
+set compiler_info [join {gcc __GNUC__ __GNUC_MINOR__ __GNUC_PATCHLEVEL__} -]
+#else
+set compiler_info [join {gcc __GNUC__ __GNUC_MINOR__ "unknown"} -]
+#endif
+#endif
+
+#if defined (__xlC__)
+/* xlC++ version like 800 */
+set compiler_info [join {xlc++ __IBMCPP__} -]
+#endif
diff --git a/testsuite/lib/ltrace.exp b/testsuite/lib/ltrace.exp
new file mode 100644
index 0000000..b56d50d
--- /dev/null
+++ b/testsuite/lib/ltrace.exp
@@ -0,0 +1,279 @@
+# This file was written by Yao Qi. (qiyao@cn.ibm.com)
+
+# Generic ltrace test subroutines that should work for any target. If these
+# need to be modified for any target, it can be done with a variable
+# or by passing arguments.
+
+
+global LTRACE
+if [info exists TOOL_EXECUTABLE] {
+ set LTRACE $TOOL_EXECUTABLE
+} else {
+ set LTRACE $objdir/../ltrace
+}
+
+global LTRACE_OPTIONS
+set LTRACE_OPTIONS "";
+
+# ltrace_compile SOURCE DEST TYPE OPTIONS
+#
+# Compile PUT(program under test) by native compiler. ltrace_compile runs
+# the right compiler, and TCL captures the output, and I evaluate the output.
+#
+# SOURCE is the name of program under test, with full directory.
+# DEST is the name of output of compilation, with full directory.
+# TYPE is an enum-like variable to affect the format or result of compiler
+# output. Values:
+# executable if output is an executable.
+# object if output is an object.
+# OPTIONS is option to compiler in this compilation.
+proc ltrace_compile {source dest type options} {
+ global LTRACE_TESTCASE_OPTIONS;
+
+ # Add platform-specific options if a shared library was specified using
+ # "shlib=librarypath" in OPTIONS.
+ set new_options ""
+ set shlib_found 0
+
+ foreach opt $options {
+ if [regexp {^shlib=(.*)} $opt dummy_var shlib_name] {
+ if [test_compiler_info "xlc*"] {
+ # IBM xlc compiler doesn't accept shared library named other
+ # than .so: use "-Wl," to bypass this
+ lappend source "-Wl,$shlib_name"
+ } else {
+ lappend source $shlib_name
+ }
+
+ if {$shlib_found == 0} {
+ set shlib_found 1
+
+ if { ([test_compiler_info "gcc-*"]&& ([istarget "powerpc*-*-aix*"]|| [istarget "rs6000*-*-aix*"] ))} {
+ lappend options "additional_flags=-L${objdir}/${subdir}"
+ } elseif { [istarget "mips-sgi-irix*"] } {
+ lappend options "additional_flags=-rpath ${objdir}/${subdir}"
+ }
+ }
+
+ } else {
+ lappend new_options $opt
+ }
+ }
+ #end of for loop
+ set options $new_options
+ # dump some information for debug purpose.
+ verbose "options are $options"
+ verbose "source is $source $dest $type $options"
+
+ set result [target_compile $source $dest $type $options];
+ verbose "result is $result"
+ regsub "\[\r\n\]*$" "$result" "" result;
+ regsub "^\[\r\n\]*" "$result" "" result;
+ if { $result != "" && [lsearch $options quiet] == -1} {
+ clone_output "compile failed for ltrace test, $result"
+ }
+ return $result;
+}
+
+proc get_compiler_info {binfile args} {
+ # For compiler.c and compiler.cc
+ global srcdir
+
+ # I am going to play with the log to keep noise out.
+ global outdir
+ global tool
+
+ # These come from compiler.c or compiler.cc
+ global compiler_info
+
+ # Legacy global data symbols.
+ #global gcc_compiled
+
+ # Choose which file to preprocess.
+ set ifile "${srcdir}/lib/compiler.c"
+ if { [llength $args] > 0 && [lindex $args 0] == "c++" } {
+ set ifile "${srcdir}/lib/compiler.cc"
+ }
+
+ # Run $ifile through the right preprocessor.
+ # Toggle ltrace.log to keep the compiler output out of the log.
+ #log_file
+ set cppout [ ltrace_compile "${ifile}" "" preprocess [list "$args" quiet] ]
+ #log_file -a "$outdir/$tool.log"
+
+ # Eval the output.
+ set unknown 0
+ foreach cppline [ split "$cppout" "\n" ] {
+ if { [ regexp "^#" "$cppline" ] } {
+ # line marker
+ } elseif { [ regexp "^\[\n\r\t \]*$" "$cppline" ] } {
+ # blank line
+ } elseif { [ regexp "^\[\n\r\t \]*set\[\n\r\t \]" "$cppline" ] } {
+ # eval this line
+ verbose "get_compiler_info: $cppline" 2
+ eval "$cppline"
+ } else {
+ # unknown line
+ verbose "get_compiler_info: $cppline"
+ set unknown 1
+ }
+ }
+
+ # Reset to unknown compiler if any diagnostics happened.
+ if { $unknown } {
+ set compiler_info "unknown"
+ }
+ return 0
+}
+
+proc test_compiler_info { {compiler ""} } {
+ global compiler_info
+ verbose "compiler_info=$compiler_info"
+ # if no arg, return the compiler_info string
+
+ if [string match "" $compiler] {
+ if [info exists compiler_info] {
+ return $compiler_info
+ } else {
+ perror "No compiler info found."
+ }
+ }
+
+ return [string match $compiler $compiler_info]
+}
+
+proc ltrace_compile_shlib {sources dest options} {
+ set obj_options $options
+ verbose "+++++++ [test_compiler_info]"
+ switch -glob [test_compiler_info] {
+ "xlc-*" {
+ lappend obj_options "additional_flags=-qpic"
+ }
+ "gcc-*" {
+ if { !([istarget "powerpc*-*-aix*"]
+ || [istarget "rs6000*-*-aix*"]) } {
+ lappend obj_options "additional_flags=-fpic"
+ }
+ }
+ "xlc++-*" {
+ lappend obj_options "additional_flags=-qpic"
+ }
+
+ default {
+ fail "Bad compiler!"
+ }
+ }
+
+ set outdir [file dirname $dest]
+ set objects ""
+ foreach source $sources {
+ set sourcebase [file tail $source]
+ if {[ltrace_compile $source "${outdir}/${sourcebase}.o" object $obj_options] != ""} {
+ return -1
+ }
+ lappend objects ${outdir}/${sourcebase}.o
+ }
+
+ set link_options $options
+ if { [test_compiler_info "xlc-*"] || [test_compiler_info "xlc++-*"]} {
+ lappend link_options "additional_flags=-qmkshrobj"
+ } else {
+ lappend link_options "additional_flags=-shared"
+ }
+ if {[ltrace_compile "${objects}" "${dest}" executable $link_options] != ""} {
+ return -1
+ }
+}
+
+#
+# ltrace_options OPTIONS_LIST
+# Pass ltrace commandline options.
+#
+proc ltrace_options { args } {
+
+ global LTRACE_OPTIONS
+ set LTRACE_OPTIONS $args
+}
+
+#
+# ltrace_runtest LD_LIBRARY_PATH BIN FILE
+# Trace the execution of BIN and return result.
+#
+# BIN is program-under-test.
+# LD_LIBRARY_PATH is the env for program-under-test to run.
+# FILE is to save the output from ltrace with default name $BIN.ltrace.
+# Retrun output from ltrace.
+#
+proc ltrace_runtest { args } {
+
+ global LTRACE
+ global LTRACE_OPTIONS
+
+ verbose "LTRACE = $LTRACE"
+
+ set LD_LIBRARY_PATH_ [lindex $args 0]
+ set BIN [lindex $args 1]
+
+ # specify the output file, the default one is $BIN.ltrace
+ if [llength $args]==3 then {
+ set file [lindex $args 2]
+ } else {
+ set file $BIN.ltrace
+ }
+ # append this option to LTRACE_OPTIONS.
+ lappend LTRACE_OPTIONS "-o"
+ lappend LTRACE_OPTIONS "$file"
+ verbose "LTRACE_OPTIONS = $LTRACE_OPTIONS"
+ #ltrace the PUT.
+ catch "exec sh -c {export LD_LIBRARY_PATH=$LD_LIBRARY_PATH_; $LTRACE $LTRACE_OPTIONS $BIN;exit}" output
+
+ # return output from ltrace.
+ return $output
+}
+
+#
+# ltrace_saveoutput OUTPUT FILE
+# Save OUTPUT from ltrace to file FILE.
+# OUTPUT is output from ltrace or return value of ltrace_runtest.
+# FILE is file save output.
+#
+proc ltrace_saveoutput { args } {
+
+ set output [lindex $args 0]
+ set file [lindex $args 1]
+
+ set fd [open $file w]
+ puts $fd $output
+ close $fd
+}
+
+
+#
+# ltrace_verify_output FILE_TO_SEARCH PATTERN MAX_LINE
+# Verify the ltrace output by comparing the number of PATTERN in
+# FILE_TO_SEARCH with INSTANCE_NO. Do not specify INSTANCE_NO if
+# instance number is ignored in this test.
+# Reutrn:
+# 0 = number of PATTERN in FILE_TO_SEARCH inqual to INSTANCE_NO.
+# 1 = number of PATTERN in FILE_TO_SEARCH qual to INSTANCE_NO.
+#
+proc ltrace_verify_output { file_to_search pattern {instance_no 0}} {
+
+ # compute the number of PATTERN in FILE_TO_SEARCH by grep and wc.
+ catch "exec sh -c {grep \"$pattern\" $file_to_search | wc -l ;exit}" output
+ verbose "output = $output"
+
+ if [ regexp "syntax error" $output ] then {
+ fail "Invalid regular expression $pattern"
+ } elseif { $instance_no == 0 } then {
+ if { $output == 0 } then {
+ fail "Fail to find $pattern in $file_to_search"
+ } else {
+ pass "$pattern in $file_to_search"
+ }
+ } elseif { $output >= $instance_no } then {
+ pass "$pattern in $file_to_search for $output times"
+ } else {
+ fail "$pattern in $file_to_search for $output times ,should be $instance_no"
+ }
+}
diff --git a/testsuite/ltrace.main/Makefile b/testsuite/ltrace.main/Makefile
new file mode 100644
index 0000000..449214a
--- /dev/null
+++ b/testsuite/ltrace.main/Makefile
@@ -0,0 +1,33 @@
+# Copyright (C) 1992 - 2001 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 1, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+CLEANFILES = *.log *.sum site.bak setval.tmp site.exp
+
+.SUFFIXES:
+clean:
+ -rm -f main main-internal system_calls signals parameters
+ -rm -f *.o *.so
+ -rm -f *.ltrace
+ -rm -f $(CLEANFILES)
+distclean: clean
+
+
+.PHONY: $(RECURSIVE_TARGETS) check clean distclean realclean
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/testsuite/ltrace.main/main-internal-1.c b/testsuite/ltrace.main/main-internal-1.c
new file mode 100644
index 0000000..2a5cd0c
--- /dev/null
+++ b/testsuite/ltrace.main/main-internal-1.c
@@ -0,0 +1,8 @@
+#include<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
index 0000000..7508d06
--- /dev/null
+++ b/testsuite/ltrace.main/main-internal.c
@@ -0,0 +1,19 @@
+ /* Ltrace Test : main-internal.c.
+ Objectives : Verify that ltrace can trace call from main
+ executable within it.
+ This file was written by Yao Qi <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
index 0000000..f3f0015
--- /dev/null
+++ b/testsuite/ltrace.main/main-internal.exp
@@ -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
index 0000000..5fd53b3
--- /dev/null
+++ b/testsuite/ltrace.main/main-lib.c
@@ -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
index 0000000..0f270bf
--- /dev/null
+++ b/testsuite/ltrace.main/main.c
@@ -0,0 +1,21 @@
+/* Ltrace Test : main.c.
+ Objectives : Verify that ltrace can trace call a library function
+ from main executable.
+
+ This file was written by Yao Qi <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
index 0000000..ca66deb
--- /dev/null
+++ b/testsuite/ltrace.main/main.exp
@@ -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
index 0000000..26e4c3b
--- /dev/null
+++ b/testsuite/ltrace.main/parameters-lib.c
@@ -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
index 0000000..dd63612
--- /dev/null
+++ b/testsuite/ltrace.main/parameters.c
@@ -0,0 +1,120 @@
+/* Ltrace Test : parameters.c.
+ Objectives : Verify that Ltrace can handle all the different
+ parameter types
+
+ This file was written by Steve Fink <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
index 0000000..33c1a1e
--- /dev/null
+++ b/testsuite/ltrace.main/parameters.conf
@@ -0,0 +1,15 @@
+void func_intptr(int*)
+void func_intptr_ret(+int*)
+int func_strlen(+string[retval])
+void func_strfixed(string[4])
+void func_ppp(int***)
+void func_stringp(string*)
+void func_enum(enum (RED=0,GREEN=1,BLUE=2,CHARTREUSE=3,PETUNIA=4))
+void func_short(short,short)
+void func_ushort(ushort, ushort)
+void func_float(float,float)
+typedef color = enum (RED=0,GREEN=1,BLUE=2,CHARTREUSE=3,PETUNIA=4)
+void func_typedef(color)
+void func_arrayi(array(int,arg2)*,void)
+void func_arrayf(array(float,arg2)*,void)
+void func_struct(struct(int,int,int,array(struct(int,int),elt2)*,array(struct(int,int),3),string[elt3])*)
diff --git a/testsuite/ltrace.main/parameters.exp b/testsuite/ltrace.main/parameters.exp
new file mode 100644
index 0000000..bb55e03
--- /dev/null
+++ b/testsuite/ltrace.main/parameters.exp
@@ -0,0 +1,72 @@
+# This file was written by Steve Fink <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
index 0000000..a02e795
--- /dev/null
+++ b/testsuite/ltrace.main/signals.c
@@ -0,0 +1,48 @@
+/* Ltrace Test : signals.c.
+ Objectives : Verify that ltrace can trace user defined signal.
+ This file was written by Yao Qi <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
index 0000000..f0708e9
--- /dev/null
+++ b/testsuite/ltrace.main/signals.exp
@@ -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
index 0000000..7be3d04
--- /dev/null
+++ b/testsuite/ltrace.main/system_calls.c
@@ -0,0 +1,68 @@
+/* Ltrace Test : system_calls.c.
+ Objectives : Verify that Ltrace can trace all the system calls in
+ execution.
+
+ You can add new system calls in it and add its verification in
+ system_calls correspondingly.
+
+ This file was written by Yao Qi <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
index 0000000..b274db5
--- /dev/null
+++ b/testsuite/ltrace.main/system_calls.exp
@@ -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
index 0000000..cd4914f
--- /dev/null
+++ b/testsuite/ltrace.minor/Makefile
@@ -0,0 +1,36 @@
+# Copyright (C) 1992 - 2001 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 1, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+CLEANFILES = *.log *.sum site.bak setval.tmp site.exp
+
+.SUFFIXES:
+clean:
+ -rm -f demangle trace-fork trace-clone trace-exec trace-exec1
+ -rm -f time-record-tt time-record-ttt time-record-T
+ -rm -f attach-process count-record
+ -rm -f print-instruction-pointer
+ -rm -f *.o *.so
+ -rm -f *.ltrace
+ -rm -f $(CLEANFILES)
+distclean: clean
+
+
+.PHONY: $(RECURSIVE_TARGETS) check clean distclean realclean
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/testsuite/ltrace.minor/attach-process.c b/testsuite/ltrace.minor/attach-process.c
new file mode 100644
index 0000000..4c00bce
--- /dev/null
+++ b/testsuite/ltrace.minor/attach-process.c
@@ -0,0 +1,16 @@
+/* Ltrace Test : attach-process.c.
+ Objectives : Verify that ltrace can attach to a running process
+ by its PID.
+
+ This file was written by Yao Qi <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
index 0000000..ab5460e
--- /dev/null
+++ b/testsuite/ltrace.minor/attach-process.exp
@@ -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
index 0000000..3b609ad
--- /dev/null
+++ b/testsuite/ltrace.minor/count-record.c
@@ -0,0 +1,51 @@
+/* Ltrace Test : count-record.c.
+ Objectives : Verify that Ltrace can count all the system calls in
+ execution and report a summary on exit.
+
+ This file was written by Yao Qi <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
index 0000000..f8c4923
--- /dev/null
+++ b/testsuite/ltrace.minor/count-record.exp
@@ -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
index 0000000..01ab18d
--- /dev/null
+++ b/testsuite/ltrace.minor/demangle-lib.cpp
@@ -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
index 0000000..14cc9f6
--- /dev/null
+++ b/testsuite/ltrace.minor/demangle.cpp
@@ -0,0 +1,121 @@
+/* Ltrace Test : demangle.cpp
+ Objectives : Verify that ltrace can demangle C++ symbols.
+
+ This file was written by Yao Qi <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
index 0000000..5077ac0
--- /dev/null
+++ b/testsuite/ltrace.minor/demangle.exp
@@ -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
index 0000000..02aa156
--- /dev/null
+++ b/testsuite/ltrace.minor/demangle.h
@@ -0,0 +1,36 @@
+
+class myclass {
+ int myint;
+ public:
+ myclass(int x);
+ myclass(void);
+ ~myclass();
+ static int Fis_i(int bar);
+ int Fi_i(int bar);
+ /* Overloaded operators */
+ void* operator new(size_t);
+ void operator delete(void *);
+ /* Unary operation. */
+ myclass operator++();// Preincrement
+ myclass operator++(int);// Postincrement
+
+ /* Binary operation. */
+ myclass operator+(int);
+
+ /* Assignment */
+ myclass& operator=(const myclass& from);
+ /* Nested classes */
+ class nested {
+ public:
+ nested();
+ ~nested();
+ int Fi_i(int bar);
+ };
+};
+
+class nested {
+ public:
+ nested();
+ ~nested();
+ int Fi_i(int bar);
+};
diff --git a/testsuite/ltrace.minor/print-instruction-pointer.c b/testsuite/ltrace.minor/print-instruction-pointer.c
new file mode 100644
index 0000000..37b8441
--- /dev/null
+++ b/testsuite/ltrace.minor/print-instruction-pointer.c
@@ -0,0 +1,11 @@
+#include <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
index 0000000..87cc8f7
--- /dev/null
+++ b/testsuite/ltrace.minor/print-instruction-pointer.exp
@@ -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
index 0000000..b411add
--- /dev/null
+++ b/testsuite/ltrace.minor/time-record-T.exp
@@ -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
index 0000000..332704a
--- /dev/null
+++ b/testsuite/ltrace.minor/time-record-tt.exp
@@ -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
index 0000000..2aee9d3
--- /dev/null
+++ b/testsuite/ltrace.minor/time-record-ttt.exp
@@ -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
index 0000000..a66b838
--- /dev/null
+++ b/testsuite/ltrace.minor/time-record.c
@@ -0,0 +1,23 @@
+/* Ltrace Test : time-record.c.
+ Objectives : Verify that Ltrace can record timestamp and spent
+ time inside each call.
+
+ This file was written by Yao Qi <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
index 0000000..a1ccb22
--- /dev/null
+++ b/testsuite/ltrace.minor/trace-clone.c
@@ -0,0 +1,38 @@
+/* Ltrace Test : trace-clone.c.
+ Objectives : Verify that ltrace can trace to child process after
+ clone called.
+
+ This file was written by Yao Qi <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
index 0000000..bda036f
--- /dev/null
+++ b/testsuite/ltrace.minor/trace-clone.exp
@@ -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
index 0000000..e798cde
--- /dev/null
+++ b/testsuite/ltrace.minor/trace-exec.c
@@ -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
index 0000000..c9de6f3
--- /dev/null
+++ b/testsuite/ltrace.minor/trace-exec.exp
@@ -0,0 +1,45 @@
+set testfile "trace-exec"
+set srcfile ${testfile}.c
+set binfile ${testfile}
+
+verbose "compiling first source file now....."
+if { [ ltrace_compile "${srcdir}/${subdir}/${testfile}.c" "${srcdir}/${subdir}/${binfile}" executable {debug} ] != "" } {
+ send_user "Testcase compile failed, so all tests in this file will automatically fail.\n"
+}
+
+verbose "compiling second source file now....."
+if { [ ltrace_compile "${srcdir}/${subdir}/${testfile}1.c" "${srcdir}/${subdir}/${binfile}1" executable {debug} ] != "" } {
+ send_user "Testcase compile failed, so all tests in this file will automatically fail.\n"
+}
+
+global LTRACE
+set exec_output ""
+
+#Run PUT for ltrace.
+spawn $LTRACE $srcdir/$subdir/$testfile $srcdir/$subdir/${testfile}1
+set timeout 4
+expect timeout {
+ fail "Time out! Maybe caused by ltrace segment fault or improper timeout value here!"
+ return
+}
+
+catch "exec $LTRACE $srcdir/$subdir/$testfile $srcdir/$subdir/${testfile}1" exec_output
+
+#check the output of this program.
+verbose "ltrace runtest output: $exec_output\n"
+if [regexp {ELF from incompatible architecture} $exec_output] {
+ fail "32-bit ltrace can not perform on 64-bit PUTs and rebuild ltrace in 64 bit mode!"
+ return
+} elseif [ regexp {Couldn't get .hash data} $exec_output ] {
+ fail "Couldn't get .hash data!"
+ return
+}
+
+ltrace_saveoutput "${exec_output}" ${srcdir}/${subdir}/${testfile}.ltrace
+
+# execl from first binary
+ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace {"^execl"} 1
+# puts from second binary
+ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace {"^puts"} 1
+# assume glibc and see we really trace both binaries
+ltrace_verify_output ${srcdir}/${subdir}/${testfile}.ltrace {"^__libc_start_main"} 2
diff --git a/testsuite/ltrace.minor/trace-exec1.c b/testsuite/ltrace.minor/trace-exec1.c
new file mode 100644
index 0000000..e234fa0
--- /dev/null
+++ b/testsuite/ltrace.minor/trace-exec1.c
@@ -0,0 +1,6 @@
+#include <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
index 0000000..a2d8a56
--- /dev/null
+++ b/testsuite/ltrace.minor/trace-fork.c
@@ -0,0 +1,33 @@
+/* Ltrace Test : trace-fork.c
+ Objectives : Verify that ltrace can trace to child process after
+ fork called.
+
+ This file was written by Yao Qi <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
index 0000000..5f30061
--- /dev/null
+++ b/testsuite/ltrace.minor/trace-fork.exp
@@ -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
index 0000000..bb4baa0
--- /dev/null
+++ b/testsuite/ltrace.torture/Makefile
@@ -0,0 +1,33 @@
+# Copyright (C) 1992 - 2001 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 1, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+CLEANFILES = *.log *.sum site.bak setval.tmp site.exp
+
+.SUFFIXES:
+clean:
+ -rm -f signals
+ -rm -f *.o *.so
+ -rm -f *.ltrace
+ -rm -f $(CLEANFILES)
+distclean: clean
+
+
+.PHONY: $(RECURSIVE_TARGETS) check clean distclean realclean
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/testsuite/ltrace.torture/ia64-sigill.exp b/testsuite/ltrace.torture/ia64-sigill.exp
new file mode 100644
index 0000000..c4cf5a2
--- /dev/null
+++ b/testsuite/ltrace.torture/ia64-sigill.exp
@@ -0,0 +1,33 @@
+# This file was written by Yao Qi <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
index 0000000..dccb674
--- /dev/null
+++ b/testsuite/ltrace.torture/ia64-sigill.s
@@ -0,0 +1,43 @@
+ .file "pokus.c"
+ .pred.safe_across_calls p1-p5,p16-p63
+ .section .rodata
+ .align 8
+.LC0:
+ stringz ""
+ .text
+ .align 16
+ .global main#
+ .proc main#
+main:
+ .prologue 14, 32
+ .save ar.pfs, r33
+ alloc r33 = ar.pfs, 0, 4, 1, 0
+ .vframe r34
+ mov r34 = r12
+ mov r35 = r1
+ .save rp, r32
+ mov r32 = b0
+ .body
+ addl r36 = @ltoffx(.LC0), r1
+ ;;
+ ld8.mov r36 = [r36], .LC0
+ br.call.sptk.many b0 = printf#
+ nop.b 0x0
+ nop.b 0x1
+ nop.b 0x2
+ nop.b 0x0
+ nop.b 0x1
+ nop.b 0x2
+ mov r1 = r35
+ addl r14 = 234, r0
+ ;;
+ mov r8 = r14
+ mov ar.pfs = r33
+ mov b0 = r32
+ .restore sp
+ mov r12 = r34
+ br.ret.sptk.many b0
+ ;;
+ .endp main#
+ .section .note.GNU-stack,"",@progbits
+ .ident "GCC: (GNU) 3.4.6 20060404 (Red Hat 3.4.6-3)"
diff --git a/testsuite/ltrace.torture/signals.c b/testsuite/ltrace.torture/signals.c
new file mode 100644
index 0000000..439aba1
--- /dev/null
+++ b/testsuite/ltrace.torture/signals.c
@@ -0,0 +1,44 @@
+/* Ltrace Test : signals.c.
+ Objectives : Verify that ltrace can trace user defined signal.
+ This file was written by Yao Qi <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
index 0000000..56a2ec9
--- /dev/null
+++ b/testsuite/ltrace.torture/signals.exp
@@ -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
index 0000000..3882c79
--- /dev/null
+++ b/testsuite/run-my-tests.sh
@@ -0,0 +1,43 @@
+#! /bin/sh
+bitmode=""
+
+# This shell script is used to run the ltrace test suite. It is possible to
+# run it via 'make check' using RUNTESTFLAGS. This script just makes it easy.
+
+function usage
+{
+ echo usage: `basename $0` '-m32|-m64 [<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"