summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJiri Olsa <jolsa@shell.devel.redhat.com>2009-09-04 02:29:08 -0400
committerJiri Olsa <jolsa@shell.devel.redhat.com>2009-09-04 02:29:08 -0400
commit04f3fbbfdb3a5dd197dbc25ca18ad244f1fbf6a5 (patch)
tree8e53039a4f5d1a4571000bc06214053261aebf8d
downloadlatrace-04f3fbbfdb3a5dd197dbc25ca18ad244f1fbf6a5.tar.gz
latrace-04f3fbbfdb3a5dd197dbc25ca18ad244f1fbf6a5.tar.xz
latrace-04f3fbbfdb3a5dd197dbc25ca18ad244f1fbf6a5.zip
initial commit - 0.5.7
-rw-r--r--COPYING674
-rw-r--r--ChangeLog247
-rw-r--r--Makefile218
-rw-r--r--README40
-rw-r--r--ReleaseNotes85
-rw-r--r--TODO33
-rw-r--r--configure.ac91
-rw-r--r--doc/Makefile25
-rw-r--r--doc/asciidoc.conf.in6
-rw-r--r--doc/latrace.txt434
-rw-r--r--etc/latrace.conf.in100
-rw-r--r--etc/latrace.d/arch-arm.conf0
-rw-r--r--etc/latrace.d/arch-i686.conf0
-rw-r--r--etc/latrace.d/arch-x86_64.conf3
-rw-r--r--etc/latrace.d/ctype.conf20
-rw-r--r--etc/latrace.d/dirent.conf31
-rw-r--r--etc/latrace.d/dlfcn.conf12
-rw-r--r--etc/latrace.d/fcntl.conf18
-rw-r--r--etc/latrace.d/getopt.conf7
-rw-r--r--etc/latrace.d/inet.conf18
-rw-r--r--etc/latrace.d/ioctl.conf4
-rw-r--r--etc/latrace.d/libintl.conf14
-rw-r--r--etc/latrace.d/libio.conf29
-rw-r--r--etc/latrace.d/locale.conf9
-rw-r--r--etc/latrace.d/misc.conf7
-rw-r--r--etc/latrace.d/mman.conf25
-rw-r--r--etc/latrace.d/ncurses.conf334
-rw-r--r--etc/latrace.d/netdb.conf110
-rw-r--r--etc/latrace.d/pthread.conf162
-rw-r--r--etc/latrace.d/pwd.conf29
-rw-r--r--etc/latrace.d/resource.conf73
-rw-r--r--etc/latrace.d/signal.conf100
-rw-r--r--etc/latrace.d/socket.conf78
-rw-r--r--etc/latrace.d/stat.conf54
-rw-r--r--etc/latrace.d/stdio.conf137
-rw-r--r--etc/latrace.d/stdlib.conf210
-rw-r--r--etc/latrace.d/string.conf85
-rw-r--r--etc/latrace.d/syslog.conf8
-rw-r--r--etc/latrace.d/term.conf40
-rw-r--r--etc/latrace.d/termios.conf28
-rw-r--r--etc/latrace.d/time.conf65
-rw-r--r--etc/latrace.d/typedefs.conf27
-rw-r--r--etc/latrace.d/unistd.conf170
-rw-r--r--etc/latrace.d/utmp.conf30
-rw-r--r--etc/latrace.d/wait.conf18
-rw-r--r--etc/sysdeps/x86_64/syscall.conf303
-rw-r--r--package/debian/changelog5
-rw-r--r--package/debian/conffiles30
-rw-r--r--package/debian/control18
-rw-r--r--package/debian/copyright21
-rw-r--r--package/debian/rules47
-rw-r--r--package/rpm/latrace.spec52
-rw-r--r--src/Makefile67
-rw-r--r--src/args-bison.y302
-rw-r--r--src/args-flex.l89
-rw-r--r--src/args.c1066
-rw-r--r--src/audit-init.c196
-rw-r--r--src/audit.c287
-rw-r--r--src/audit.h102
-rw-r--r--src/autoconf.h.in36
-rw-r--r--src/autoconf.make.in42
-rw-r--r--src/config.c293
-rw-r--r--src/config.h417
-rw-r--r--src/fifo.c150
-rw-r--r--src/latrace.c45
-rw-r--r--src/list.h103
-rw-r--r--src/objsearch.c192
-rw-r--r--src/output.c125
-rw-r--r--src/run.c319
-rw-r--r--src/stats.c328
-rw-r--r--src/sysdeps/arm/stack.c269
-rw-r--r--src/sysdeps/i686/stack.c131
-rw-r--r--src/sysdeps/i686/stack.h27
-rw-r--r--src/sysdeps/x86_64/stack.c615
-rw-r--r--src/sysdeps/x86_64/stack.h90
-rw-r--r--src/thread.c61
-rw-r--r--test/test1.c278
77 files changed, 10014 insertions, 0 deletions
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..94a9ed0
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. 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
+them 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 prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. 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.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey 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;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If 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 convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU 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 that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ 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.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+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.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ 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
+state 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 3 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, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ <program> Copyright (C) <year> <name of author>
+ This program 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, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+ The GNU 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 Lesser General
+Public License instead of this License. But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..35b09f0
--- /dev/null
+++ b/ChangeLog
@@ -0,0 +1,247 @@
+2009-09-04 Jiri Olsa <olsajiri@gmail.com>
+ * 0.5.7 release changes
+
+2009-08-21 Jiri Olsa <olsajiri@gmail.com>
+ * added '-B' option to always display the { } around the symbol body
+ * minor code sttyle changes
+
+2009-08-20 Jiri Olsa <olsajiri@gmail.com>
+ * added C++ demangling support - "-d" option
+
+-------------------------------------------------------------------------------
+latrace 0.5.6
+
+2009-07-06 Jiri Olsa <olsajiri@gmail.com>
+ * changes for the rpm review
+ * 0.5.6 release changes
+
+2009-07-04 Jiri Olsa <olsajiri@gmail.com>
+ * minor changes for the rpm review
+
+2009-07-02 Jiri Olsa <olsajiri@gmail.com>
+ * adding --unsafe for asciidoc to workaround
+ build on the Fedora Rawhide
+
+2009-07-01 Jiri Olsa <olsajiri@gmail.com>
+ * adding %postun %post to latrace.spec & several minor
+ changes based on the Fedora rpm review
+
+2009-06-13 Jiri Olsa <olsajiri@gmail.com>
+ * added latrace.spec for rpm pkg. building
+ * minor Makefile mrproper change
+
+2009-06-06 Jiri Olsa <olsajiri@gmail.com>
+ * added support pointers in typedef
+ * fixed minor bug for pointer output
+ * added more checks to configure.ac
+ * make mrproper real propper
+
+2009-05-13 Jiri Olsa <olsajiri@gmail.com>
+ * added DESTDIR makefile support
+
+-------------------------------------------------------------------------------
+latrace 0.5.5
+
+2009-04-25 Jiri Olsa <olsajiri@gmail.com>
+ * fixed arch dependent enum handling
+ * fixed config file line number tracking
+
+2009-04-25 Jiri Olsa <olsajiri@gmail.com>
+ * release notes for 0.5.5
+
+2009-04-22 Jiri Olsa <olsajiri@gmail.com>
+ * main Makefile changes - adding the package target
+
+2009-04-17 Jiri Olsa <olsajiri@gmail.com>
+ * install function - skip the install if the file does not exist
+
+2009-04-15 Jiri Olsa <olsajiri@gmail.com>
+ * adding syscall.conf for x86_64
+
+2009-04-10 Jiri Olsa <olsajiri@gmail.com>
+ * getstr_pod/enum redesign
+ * added etc/latrace.d/mman.conf
+
+2009-04-08 Jiri Olsa <olsajiri@gmail.com>
+ * enum minor changes
+ * added etc/latrace.d/resource.conf
+
+2009-04-07 Jiri Olsa <olsajiri@gmail.com>
+ * added 'pcC' options for x86_64, since it looks
+ glibc bug 7055 got fixed somehow
+
+ glibc bug 7055 - LD_AUDIT - gettimeofday function
+ segfaults if called from interface
+
+2009-04-03 Jiri Olsa <olsajiri@gmail.com>
+ * added doc enum part
+
+2009-04-01 Jiri Olsa <olsajiri@gmail.com>
+ * added enum support
+
+2009-03-30 Jiri Olsa <olsajiri@gmail.com>
+ * stats - syntax changes
+ * stats - added -C sym, fixed -C lib
+
+2009-03-24 Jiri Olsa <olsajiri@gmail.com>
+ * removing stack.h include from generic parts
+ * fix PRINT_VERBOSE[12] for x86_64
+ * doc changes
+
+2009-03-17 Jiri Olsa <olsajiri@gmail.com>
+ * doc changes
+
+2009-03-14 Jiri Olsa <olsajiri@gmail.com>
+ * unify the PRINT_VERBOSE[12] to one method only PRINT_VERBOSE
+ * unify the ERROR[12] to one method only ERROR
+
+2009-03-09 Jiri Olsa <olsajiri@gmail.com>
+ * minor attribute changes
+
+2009-03-08 Jiri Olsa <olsajiri@gmail.com>
+ * adding cscope support
+
+2009-03-08 Jiri Olsa <olsajiri@gmail.com>
+ * adding Makefile support for checking prefix and CFLAGS changes
+ (stolen from git sources)
+
+2009-03-07 Jiri Olsa <olsajiri@gmail.com>
+ * introducing asciidoc man page, needs more formatting changes...
+
+2009-03-06 Jiri Olsa <olsajiri@gmail.com>
+ * added -F option to disable fork following
+ * added -E option to disable exec following
+
+2009-03-05 Jiri Olsa <olsajiri@gmail.com>
+ * added -T option to hide thread id
+
+2009-03-05 Jiri Olsa <olsajiri@gmail.com>
+ * x86_64 - fixed argument display (fixed glibc bug 9893,
+ not sure when the glibc fix will be available,
+ need to consider the option availibility before next
+ release
+
+-------------------------------------------------------------------------------
+latrace 0.5.4
+
+2009-02-28 Jiri Olsa <olsajiri@gmail.com>
+ * release notes for 0.5.4
+ * man page update
+
+2009-02-28 Jiri Olsa <olsajiri@gmail.com>
+ * x86_64 code refactoring
+ * introduced glibc bug 9893, and disabled 'AaD' options because of that
+ updated man page with this info
+ * added more functions to the test1.c
+ * removed i386 link as it was useless
+
+2009-02-16 Jiri Olsa <olsajiri@gmail.com>
+ * Akos Pasztory <akos.pasztory@gmail.com>
+ * License changes applied and better description in debian/control.
+ Made debian/rules executable.
+
+2009-02-16 Jiri Olsa <olsajiri@gmail.com>
+ * licensed under GPLv3 - more changes
+
+2009-02-14 Jiri Olsa <olsajiri@gmail.com>
+ * licensed under GPLv3
+
+2009-02-05 Jiri Olsa <olsajiri@gmail.com>
+ * Akos Pasztory <akos.pasztory@gmail.com>
+ * initial Debian packaging
+
+2009-02-05 Jiri Olsa <olsajiri@gmail.com>
+ * Akos Pasztory <akos.pasztory@gmail.com>
+ * ARM EABI argument extraction support
+
+2009-02-05 Jiri Olsa <olsajiri@gmail.com>
+ * Akos Pasztory <akos.pasztory@gmail.com>
+ * added a test program
+ * Jiri Olsa - fixed x86 structure walkthrough
+
+2009-02-05 Jiri Olsa <olsajiri@gmail.com>
+ * Akos Pasztory <akos.pasztory@gmail.com>
+ * support for additional POD types
+
+ * Added support for `short', `float', `double', `llong' and `u_llong'
+ (the last two are `long long's).
+ * Jiri Olsa - added ARGS_SPRINTF macro, to have code only on one place
+ and small Makefile bugfix
+
+2009-02-02 Jiri Olsa <olsajiri@gmail.com>
+ * Akos Pasztory <akos.pasztory@gmail.com>
+ * Ignore `const' and `extern' in config files
+ Make it easier to reuse ordinary .h files (though
+ it's still far away).
+
+2009-02-02 Jiri Olsa <olsajiri@gmail.com>
+ * Akos Pasztory <akos.pasztory@gmail.com>
+ * Made it compile in Scratchbox
+ - works with an older `install' program that doesn't recognize `-t'
+ - treat i.86 as i686
+ * configuration files are installed into $(sysconfdir); the program
+ now honors this setting at runtime
+
+2008-12-28 Jiri Olsa <olsajiri@gmail.com>
+ * code style changes
+
+-------------------------------------------------------------------------------
+latrace 0.5.3
+
+2008-12-12 Jiri Olsa <olsajiri@gmail.com>
+ * minor code style changes
+
+2008-12-10 Jiri Olsa <olsajiri@gmail.com>
+ * minor code style changes
+ * adding release notes for 0.5.3
+
+2008-12-10 Jiri Olsa <olsajiri@gmail.com>
+ * x86_64 - finished the case of returning structure by value,
+ x86_64 argument display support is now complete.. bugs expected :)
+
+2008-12-10 Jiri Olsa <olsajiri@gmail.com>
+ * x86_64 - support for structure passed by value in function arguments
+ still missing support for the same in the function return value
+
+2008-12-10 Jiri Olsa <olsajiri@gmail.com>
+ * x86_64 now working except for the structure detailed output
+
+2008-12-07 Jiri Olsa <olsajiri@gmail.com>
+ * complete redesign of the args <-> stack modules communication
+ to be able to manage other ABI platforms properly
+
+2008-12-03 Jiri Olsa <olsajiri@gmail.com>
+ * added support for objsearch LD_AUDIT interface (-L option)
+
+2008-12-01 Jiri Olsa <olsajiri@gmail.com>
+ * added -b option to display flow only below requested symbols
+ * man page updated
+
+2008-11-28 Jiri Olsa <olsajiri@gmail.com>
+ * minors to make autoreconf work, suggested by Nix
+
+2008-11-26 Jiri Olsa <olsajiri@gmail.com>
+ * x86_64 - removed 'cCp' options support because of the glibc bug #7055
+
+2008-11-25 Jiri Olsa <olsajiri@gmail.com>
+ * x86_64, args, output - minor fixes
+
+2008-11-24 Jiri Olsa <olsajiri@gmail.com>
+ * x86_64 - initial changes for argument values display (works
+ for integer and pointers) need updates for arguments
+ passed/returned by value
+
+2008-11-22 Jiri Olsa <olsajiri@gmail.com>
+ * arch specific code redesign (x84, x86_64)
+ x86 working, x86_64 compiles
+ * doc/latrace.1.in - minor change
+
+2008-11-16 Jiri Olsa <olsajiri@gmail.com>
+ * added generated date to the man page
+ * minor code style changes
+
+2008-11-14 Jiri Olsa <olsajiri@gmail.com>
+ * ./ChangeLog - added change log
+
+-------------------------------------------------------------------------------
+latrace 0.5.2
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..aa48365
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,218 @@
+# Copyright (C) 2008, 2009 Jiri Olsa <olsajiri@gmail.com>
+#
+# This file is part of the latrace.
+#
+# The latrace 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 3 of the License, or
+# (at your option) any later version.
+#
+# The latrace 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 the latrace (file COPYING). If not, see
+# <http://www.gnu.org/licenses/>.
+
+
+-include src/autoconf.make
+
+confdir := $(sysconfdir)/latrace.d
+
+# looks like DESTDIR is a standard, but prioritize ROOTDIR anyway
+ifdef DESTDIR
+ifndef ROOTDIR
+ROOTDIR=$(DESTDIR)
+endif
+endif
+
+ifneq ($(findstring $(MAKEFLAGS),w),w)
+PRINT_DIR = --no-print-directory
+else # "make -w"
+NO_SUBDIR = :
+endif
+
+# nice output definition
+# Mostly copied from kernel and git makefiles.
+
+ifndef V
+ QUIET_CC = @echo " CC" $@;
+ QUIET_LD = @echo " LD" $@;
+ QUIET_LEX = @echo " LE" $@;
+ QUIET_YACC = @echo " YA" $@;
+ QUIET_DEP = @echo " DEP" $@;
+ QUIET_GEN = @echo " GEN" $@;
+ QUIET_ASCIIDOC = @echo " ASCIIDOC" $@;
+ QUIET_XMLTO = @echo " XMLTO" $@;
+ QUIET_PKG = @echo -n " PKG ";
+
+# install file quietly, arguments:
+# 1 - file to install
+# 2 - directory to install to
+# 3 - permissions
+# 4 - bool - skip the install if the file does not exist
+define install
+ @if [ -n "$4" -a ! -e $1 ]; then \
+ echo " SKIP $(ROOTDIR)$2/$(notdir $1)"; \
+ else \
+ echo -n " INSTALL " `echo $(ROOTDIR)$2/$(notdir $1) | sed 's:[/]\+:/:g'` ; \
+ mkdir -p $(ROOTDIR)$2; \
+ install -m $3 $1 $(ROOTDIR)$2; echo; \
+ fi
+
+endef
+define remove
+ @echo " CLEAN " $1; $(RM) -rf $1
+endef
+else
+define remove
+ $(RM) -rf $1
+endef
+define install
+ if [ -n "$4" -a ! -e $1 ]; then \
+ echo " SKIP $(ROOTDIR)$2/$(notdir $1)"; \
+ else \
+ mkdir -p $(ROOTDIR)$2; \
+ install -m $3 $1 $(ROOTDIR)$2; echo; \
+ fi
+endef
+endif
+
+
+.PHONY: all clean tags install package .FORCE-LATRACE-CFLAGS
+
+all::
+
+install:: all
+ $(call install,etc/latrace.d/ctype.conf,$(confdir),644)
+ $(call install,etc/latrace.d/inet.conf,$(confdir),644)
+ $(call install,etc/latrace.d/misc.conf,$(confdir),644)
+ $(call install,etc/latrace.d/typedefs.conf,$(confdir),644)
+ $(call install,etc/latrace.d/stdlib.conf,$(confdir),644)
+ $(call install,etc/latrace.d/string.conf,$(confdir),644)
+ $(call install,etc/latrace.d/ctype.conf,$(confdir),644)
+ $(call install,etc/latrace.d/ncurses.conf,$(confdir),644)
+ $(call install,etc/latrace.d/stdio.conf,$(confdir),644)
+ $(call install,etc/latrace.d/dirent.conf,$(confdir),644)
+ $(call install,etc/latrace.d/unistd.conf,$(confdir),644)
+ $(call install,etc/latrace.d/libintl.conf,$(confdir),644)
+ $(call install,etc/latrace.d/dlfcn.conf,$(confdir),644)
+ $(call install,etc/latrace.d/fcntl.conf,$(confdir),644)
+ $(call install,etc/latrace.d/getopt.conf,$(confdir),644)
+ $(call install,etc/latrace.d/signal.conf,$(confdir),644)
+ $(call install,etc/latrace.d/ioctl.conf,$(confdir),644)
+ $(call install,etc/latrace.d/socket.conf,$(confdir),644)
+ $(call install,etc/latrace.d/netdb.conf,$(confdir),644)
+ $(call install,etc/latrace.d/stat.conf,$(confdir),644)
+ $(call install,etc/latrace.d/wait.conf,$(confdir),644)
+ $(call install,etc/latrace.d/utmp.conf,$(confdir),644)
+ $(call install,etc/latrace.d/time.conf,$(confdir),644)
+ $(call install,etc/latrace.d/termios.conf,$(confdir),644)
+ $(call install,etc/latrace.d/term.conf,$(confdir),644)
+ $(call install,etc/latrace.d/syslog.conf,$(confdir),644)
+ $(call install,etc/latrace.d/pwd.conf,$(confdir),644)
+ $(call install,etc/latrace.d/libio.conf,$(confdir),644)
+ $(call install,etc/latrace.d/locale.conf,$(confdir),644)
+ $(call install,etc/latrace.d/pthread.conf,$(confdir),644)
+ $(call install,etc/latrace.d/resource.conf,$(confdir),644)
+ $(call install,etc/latrace.d/mman.conf,$(confdir),644)
+ $(call install,etc/latrace.d/arch-$(CONFIG_SYSDEP_DIR).conf,$(confdir),644)
+ $(call install,etc/latrace.conf,$(sysconfdir),644)
+ifeq ($(CONFIG_SYSDEP_DIR),x86_64)
+ $(call install,etc/sysdeps/$(CONFIG_SYSDEP_DIR)/syscall.conf,$(confdir),644,1)
+endif
+
+
+ifeq (,$(filter clean mrproper,$(MAKECMDGOALS)))
+-include deps.make
+endif
+
+
+# main building schema
+# Module subdir (src,libsf) are supposed to fill PROGRAMS and
+# OBJS variables, and rule to link the module. The top makefile
+# will do the rest.
+
+PROGRAMS=
+OBJS=
+
+include src/Makefile
+include doc/Makefile
+
+INCLUDES= -Isrc -Isrc/sysdeps/$(CONFIG_SYSDEP_DIR)
+ALL_CFLAGS=$(CPPFLAGS) $(CFLAGS) -O2 -fPIC -Wall $(INCLUDES) -D_GNU_SOURCE
+
+
+%.o: %.c LATRACE-CFLAGS
+ $(QUIET_CC)$(CC) -o $*.o -c $(ALL_CFLAGS) $<
+
+.SECONDARY:
+
+%.c: %.l LATRACE-CFLAGS
+ $(QUIET_LEX)$(LEX) -t $< > $(basename $<).c
+
+%.c: %.y LATRACE-CFLAGS
+ $(QUIET_YACC)$(YACC) -v $< -d -o $(basename $<).c
+
+
+all:: $(PROGRAMS) LATRACE-CFLAGS
+
+clean::
+ $(call remove, $(OBJS) $(PROGRAMS))
+ $(call remove, src/args-bison.c src/args-flex.c src/args-bison.h src/args-bison.output)
+ $(call remove, lib bin share deps.make latrace-$(LT_VER))
+
+mrproper::
+ @for i in `find . -type f -o -type d -o -type l | cut -c 3- | grep -v svn`; do \
+ svn info $$i > /dev/null 2>&1; \
+ if [ x"$$?" != x"0" ]; then \
+ echo " CLEAN $$i"; rm -rf $$i; \
+ fi; \
+ done
+
+package:
+ $(QUIET_PKG)rm -f latrace-$(LT_VER); ln -s . latrace-$(LT_VER); \
+ echo "latrace-$(LT_VER)"; \
+ for i in `find . -type f | cut -c 3- | grep -v svn`; do \
+ svn info $$i > /dev/null 2>&1; \
+ if [ x"$$?" == x"0" ]; then \
+ echo "latrace-$(LT_VER)/$$i"; \
+ fi; \
+ done | tar cjvf latrace-$(LT_VER).tar.bz2 -T- > /dev/null 2>&1
+
+
+# dependencies
+# The gcc -M depedencies generation needs to repaired to include
+# subdirectory name within the target.. at least I haven't find any
+# gcc option to do that.
+# - no dependency for flex and bison definitions
+DEPS_OBJS=$(filter-out src/args-flex.o src/args-bison.o,$(OBJS))
+
+deps.make:
+ $(QUIET_DEP)$(RM) -f deps.make; \
+ (for obj in $(DEPS_OBJS); do \
+ src=`echo $$obj | sed "s/\.o/.c/"`; \
+ $(CC) $(ALL_CFLAGS) -M -MT$$obj $$src; \
+ done) > deps.make
+
+# utilities
+tags:
+ $(QUIET_GEN)$(RM) -f tags; \
+ $(FIND) . -name '*.[hc]' -print | xargs ctags -a
+
+cscope:
+ $(QUIET_GEN)$(RM) -f cscope*; \
+ $(FIND) . -name '*.[hc]' -print > cscope.files; \
+ cscope -b -icscope.files
+
+# detect prefix and cflags changes
+TRACK_CFLAGS = $(subst ','\'',$(ALL_CFLAGS)):\
+ $(prefix):$(exec_prefix):$(bindir):$(libdir):$(sysconfdir) #'
+
+LATRACE-CFLAGS: .FORCE-LATRACE-CFLAGS
+ @FLAGS='$(TRACK_CFLAGS)'; \
+ if test x"$$FLAGS" != x"`cat LATRACE-CFLAGS 2>/dev/null`" ; then \
+ echo "$$FLAGS" >LATRACE-CFLAGS; \
+ fi
diff --git a/README b/README
new file mode 100644
index 0000000..22615e5
--- /dev/null
+++ b/README
@@ -0,0 +1,40 @@
+
+latrace LD_AUDIT 2.4+ libc frontend - done by Jiri Olsa (olsajiri@gmail.com)
+-------------------------------------------------------------------------------
+
+
+---[ Installation ]
+
+ To install latrace under /usr use following commands
+
+ autoconf
+ ./configure --prefix=/usr --sysconfdir=/etc
+ make
+ su
+ # set ROOTDIR or DESTDIR to you alternative root, if you dont want '/'
+ make install
+
+
+
+---[ Documentation ]
+
+ All needed documentation is in the man page, after install run:
+
+ man latrace
+
+
+
+---[ Author ]
+
+ This package is Copyright (C) 2008,2009 Jiri Olsa, and is being distributed
+ under the terms of the GPLv3 license. For more details, see the file
+ `doc/COPYING'.
+
+ You can contact me by email at olsajiri@gmail.com.
+
+ The latrace homepage is:
+ http://latrace.sf.net
+
+ Credit is also due to:
+ Nix <nix@esperi.org.uk>
+ Akos Pasztory <akos.pasztory@gmail.com>
diff --git a/ReleaseNotes b/ReleaseNotes
new file mode 100644
index 0000000..6e8b471
--- /dev/null
+++ b/ReleaseNotes
@@ -0,0 +1,85 @@
+
+latrace release notes (olsajiri@gmail.com)
+-------------------------------------------------------------------------------
+
+[x] latrace 0.5.7 (9/4/2009)
+ * added '-B' option to always display the { } around the symbol body
+ * added C++ demangling support - "-d" option
+
+[x] latrace 0.5.6 (7/6/2009)
+ * Fedora rpm package release
+ * several minor fixies:
+ - added support pointers in typedef
+ - fixed minor bug for pointer output
+ - added more checks to configure.ac
+ - make mrproper real propper
+ - added DESTDIR makefile support
+
+[x] latrace 0.5.5 (4/25/2009)
+ x added enum support
+ x added -F option to disable fork following
+ x added -E option to disable exec following
+ x added -T option to hide thread id
+ x x86_64 - added 'pcC' options , since it looks
+ glibc bug 7055 got fixed somehow
+ x x86_64 - fixed argument display (fixed glibc bug 9893,
+ not sure when the glibc fix will be available 2.10?)
+ x stats - added -C sym, fixed -C lib
+ x confs - added syscall.conf (x86_64), mman.conf, resource.conf
+ x asciidoc man/html/txt
+
+[x] latrace 0.5.4 (3/2/2009)
+ x ARM support (EABI)
+ x added config file support for 'float', 'double',
+ 'long long' and 'unsigned long long'
+ x licensed under GPLv3
+ x initial Debian packaging
+ x ignore 'const' and 'extern' in config files
+ Make it easier to reuse ordinary .h files (though
+ it's still far away).
+ x configuration files are installed into $(sysconfdir);
+ x x86_64 - disabled argument display (options 'AaD'),
+ because of the glibc bug 9893
+ x x86 - structure display fix
+
+[x] latrace 0.5.3 (12/12/2008)
+ x x86_64 full support
+ x autoreconf compliant
+ x new '-b' option to display flow only below requested symbols
+ x new '-L' option to support objsearch LD_AUDIT interface
+ x bug fixes
+
+[x] latrace 0.5.2 (11/12/2008)
+ x bug fixes
+
+[x] latrace 0.5.1 (10/26/2008)
+ x C like syntax for the config file - typedef/struct/functions (bison/flex)
+ x optional detailed output for structures (by ptr and value)
+ x documentation - doc/expl in the man page
+
+[x] latrace 0.5 (7/7/2008)
+ x display arguments values
+ x compile on x86_64
+
+[x] latrace 0.4 (6/13/2008)
+ x multithread counts support
+ x separate verbose and debug ouput
+ x runtime for each thread
+ x stats - reallocation for symbol hashtable
+ x documentation - initial latrace man page
+
+[x] latrace 0.3 (6/7/2008)
+ x separate verbose logging
+ x indent size configurable
+ x sort counts by user parameter (calls, %, library)
+ x output to file
+ x more statistics counts, time spent in call
+
+[x] latrace 0.2 (5/26/2008)
+ x statistics (like strace -c)
+ x looking for programs in PATH, not just absolute path
+ x symbols deep indentation
+
+[x] latrace 0.1 (5/18/2008)
+ x config symbols to audit
+ x config libraries to audit
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..fe879d6
--- /dev/null
+++ b/TODO
@@ -0,0 +1,33 @@
+
+latrace TODO - feel free to contact me with any feature idea
+-------------------------------------------------------------------------------
+olsajiri@gmail.com
+
+
+for 0.5.8
+ - config - arrays in structures
+ - add mask enum support (ORed values)
+ - add support for display number at different bases (2,8,10,16)
+
+for 0.6
+ - variable lenght argument output (printf like)
+ - config - long/float/double support
+ - config - X symbols config file
+ - runtime configuration control
+ - segfault handling support (libSegFault.so loading support)
+ - statistics for recursive calls
+ - automated tests
+ - other LD_AUDIT interface functions utilization
+ - statistics check
+
+bugs
+ - make waiting for child exit more robust (suspend/continue...)
+ - library settings does not work properly
+ - testing, segfaults with skype (test with simple LD_AUDIT lib)
+ - test statistics counts
+ - fifo reading more inteligent
+ - detailed arguments buffer memory management (now fixed size)
+ - environment variables to the include path
+ - check we dont cross all the hardcoded limits
+ - consolidate leveled VERBOSE output
+ - info doc (produce html, pdf... outputs)
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..50744ed
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,91 @@
+# Copyright (C) 2008, 2009 Jiri Olsa <olsajiri@gmail.com>
+#
+# This file is part of the latrace.
+#
+# The latrace 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 3 of the License, or
+# (at your option) any later version.
+#
+# The latrace 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 the latrace (file COPYING). If not, see
+# <http://www.gnu.org/licenses/>.
+
+
+AC_PREREQ(2.61)
+AC_INIT(latrace, 0.5.7, olsajiri@gmail.com)
+AC_CONFIG_SRCDIR([src/latrace.c])
+
+AC_PROG_CC
+AC_PROG_LEX
+AC_PROG_YACC
+AC_PROG_LN_S
+
+AC_HEADER_STDC
+AC_CHECK_HEADERS([stdlib.h])
+AC_CHECK_HEADERS([unistd.h])
+AC_CHECK_HEADERS([string.h])
+AC_CHECK_HEADERS([libintl.h])
+AC_CHECK_HEADERS([malloc.h])
+AC_CHECK_HEADERS([stddef.h])
+AC_C_CONST
+AC_TYPE_PID_T
+AC_FUNC_FORK
+AC_FUNC_REALLOC
+AC_CHECK_FUNCS([memset setenv])
+AC_CHECK_FUNCS([gettimeofday])
+AC_CHECK_FUNCS([mkfifo])
+AC_CHECK_FUNCS([select])
+AC_CHECK_FUNCS([strchr])
+AC_CHECK_FUNCS([strdup])
+AC_CHECK_FUNCS([strstr])
+AC_CHECK_FUNCS([strerror])
+AC_CHECK_FUNCS([strtol])
+AC_CHECK_HEADERS([fcntl.h])
+AC_CHECK_HEADERS([sys/time.h])
+AC_CHECK_HEADERS([limits.h])
+AC_FUNC_MALLOC
+AC_FUNC_ALLOCA
+AC_FUNC_CLOSEDIR_VOID
+AC_FUNC_SELECT_ARGTYPES
+AC_HEADER_DIRENT
+AC_HEADER_SYS_WAIT
+AC_HEADER_TIME
+AC_C_INLINE
+AC_TYPE_OFF_T
+AC_TYPE_SSIZE_T
+AC_TYPE_UINT32_T
+AC_TYPE_SIZE_T
+AC_TYPE_INT16_T
+AC_TYPE_INT32_T
+AC_TYPE_INT8_T
+AC_TYPE_UINT16_T
+AC_TYPE_UINT8_T
+
+date=`date "+%B %G"`
+unamem=`uname -m | sed 's/i.86/i686/'`
+
+AC_SUBST(LT_DATE, "$date")
+AC_SUBST(CONFIG_SYSDEP_DIR, "$unamem")
+AC_SUBST(LT_VER, "AC_PACKAGE_VERSION")
+
+AC_DEFINE(CONFIG_LT_CONFIG, "/tmp/lt-config", [Temporary directory prefix.])
+AC_DEFINE(LT_VER, "AC_PACKAGE_VERSION", [Version of latrace.])
+
+if test "$unamem" = "x86_64"; then
+ AC_DEFINE(LT_ARCH_X86_64, 1, [The x86_64 arch.])
+elif test "$unamem" = "i686"; then
+ AC_DEFINE(LT_ARCH_X86, 1, [The x86 arch.])
+fi
+
+AC_CONFIG_HEADER([src/autoconf.h])
+AC_CONFIG_FILES([src/autoconf.make])
+AC_CONFIG_FILES([doc/asciidoc.conf])
+AC_CONFIG_FILES([etc/latrace.conf])
+
+AC_OUTPUT
diff --git a/doc/Makefile b/doc/Makefile
new file mode 100644
index 0000000..9026baa
--- /dev/null
+++ b/doc/Makefile
@@ -0,0 +1,25 @@
+
+ASCIIDOC=asciidoc
+XMLTO=xmlto
+
+MANMAN=doc/latrace.1
+MANTXT=doc/latrace.txt
+MANXML=doc/latrace.xml
+MANHTML=doc/latrace.html
+
+.PHONY: doc man htmlman
+
+doc: $(MANMAN) $(MANHTML)
+
+$(MANMAN): $(MANTXT)
+ $(QUIET_ASCIIDOC)$(ASCIIDOC) -f doc/asciidoc.conf -b docbook -d manpage -o $(MANXML) $(MANTXT)
+ $(QUIET_XMLTO)$(XMLTO) -o doc man $(MANXML)
+
+$(MANHTML): $(MANTXT)
+ $(QUIET_ASCIIDOC)$(ASCIIDOC) -b xhtml11 -d manpage --unsafe -o $(MANHTML) $(MANTXT)
+
+clean::
+ $(call remove, $(MANXML) $(MANHTML) $(MANMAN))
+
+install:: doc
+ $(call install,$(MANMAN),$(mandir)/man1,644)
diff --git a/doc/asciidoc.conf.in b/doc/asciidoc.conf.in
new file mode 100644
index 0000000..8682213
--- /dev/null
+++ b/doc/asciidoc.conf.in
@@ -0,0 +1,6 @@
+[attributes]
+
+author = Jiri Olsa
+email = olsajiri@gmail.com
+date = @LT_DATE@
+revision = @LT_VER@
diff --git a/doc/latrace.txt b/doc/latrace.txt
new file mode 100644
index 0000000..937775f
--- /dev/null
+++ b/doc/latrace.txt
@@ -0,0 +1,434 @@
+latrace(1)
+==========
+Jiri Olsa <olsajiri@gmail.com>
+
+
+NAME
+----
+latrace - LD_AUDIT 2.4+ libc frontend
+
+
+SYNOPSIS
+--------
+*latrace* [-ltfsbcCpADaoyIiBdvTFELVh] command [arg ... ]
+
+
+DESCRIPTION
+-----------
+*latrace* is able to run a command and display its dynamic library calls using
+a *LD_AUDIT* libc feature (available from libc version 2.4 onward - see <<DISCUSSION>>
+). It is also capable to measure and display various statistics of
+dynamic calls.
+
+If the config file is provided, latrace will display symbol's arguments with
+detailed output for structures. The config file syntax is similar to the C
+language, with several exceptions (see <<CONFIG>>).
+
+The latrace by default fully operates inside of the traced program. However
+another pipe mode is available, to move the main work to the latrace binary
+(see <<PIPEMODE>>).
+
+Its use is very similar to strace(1) and ltrace(1).
+
+
+OPTIONS
+-------
+*-l, --libs lib1[,lib2,...]*::
+ audit from and to lib1, lib2 ...
+
+*-t, --libs-to lib1[,lib2,...]*::
+ audit to lib1, lib2 ...
+
+*-f, --libs-from lib1[,lib2,...]*::
+ audit from lib1, lib2 ...
+
+*-s, --sym sym1[,sym2,...]*::
+ audit symbols sym1, sym2 ...
+
+*-b, --flow-below sym1[,sym2,...]*::
+ display flow for sym1, sym2 ...
+
+*-c, --counts*::
+ display statistics counts of symbols - implies pipe mode (see <<PIPEMODE>>)
+ an no symbol output is displayed
+
+*-C, --sort-counts stat*::
+ implies -c, plus sort the statistics by stat with following values:
+ time,per,call,ucall,lib,sym (default is call)
+
+*-p, --pipe*::
+ use pipe to latrace process to send audit data (see <<PIPEMODE>>)
+
+*-o, --output file*::
+ store output to file
+
+*-A, --enable-args*::
+ enable arguments output (definitions from /etc/latrace.conf)
+
+*-D, --detail-args*::
+ display struct arguments in more detail
+
+*-a, --args file*::
+ specify arguments definition file, implies -A (without the default
+ definition file of course)
+
+*-y, --framesize number*::
+ framesize for storing the stack before pltexit (default 100)
+
+*-I, --no-indent-sym*::
+ do no indent symbols based on the their stack depth
+
+*-i, --indent-sym indent_size*::
+ indent size specification in indent_size
+
+*-B, --braces*::
+ allways display '{' '}' for the around the symbol body
+
+*-d, --demangle*::
+ C++ demangle symbols on the output
+
+*-v, --verbose*::
+ verbose output
+
+*-T, --hide-tid*::
+ dont display thread id
+
+*-F, --not-follow-fork*::
+ dont follow fork calls (childs). This is just supressing the latrace
+ output from new childs. The nature of the *LD_AUDIT* feature prevents to
+ disable it completely.
+
+*-E, --not-follow-exec*::
+ dont follow exec calls
+
+
+EXAMPLES
+--------
+- The simplest way to run latrace is like this:
++
+** latrace cat**
+
+- To see the argument values specified by default config file run:
++
+** latrace -A cat**
+
+- Same as above but using the pipe mode to get all the end symbols printed:
++
+** latrace -Ap cat**
+
+- To see the argument values specified by specified config file run:
++
+** latrace -a latrace.conf cat**
+
+- To get output only for specified symbol (eg. read and write) run:
++
+** latrace -A -s read,write cat**
+
+- To get flow under the specified symbol (eg. sysconf) run:
++
+** latrace -b sysconf kill**
+
+- To get output only for specified library (eg. libproc) run:
++
+** latrace -Al libproc w**
+
+- To get symbol statistics run:
++
+** latrace -c ls**
+
+- To get symbol statistics sorted by time run:
++
+** latrace -C time ls**
+
+- To get output stored to the text file run:
++
+** latrace -o output.latrace ls**
+
+- To change the libkrava1.so dependency to the libkrava2.so run one of these:
++
+** latrace -L krava1%krava2 ex**
++
+** latrace -L krava1~libkrava2.so ex**
++
+** latrace -L libkrava1.so=libkrava2.so ex**
+
+
+[[DISCUSSION]]
+DISCUSSION
+----------
+LD_AUDIT
+~~~~~~~~
+This is just a brief and vague description of the *LD_AUDIT* feature.
+For more information look to *rtld-audit(7)* man done by Petr Baudis or study the
+glibc/latrace source code. Very brief explanation follows.
+
+The libc dynamic linker audit feature allows to trace/audit program's
+symbols/libraries. The feature is enabled by the *LD_AUDIT* environment
+variable. This variable must contain path to the audit shared library.
+This audit library needs to follow specific interface. The interface functions
+will be then called by the dynamic linker appropriatelly.
+
+The audit library needs to export following symbols (the "la_PLTENTER" and
+"la_PLTEXIT" names are architecture dependent).
+
+ "la_activity"
+ "la_objsearch"
+ "la_objopen"
+ "la_preinit"
+ "la_symbind32"
+ "la_symbind64"
+ "la_PLTENTER"
+ "la_PLTEXIT"
+ "la_objclose"
++
+
+As for the latrace package the audit shared library is called libltaudit.so.
+
+OBJSEARCH
+~~~~~~~~~
+The objsearch *LD_AUDIT* interface provide means for changing traced program
+shared object names/locations. The -L option argument should have
+following form:
+
+__-L s1[,s2,...]__ where sN is __src [=%~] dst__
+
+The _src_ is the source pattern/name and _dst_ is the destination name/pattern.
+
+[horizontal]
+=:: Comparing src with the library name. If matched, replace the library name with dst.
+
+ library name - /lib/krava1.so
+ src - /lib/krava1.so
+ dst - /lib/krava2.so
+
+ final library name - /lib/krava2.so
+
+%:: Looking for the src in the library name. If found, replace the src with dst part.
+
+ library name - /lib/krava1.so
+ src - krava1
+ dst - krava2
+
+ final library name - /lib/krava2.so
+
+~:: Looking for the src in the library name. If found, replace the library name with dst.
+
+ library name - /lib/krava1.so
+ src - krava1
+ dst - /lib/krava2.so
+
+ final library name - /lib/krava2.so
+
+
+[[PIPEMODE]]
+PIPE mode
+~~~~~~~~~
+The *latrace* can work in two modes. The first one *native* does does the
+output directly in the traced program process. The other one, *pipe* mode use
+the IPC fifo mechanism to send the data from the traced process to the latrace
+process. The latrace process is then responsible for the output. Using the
+pipe mode you loose the traced program standard output context with printed
+symbols.
+
+By using the *pipe* mode, the latrace is not dependent on the trace program
+usage/manipulation of the standard output descriptor. Also the symbol
+statistics counts __-c, -C options__ use the *pipe* mode to transfer symbol
+information to the latrace binary, and the latrace binary does the counts
+at the end.
+
+
+[[CONFIG]]
+CONFIG
+~~~~~~
+The latrace config file allows user to define symbols as an classic C
+functions with arguments. Argument names will be display together with values
+as the latrace output. The more arguments are defined, the more performance and
+memory penalties should be expected.
+
+The package is delivered with several config files for the most commonly used
+functions. List of the glibc header files used follows (the list mostly
+follows the ltrace header files list, and author is willing to update it
+according to the needs.
+
+ /usr/include/arpa/inet.h
+ /usr/include/ctype.h
+ /usr/include/stdlib.h
+ /usr/include/string.h
+ /usr/include/ctype.h
+ /usr/include/ncurses.h
+ /usr/include/stdio.h
+ /usr/include/dirent.h
+ /usr/include/unistd.h
+ /usr/include/libintl.h
+ /usr/include/dlfcn.h
+ /usr/include/fcntl.h
+ /usr/include/getopt.h
+ /usr/include/signal.h
+ /usr/include/sys/ioctl.h
+ /usr/include/sys/socket.h
+ /usr/include/netdb.h
+ /usr/include/pthread.h
+ /usr/include/sys/resource.h
+ /usr/include/sys/mman.h
++
+
+The config file structure consists of */etc/latrace.conf* file, which is the
+default one read by latrace. This config file includes other config files
+placed in the */etc/latrace.d* directory. This directory contain all the config
+files for the above mentioned header files.
+
+As already mentioned, the latrace config file syntax lightly follows the C
+language syntax. Following part describes the latrace config file
+language.
+
+
+
+- Several **POD types** (plain old data), are hardcoded in latrace. Size of those
+arguments is determined by the sizeof macro. The list follows.
++
+ void
+ char u_char
+ short u_short
+ int u_int
+ long u_long
+ llong u_llong # (long long)
+ float double
+
+- The *typedef* keyword allows to specify new type based on the already existing one
+(POD or typedefed). Eventhough there's a way for multiple pointer layers in the type
+definition (*), only one is taken.
++
+..............................
+typedef base_type new_type;
+typedef base_type * new_type;
+typedef base_type ** new_type;
+..............................
+
+- *Comments* follow the C style /\* \*/ logic.
++
+++ /\* comments \*/ ++
+
+- The *include* keyword allows to include another config file.
++
+++ #include "filename"++
+
+- The *struct* keyword allows to define the structure. The syntax folows following
+grammar rules.
++
+...........................................
+START:: struct NAME { STRUCT_DEF };
+STRUCT_DEF:: DEF | EMPTY
+DEF:: NAME NAME |
+ NAME '*' NAME |
+ struct NAME NAME |
+ struct NAME '*' NAME
+NAME:: [-0-9a-zA-Z_]+
+...........................................
+
+- The *function* definition follows following syntax (DEF and NAME are the same as
+for struct definition).
++
+..........................................
+START:: DEF '(' ARGS ')' ';'
+ARGS:: ARGS ',' DEF | DEF | EMPTY
+..........................................
+
+- The *enum* definition follows following syntax (NAME is same as for struct
+definition).
++
+..................................................
+START:: ENUM NAME '{' ENUM_DEF '}' ';'
+ENUM_DEF:: ENUM_DEF ',' ENUM_ELEM | ENUM_ELEM
+ENUM_ELEM:: NAME '=' NAME | NAME
+..................................................
+
+
+- Example of a simple latrace config file.
++
+............................................
+---[ cut here ]-----------------------------
+enum krava {
+ krava1 = 1,
+ krava2,
+ krava3 = 100
+};
+
+#include "krava.conf"
+
+typedef u_int pid_t;
+
+struct ex_st {
+ pid_t p;
+ int cnt;
+ char *name;
+};
+
+int f1(pid_t p, struct ex_st *k);
+int f2(char* name, struct ex_st k, int k = krava);
+struct ex_st* f3(pid_t *p, struct ex_st k);
+---[ cut here ]-----------------------------
+............................................
+
+- Arrays are not supported yet, so there's no way to define some structures. For
+such a structures use void* type where the structure argu- ment is passed by
+pointer. If it is passed by value, there's no workaround so far (aside from
+filling the structure body with POD types up to the actual length of the
+structure :).
+
+- Variable argument lists (va_list/...) are not supported yet. The function
+definition needs to stop before the first variable argument list argument.
+
+
+PORTS
+-----
+Author is willing to port the latrace to any architecture, as long as he got an
+access to corresponding system. Currently functional ports are:
+
+[horizontal]
+*x86*:: ok
+*x86_64*:: ok
+*arm*:: ok (contributed and maintained by Akos Pasztory)
+
+
+LD_AUDIT related glibc bugs:
+
+- *Bug 7055 (no longer reproducible)*
+LD_AUDIT - gettimeofday function segfaults if called from interface
+<http://sources.redhat.com/bugzilla/show_bug.cgi?id=7055>
+
+
+- *Bug 9893 (FIXED in 2.10)*
+LD_AUDIT - misaligned _dl_call_pltexit parameter causing crash in audit library
+<http://sources.redhat.com/bugzilla/show_bug.cgi?id=9893>
+
+
+- *Bug 3924 (FIXED in 2.7-2)*
+LD_AUDIT implementation causing process segfaulting
+<http://sourceware.org/bugzilla/show_bug.cgi?id=3924>
+
+
+BUGS
+----
+MANY, plz report bugs to <olsajiri@gmail.com>. You can also visit the
+latrace.sf.net page to see the latest release notes information.
+
+
+AUTHOR
+------
+Jiri Olsa <olsajiri@gmail.com>
+
+
+CONTRIBUTORS
+------------
+- Nix <nix@esperi.org.uk>
+- Akos Pasztory <akos.pasztory@gmail.com>
+
+
+LICENSE
+-------
+This is free software, distributed under the *GPLv3* license.
+
+
+SEE ALSO
+--------
+**strace(1), ltrace(1)**
diff --git a/etc/latrace.conf.in b/etc/latrace.conf.in
new file mode 100644
index 0000000..b62cda5
--- /dev/null
+++ b/etc/latrace.conf.in
@@ -0,0 +1,100 @@
+
+/* arch specific */
+#include "arch-@CONFIG_SYSDEP_DIR@.conf"
+
+/* miscelaneous functions */
+#include "misc.conf"
+
+/* miscelaneous typedefs */
+#include "typedefs.conf"
+
+/* /usr/include/arpa/inet.h */
+#include "inet.conf"
+
+/* /usr/include/ctype.h */
+#include "ctype.conf"
+
+/* /usr/include/stdlib.h */
+#include "stdlib.conf"
+
+/* /usr/include/string.h */
+#include "string.conf"
+
+/* /usr/include/ctype.h */
+#include "ctype.conf"
+
+/* /usr/include/ncurses.h */
+#include "ncurses.conf"
+
+/* /usr/include/stdio.h */
+#include "stdio.conf"
+
+/* /usr/include/dirent.h */
+#include "dirent.conf"
+
+/* /usr/include/unistd.h */
+#include "unistd.conf"
+
+/* /usr/include/libintl.h */
+#include "libintl.conf"
+
+/* /usr/include/dlfcn.h */
+#include "dlfcn.conf"
+
+/* /usr/include/fcntl.h */
+#include "fcntl.conf"
+
+/* /usr/include/getopt.h */
+#include "getopt.conf"
+
+/* /usr/include/signal.h */
+#include "signal.conf"
+
+/* /usr/include/sys/ioctl.h */
+#include "ioctl.conf"
+
+/* /usr/include/sys/socket.h */
+#include "socket.conf"
+
+/* /usr/include/netdb.h */
+#include "netdb.conf"
+
+/* /usr/include/sys/stat.h */
+#include "stat.conf"
+
+/* /usr/include/sys/wait.h */
+#include "wait.conf"
+
+/* /usr/include/utmp.h */
+#include "utmp.conf"
+
+/* /usr/include/time.h */
+#include "time.conf"
+
+/* /usr/include/termios.h */
+#include "termios.conf"
+
+/* /usr/include/term.h */
+#include "term.conf"
+
+/* /usr/include/sys/syslog.h */
+#include "syslog.conf"
+
+/* /usr/include/pwd.h */
+#include "pwd.conf"
+
+/* /usr/include/libio.h */
+#include "libio.conf"
+
+/* /usr/include/locale.h */
+#include "locale.conf"
+
+/* /usr/include/pthread.h */
+#include "pthread.conf"
+
+/* /usr/include/sys/resource.h */
+#include "resource.conf"
+
+/* /etc/latrace.d/mman.conf */
+#include "mman.conf"
+
diff --git a/etc/latrace.d/arch-arm.conf b/etc/latrace.d/arch-arm.conf
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/etc/latrace.d/arch-arm.conf
diff --git a/etc/latrace.d/arch-i686.conf b/etc/latrace.d/arch-i686.conf
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/etc/latrace.d/arch-i686.conf
diff --git a/etc/latrace.d/arch-x86_64.conf b/etc/latrace.d/arch-x86_64.conf
new file mode 100644
index 0000000..a132832
--- /dev/null
+++ b/etc/latrace.d/arch-x86_64.conf
@@ -0,0 +1,3 @@
+
+/* /usr/include/bits/syscall.h */
+#include "syscall.conf"
diff --git a/etc/latrace.d/ctype.conf b/etc/latrace.d/ctype.conf
new file mode 100644
index 0000000..1bc8baa
--- /dev/null
+++ b/etc/latrace.d/ctype.conf
@@ -0,0 +1,20 @@
+
+/* /usr/include/ctype.h */
+
+
+void* __ctype_b_loc(void);
+void* __ctype_tolower_loc(void);
+void* __ctype_toupper_loc (void);
+
+
+int isctype(int c, int mask);
+int isascii(int c);
+int toascii(int c);
+
+
+int tolower(int c);
+int toupper(int c);
+int __tolower_l(int c, __locale_t l);
+int tolower_l(int c, __locale_t l);
+int __toupper_l(int c, __locale_t l);
+int toupper_l(int c, __locale_t l);
diff --git a/etc/latrace.d/dirent.conf b/etc/latrace.d/dirent.conf
new file mode 100644
index 0000000..40262c3
--- /dev/null
+++ b/etc/latrace.d/dirent.conf
@@ -0,0 +1,31 @@
+
+/* /usr/include/dirent.h */
+
+
+DIR* opendir(char *name);
+DIR* fdopendir(int fd);
+int closedir(DIR *dirp);
+
+
+void* readdir(DIR *dirp);
+void* readdir64(DIR *dirp);
+int readdir_r(DIR *dirp, void *entry, void *result);
+int readdir64_r(DIR *dirp, void *entry, void *result);
+
+
+void rewinddir(DIR *dirp);
+void seekdir(DIR *dirp, long __pos);
+long telldir(DIR *dirp);
+int dirfd(DIR *dirp);
+
+
+int scandir(char *dir, void *namelist, void *selector, void *cmp);
+int scandir64(char *dir, void *namelist, void *selector, void *cmp);
+int alphasort(void *e1, void *e2);
+int alphasort64(void *e1, void *e2);
+int versionsort(void *e1, void *e2);
+int versionsort64(void *e1, void *e2);
+
+
+size_t getdirentries(int fd, char *buf, size_t nbytes, __off_t *basep);
+size_t getdirentries64(int fd, char *buf, size_t nbytes, __off64_t *basep);
diff --git a/etc/latrace.d/dlfcn.conf b/etc/latrace.d/dlfcn.conf
new file mode 100644
index 0000000..82f8ec8
--- /dev/null
+++ b/etc/latrace.d/dlfcn.conf
@@ -0,0 +1,12 @@
+
+/* /usr/include/dlfcn.h */
+
+void* dlopen(char *file, int mode);
+int dlclose(void *handle);
+void* dlsym(void *handle, char* name);
+void* dlmopen(long nsid, char *file, int mode);
+void* dlvsym(void *handle, char *name, char* version);
+char* dlerror();
+int dladdr(void *address, void *info);
+int dladdr1(void *address, void *info, void *extra_info, int flags);
+int dlinfo(void *handle, int request, void *arg);
diff --git a/etc/latrace.d/fcntl.conf b/etc/latrace.d/fcntl.conf
new file mode 100644
index 0000000..d4eab51
--- /dev/null
+++ b/etc/latrace.d/fcntl.conf
@@ -0,0 +1,18 @@
+
+/* /usr/include/fcntl.h */
+
+int fcntl(int fd, int cmd);
+int open(char *file, int oflag);
+int open64(char *file, int oflag);
+int openat(int fd, char *file, int oflag);
+int openat64(int fd, char *file, int oflag);
+int creat(char *file, __mode_t mode);
+int creat64(char *file, __mode_t mode);
+int lockf(int fd, int cmd, __off_t len);
+
+
+int lockf64(int fd, int cmd, __off64_t len);
+int posix_fadvise(int fd, __off_t offset, __off_t len, int advise);
+int posix_fadvise64(int fd, __off64_t offset, __off64_t len, int advise);
+int posix_fallocate(int fd, __off_t offset, __off_t len);
+int posix_fallocate64(int fd, __off64_t offset, __off64_t len);
diff --git a/etc/latrace.d/getopt.conf b/etc/latrace.d/getopt.conf
new file mode 100644
index 0000000..93692a2
--- /dev/null
+++ b/etc/latrace.d/getopt.conf
@@ -0,0 +1,7 @@
+
+/* /usr/include/getopt.h */
+
+int getopt (int argc, void *argv, char *shortopts);
+int getopt();
+int getopt_long(int argc, void *argv, char *shortopts, void *longopts, int *longind);
+int getopt_long_only(int argc, void *argv, char *shortopts, void *longopts, int *longind);
diff --git a/etc/latrace.d/inet.conf b/etc/latrace.d/inet.conf
new file mode 100644
index 0000000..25621f0
--- /dev/null
+++ b/etc/latrace.d/inet.conf
@@ -0,0 +1,18 @@
+
+/* /usr/include/arpa/inet.h */
+
+struct in_addr {
+ in_addr_t s_addr;
+};
+
+in_addr_t inet_addr(char *__cp);
+in_addr_t inet_lnaof(struct in_addr __in);
+struct in_addr inet_makeaddr(in_addr_t __net, in_addr_t __host);
+in_addr_t inet_netof(struct in_addr __in);
+in_addr_t inet_network(char *__cp);
+char* inet_ntoa(struct in_addr __in);
+int inet_pton(int __af, char *__cp, void __buf);
+char* inet_ntop(int __af, void *__cp, char *__buf, socklen_t __len);
+int inet_aton(char *__cp, struct in_addr *__inp);
+char* inet_neta(in_addr_t __net, char *__buf, size_t __len);
+char* inet_net_ntop(int __af, void *__cp, int __bits, char *__buf, size_t __len);
diff --git a/etc/latrace.d/ioctl.conf b/etc/latrace.d/ioctl.conf
new file mode 100644
index 0000000..9de73e8
--- /dev/null
+++ b/etc/latrace.d/ioctl.conf
@@ -0,0 +1,4 @@
+
+/* /usr/include/sys/ioctl.h */
+int ioctl(int fd, u_long request);
+
diff --git a/etc/latrace.d/libintl.conf b/etc/latrace.d/libintl.conf
new file mode 100644
index 0000000..bb80085
--- /dev/null
+++ b/etc/latrace.d/libintl.conf
@@ -0,0 +1,14 @@
+
+/* /usr/include/libintl.h */
+
+char* gettext(char *msgid);
+char* dgettext(char *domainname, char *msgid);
+char* __dgettext(char *domainname, char *msgid);
+char* dcgettext(char *domainname, char *msgid, int category);
+char* __dcgettext(char *domainname, char *msgid, int category);
+char* ngettext(char *msgid1, char *msgid2, u_long n);
+char* dngettext(char *domainname, char *msgid1, char *msgid2, u_long n);
+char* dcngettext(char *domainname, char *msgid1, char *msgid2, u_long n, int category);
+char* textdomain(char *domainname);
+char* bindtextdomain(char *domainname, char *dirname);
+char* bind_textdomain_codeset(char *domainname, char *codeset);
diff --git a/etc/latrace.d/libio.conf b/etc/latrace.d/libio.conf
new file mode 100644
index 0000000..705c173
--- /dev/null
+++ b/etc/latrace.d/libio.conf
@@ -0,0 +1,29 @@
+
+/* /usr/include/libio.h UNCOMPLETE */
+
+
+typedef void _IO_FILE;
+typedef size_t _IO_size_t;
+
+
+int __underflow(_IO_FILE *f);
+int __uflow(_IO_FILE *f);
+int __overflow(_IO_FILE *f, int a);
+
+
+int _IO_getc(_IO_FILE *fp);
+int _IO_putc(int c, _IO_FILE *fp);
+int _IO_feof(_IO_FILE *fp);
+int _IO_ferror(_IO_FILE *fp);
+
+
+int _IO_peekc_locked(_IO_FILE *fp);
+void _IO_flockfile(_IO_FILE *f);
+void _IO_funlockfile(_IO_FILE *f);
+int _IO_ftrylockfile(_IO_FILE *f);
+
+
+int _IO_vfscanf(_IO_FILE *f, char *s);
+int _IO_vfprintf(_IO_FILE *f, char *s);
+_IO_size_t _IO_padn(_IO_FILE *f, int b, _IO_size_t s);
+_IO_size_t _IO_sgetn(_IO_FILE *f, void *p, _IO_size_t s);
diff --git a/etc/latrace.d/locale.conf b/etc/latrace.d/locale.conf
new file mode 100644
index 0000000..bb2e207
--- /dev/null
+++ b/etc/latrace.d/locale.conf
@@ -0,0 +1,9 @@
+
+/* /usr/include/locale.h */
+
+
+char* setlocale(int category, char *locale);
+__locale_t newlocale(int category_mask, char *locale, __locale_t __base);
+__locale_t duplocale(__locale_t __dataset);
+void freelocale(__locale_t dataset);
+__locale_t uselocale(__locale_t __dataset);
diff --git a/etc/latrace.d/misc.conf b/etc/latrace.d/misc.conf
new file mode 100644
index 0000000..d996b50
--- /dev/null
+++ b/etc/latrace.d/misc.conf
@@ -0,0 +1,7 @@
+
+/* miscelaneous functions */
+
+int __libc_start_main(void *main, int argc, void *ubp_av, void *auxvec, void *init, void *fini, void *rtld_fini);
+
+/* /usr/include/sys/utsname.h */
+int uname(void *name);
diff --git a/etc/latrace.d/mman.conf b/etc/latrace.d/mman.conf
new file mode 100644
index 0000000..8792d22
--- /dev/null
+++ b/etc/latrace.d/mman.conf
@@ -0,0 +1,25 @@
+
+/* /usr/include/sys/mman.h */
+
+extern void *mmap(void *addr, size_t len, int prot,
+ int flags, int fd, __off_t offset);
+
+extern void *mmap64(void *addr, size_t len, int prot,
+ int flags, int fd, long offset);
+
+extern int munmap(void *addr, size_t len);
+extern int mprotect(void *addr, size_t len, int prot);
+extern int msync(void *addr, size_t len, int flags);
+extern int posix_madvise(void *addr, size_t len, int advice);
+extern int mlock(void *addr, size_t len);
+extern int munlock(void *addr, size_t len);
+extern int mlockall(int flags);
+extern int munlockall(void);
+extern int mincore(void *start, size_t len, u_char *vec);
+
+extern void *mremap(void *addr, size_t old_len, size_t new_len,
+ int flags);
+extern int remap_file_pages(void *start, size_t size, int prot,
+ size_t pgoff, int flags);
+extern int shm_open(char *name, int oflag, mode_t mode);
+extern int shm_unlink(char *name);
diff --git a/etc/latrace.d/ncurses.conf b/etc/latrace.d/ncurses.conf
new file mode 100644
index 0000000..d226f1a
--- /dev/null
+++ b/etc/latrace.d/ncurses.conf
@@ -0,0 +1,334 @@
+
+/* /usr/include/ncurses.conf */
+
+typedef int attr_t;
+typedef attr_t chtype;
+typedef u_char bool;
+
+bool is_term_resized(int a, int b);
+char* keybound (int a, int b);
+char* curses_version(void);
+int assume_default_colors(int a, int b);
+int define_key(char *a, int b);
+int key_defined(char *a);
+int keyok(int a, int b);
+int resize_term(int a, int b);
+int resizeterm(int a, int b);
+int use_default_colors(void);
+int use_extended_names(int a);
+int use_legacy_coding(int a);
+int wresize (void *w, int a, int b);
+void nofilter(void);
+
+
+int wgetch_events(void *w, void *event);
+int wgetnstr_events(void *w, char *a, int b, void *event);
+
+int addch(chtype a);
+int addchnstr(chtype *a, int b);
+int addchstr(chtype *a);
+int addnstr(char *a, int b);
+int addstr(char *a);
+int attroff(attr_t a);
+int attron(attr_t a);
+int attrset(attr_t a);
+int attr_get(attr_t *a, short *b, void *c);
+int attr_off(attr_t a, void *b);
+int attr_on(attr_t a, void *b);
+int attr_set(attr_t a, short b, void *c);
+int baudrate();
+int beep();
+int bkgd(chtype a);
+void bkgdset(chtype a);
+int border(chtype a, chtype b, chtype c, chtype d, chtype c, chtype d, chtype e, chtype f);
+int box(void *w, chtype a, chtype b);
+bool can_change_color();
+int cbreak(void);
+int chgat(int a, attr_t b, short c, void *d);
+int clear();
+int clearok(void *w, bool a);
+int clrtobot(void);
+int clrtoeol(void);
+int color_content(short a, short *b, short *c, short *d);
+int color_set(short a, void *b);
+int COLOR_PAIR(int a);
+int copywin(void *w1, void *w2, int a, int b, int c, int d, int e, int f, int g);
+int curs_set(int a);
+int def_prog_mode(void);
+int def_shell_mode(void);
+int delay_output(int a);
+int delch(void);
+void delscreen(void *s);
+int delwin(void *w);
+int deleteln();
+void* derwin(void *w, int a, int b, int c, int d);
+int doupdate();
+void* dupwin(void *w);
+int echo();
+int echochar(chtype a);
+int erase();
+int endwin();
+char erasechar();
+void filter();
+int flash();
+int flushinp();
+chtype getbkgd(void *w);
+int getch();
+int getnstr(char *a, int b);
+int getstr(char *a);
+void* getwin(void *f);
+int halfdelay(int a);
+bool has_colors();
+bool has_ic();
+bool has_il();
+int hline(chtype b, int c);
+void idcok(void* w, bool b);
+int idlok(void *w, bool b);
+void immedok(void *w, bool b);
+chtype inch();
+int inchnstr(chtype *a, int b);
+int inchstr(chtype *a);
+void* initscr();
+int init_color(short a, short b, short c, short d);
+int init_pair(short a, short b, short c);
+int innstr(char *a, int b);
+int insch(chtype a);
+int insdelln(int a);
+int insertln();
+int insnstr(char *a, int b);
+int insstr(char *a);
+int instr(char *a);
+int intrflush(void *a, bool b);
+bool isendwin();
+bool is_linetouched(void *a, int b);
+bool is_wintouched(void *a);
+char* keyname(int a);
+int keypad(void *a, bool b);
+char killchar();
+int leaveok(void *a, bool b);
+char* longname();
+int meta(void *a, bool b);
+int move(int a, int b);
+int mvaddch(int a, int b, chtype c);
+int mvaddchnstr(int a, int b, chtype *c, int d);
+int mvaddchstr(int a, int b, chtype *c);
+int mvaddnstr(int a, int b, char *c, int d);
+int mvaddstr(int a, int b, char *c);
+int mvchgat(int a, int b, int c, attr_t d, short e, void *f);
+int mvcur(int a, int b, int c, int d);
+int mvdelch(int a, int b);
+int mvderwin(void *a, int b, int c);
+int mvgetch(int a, int b);
+int mvgetnstr(int a, int b, char *c, int d);
+int mvgetstr(int a, int b, char *c);
+int mvhline(int a, int b, chtype c, int d);
+chtype mvinch(int a, int b);
+int mvinchnstr(int a, int b, chtype *c, int d);
+int mvinchstr(int a, int b, chtype *c);
+int mvinnstr(int a, int b, char *c, int d);
+int mvinsch(int a, int b, chtype c);
+int mvinsnstr(int a, int b, char *c, int d);
+int mvinsstr(int a, int b, char *c);
+int mvinstr(int a, int b, char *c);
+int mvprintw(int a, int b, char *c);
+int mvscanw(int a, int b, char *c);
+int mvvline(int a, int b, chtype c, int d);
+int mvwaddch(void *w, int b, int c, chtype d);
+int mvwaddchnstr(void *w, int b, int c, chtype *d, int e);
+int mvwaddchstr(void *w, int b, int c, chtype *d);
+int mvwaddnstr(void *w, int b, int c, char *d, int e);
+int mvwaddstr(void *w, int b, int c, char *d);
+int mvwchgat(void *w, int b, int c, int d, attr_t e, short f, void *g);
+int mvwdelch(void *w, int b, int c);
+int mvwgetch(void *w, int b, int c);
+int mvwgetnstr(void *w, int b, int c, char *d, int e);
+int mvwgetstr(void *w, int b, int c, char *d);
+int mvwhline(void *w, int b, int c, chtype d, int e);
+int mvwin(void *w, int b, int c);
+chtype mvwinch(void *w, int b, int c);
+int mvwinchnstr(void *w, int b, int c, chtype *d, int e);
+int mvwinchstr(void *w, int b, int c, chtype *d);
+int mvwinnstr(void *w, int b, int c, char *s, int d);
+int mvwinsch(void *w, int b, int c, chtype d);
+int mvwinsnstr(void *w, int b, int c, char *s, int d);
+int mvwinsstr(void *w, int b, int c, char *s);
+int mvwinstr(void *w, int b, int c, char *s);
+int mvwprintw(void *w, int b, int c, char *s);
+int mvwscanw(void *w, int b, int c, char *s);
+int mvwvline(void *w, int b, int c, chtype d, int e);
+int napms(int a);
+void* newpad(int a, int b);
+void* newterm(char *a, void *f1, void *f2);
+void* newwin(int a, int b, int c, int d);
+int nl();
+int nocbreak();
+int nodelay(void *w, bool b);
+int noecho();
+int nonl();
+void noqiflush();
+int noraw();
+int notimeout(void *w, bool b);
+int overlay(void *w, void *b);
+int overwrite(void *w, void *b);
+int pair_content(short a, short *b, short *c);
+int PAIR_NUMBER(int a);
+int pechochar(void *w, chtype b);
+int pnoutrefresh(void *w, int b, int c, int d, int e, int f, int g);
+int prefresh(void *w, int b, int c, int d, int e, int f, int g);
+int printw(char *s);
+int putwin(void *w, void *b);
+void qiflush();
+int raw();
+int redrawwin(void *w);
+int refresh();
+int resetty();
+int reset_prog_mode();
+int reset_shell_mode();
+int ripoffline(int a, void *f);
+int savetty();
+int scanw(char *s);
+int scr_dump(char *s);
+int scr_init(char *s);
+int scrl(int a);
+int scroll(void *a);
+int scrollok(void *a, bool b);
+int scr_restore(char *a);
+int scr_set(char *a);
+int setscrreg(int a, int b);
+void* set_term(void *a);
+int slk_attroff(chtype a);
+int slk_attr_off(attr_t a, void *b);
+int slk_attron(chtype a);
+int slk_attr_on(attr_t a, void *b);
+int slk_attrset(chtype a);
+attr_t slk_attr();
+int slk_attr_set(attr_t a, short b, void *c);
+int slk_clear();
+int slk_color(short a);
+int slk_init(int a);
+char* slk_label(int a);
+int slk_noutrefresh();
+int slk_refresh();
+int slk_restore();
+int slk_set(int a, char *b, int c);
+int slk_touch();
+int standout();
+int standend();
+int start_color();
+void* subpad(void *a, int b, int c, int d, int e);
+void* subwin(void *a, int b, int c, int d, int e);
+int syncok(void *a, bool b);
+chtype termattrs();
+char* termname();
+void timeout(int a);
+int touchline(void *w, int b, int c);
+int touchwin(void *w);
+int typeahead(int a);
+int ungetch(int a);
+int untouchwin(void *w);
+void use_env(bool b);
+int vidattr(chtype c);
+int vidputs(chtype c, void *f);
+int vline(chtype c, int b);
+int vwprintw(void *w, char *b);
+int vw_printw(void *w, char *b);
+int vwscanw(void *w, char *b);
+int vw_scanw(void *w, char *b);
+int waddch(void *w, chtype b);
+int waddchnstr(void *w, chtype *b, int c);
+int waddchstr(void *w, chtype *b);
+int waddnstr(void *w,char *b, int b);
+int waddstr(void *w, char *b);
+int wattron(void *w, int b);
+int wattroff(void *w, int b);
+int wattrset(void *w, int b);
+int wattr_get(void *w, attr_t *b, short *c, void *d);
+int wattr_on(void *w, attr_t b, void *c);
+int wattr_off(void *w, attr_t b, void *c);
+int wattr_set(void *w, attr_t b, short c, void *d);
+int wbkgd(void *w, chtype a);
+void wbkgdset(void *w, chtype a);
+int wborder(void *w, chtype a, chtype b, chtype c, chtype d, chtype e, chtype f, chtype g, chtype h);
+int wchgat(void *w, int a, attr_t b, short c, void *p);
+int wclear(void *w);
+int wclrtobot(void *w);
+int wclrtoeol(void *w);
+int wcolor_set(void *w, short b, void *p);
+void wcursyncup(void *w);
+int wdelch(void *w);
+int wdeleteln(void *w);
+int wechochar(void *w, chtype c);
+int werase(void *w);
+int wgetch(void *w);
+int wgetnstr(void *w, char *s, int d);
+int wgetstr(void *w, char *s);
+int whline(void *w, chtype c, int d);
+chtype winch(void *w);
+int winchnstr(void *w, chtype *c, int d);
+int winchstr(void *w, chtype *c);
+int winnstr(void *w, char *s, int c);
+int winsch(void *w, chtype c);
+int winsdelln(void *w, int a);
+int winsertln(void *w);
+int winsnstr(void *w, char *s, int c);
+int winsstr(void *w, char *s);
+int winstr(void *w, char *s);
+int wmove(void *w, int a, int b);
+int wnoutrefresh(void *w);
+int wprintw(void *w, char *s);
+int wredrawln(void *w, int a, int b);
+int wrefresh(void *w);
+int wscanw(void *w, char *s);
+int wscrl(void *w, int a);
+int wsetscrreg(void *w, int a, int b);
+int wstandout(void *w);
+int wstandend(void *w);
+void wsyncdown(void *w);
+void wsyncup(void *w);
+void wtimeout(void *w, int a);
+int wtouchln(void *w, int a, int b, int c);
+int wvline(void *w, chtype a, int b);
+
+int tigetflag(char *s);
+int tigetnum(char *s);
+char tigetstr(char *s);
+int putp(char *s);
+char tparm(char *s);
+char* tparm_varargs(char *s);
+
+int getcurx(void *w);
+int getcury(void *w);
+int getbegx(void *w);
+int getbegy(void *w);
+int getmaxx(void *w);
+int getmaxy(void *w);
+int getparx(void *w);
+int getpary(void *w);
+
+int vsscanf(char *s, char *s1);
+
+typedef long mmask_t;
+
+int getmouse(void *e);
+int ungetmouse(void *e);
+mmask_t mousemask(mmask_t a, mmask_t *b);
+bool wenclose(void *w, int a, int c);
+int mouseinterval(int a);
+bool wmouse_trafo(void *w, int *a, int *b, bool c);
+bool mouse_trafo(int *a, int *b, bool c);
+
+int mcprint(char *s, int a);
+int has_key(int a);
+
+void _tracef(char *s);
+void _tracedump(char *s, void *w);
+char* _traceattr(attr_t a);
+char* _traceattr2(int a, chtype c);
+char* _nc_tracebits();
+char* _tracechar(int a);
+char* _tracechtype(chtype c);
+char* _tracechtype2(int a, chtype c);
+char* _tracecchar_t(void *a);
+char* _tracecchar_t2(int a, void *b);
+char* _tracemouse(void *e);
+void trace(u_int a);
diff --git a/etc/latrace.d/netdb.conf b/etc/latrace.d/netdb.conf
new file mode 100644
index 0000000..4443d44
--- /dev/null
+++ b/etc/latrace.d/netdb.conf
@@ -0,0 +1,110 @@
+
+/* /usr/include/netdb.h */
+
+
+int* __h_errno_location();
+void herror(char *str);
+char* hstrerror(int err_num);
+
+
+struct hostent {
+ char* h_name;
+ void* h_aliases;
+ int h_addrtype;
+ int h_length;
+ void* h_addr_list;
+};
+
+
+void sethostent(int stay_open);
+void endhostent();
+struct hostent* gethostent();
+struct hostent* gethostbyaddr(void *addr, socklen_t len, int type);
+struct hostent* gethostbyname(char *name);
+struct hostent* gethostbyname2(char *name, int af);
+
+
+int gethostent_r(struct hostent *result_buf, char *buf, size_t buflen, void *result, int *h_errnop);
+int gethostbyaddr_r(void *addr, socklen_t len, int type, struct hostent *result_buf, char *buf, size_t buflen, void *result, int *h_errnop);
+int gethostbyname_r(char *name, struct hostent *result_buf, char *buf, size_t buflen, void *result, int *h_errnop);
+int gethostbyname2_r(char *name, int af, struct hostent *result_buf, char *buf, size_t buflen, void *result, int *h_errnop);
+
+
+void setnetent(int stay_open);
+void endnetent();
+void* getnetent();
+void* getnetbyaddr(uint32_t net, int type);
+void* getnetbyname(char *name);
+int getnetent_r(void *result_buf, char *buf, size_t buflen,void *result, int *h_errnop);
+int getnetbyaddr_r(uint32_t net, int type, void *result_buf, char *buf, size_t buflen, void *result, int *h_errnop);
+int getnetbyname_r(char *name, void *result_buf, char *buf, size_t buflen, void *result, int *h_errnop);
+
+
+struct servent {
+ char *s_name;
+ void *s_aliases;
+ int s_port;
+ char *s_proto;
+};
+
+
+void setservent(int stay_open);
+void endservent();
+struct servent* getservent();
+struct servent* getservbyname(char *name, char *proto);
+struct servent* getservbyport(int port, char *proto);
+int getservent_r(struct servent *result_buf, char *buf, size_t buflen, void *result);
+int getservbyname_r(char *name, char *proto, struct servent *result_buf, char *buf, size_t buflen, void *result);
+int getservbyport_r(int port, char *proto, struct servent *result_buf, char *buf, size_t buflen, void *result);
+
+
+struct protoent {
+ char *p_name;
+ char *p_aliases;
+ int p_proto;
+};
+
+
+void setprotoent(int stay_open);
+void endprotoent();
+struct protoent* getprotoent();
+struct protoent* getprotobyname(char *name);
+struct protoent* getprotobynumber(int proto);
+int getprotoent_r(struct protoent* result_buf, char *buf, size_t buflen, void *result);
+int getprotobyname_r(char *name, struct protoent *result_buf, char *buf, size_t buflen, void *result);
+int getprotobynumber_r(int proto, struct protoent* result_buf, char *buf, size_t buflen, void *result);
+
+
+int setnetgrent(char *netgroup);
+void endnetgrent();
+int getnetgrent(void *hostp, void *userp, void *domainp);
+int innetgr(char *netgroup, char *host, char *user, char *domain);
+int getnetgrent_r(void *hostp, void *userp, void *domainp, char *buffer, size_t buflen);
+
+
+int rcmd(void *ahost, u_short rport, char *locuser, char *remuser, char *cmd, int *fd2p);
+int rcmd_af(void *ahost, u_short rport, char *locuser, char *remuser, char *cmd, int *fd2p, u_int af);
+
+
+int rexec(void *ahost, int rport, char *name, char *pass, char *cmd, int *fd2p);
+int rexec_af(void *ahost, int rport, char *name, char *pass, char *cmd, int *fd2p, u_int af);
+
+
+int ruserok(char *rhost, int suser, char *remuser, char *locuser);
+int ruserok_af(char *rhost, int suser, char *remuser, char *locuser, u_int af);
+
+
+int rresvport(int *alport);
+int rresvport_af(int *alport, u_int af);
+
+
+int getaddrinfo(char *name, char *service, void *req, void *pai);
+void freeaddrinfo(void *ai);
+
+
+char* gai_strerror(int ecode);
+int getnameinfo(void *sa, socklen_t salen, char *host, socklen_t hostlen, char *serv, socklen_t servlen, u_int flags);
+int getaddrinfo_a(int mode, void *list, int ent, void *sig);
+int gai_suspend(void *list, int ent, void *timeout);
+int gai_error(void *req);
+int gai_cancel(void *gaicbp);
diff --git a/etc/latrace.d/pthread.conf b/etc/latrace.d/pthread.conf
new file mode 100644
index 0000000..02ad872
--- /dev/null
+++ b/etc/latrace.d/pthread.conf
@@ -0,0 +1,162 @@
+
+/* /usr/include/pthread.h */
+
+
+typedef void __clockid_t;
+typedef u_long pthread_t;
+typedef void pthread_attr_t;
+typedef void sched_param;
+typedef void cpu_set_t;
+typedef void pthread_once_t;
+typedef void pthread_mutex_t;
+typedef void pthread_mutexattr_t;
+typedef void pthread_rwlock_t;
+typedef void pthread_rwlockattr_t;
+typedef void pthread_cond_t;
+typedef void pthread_condattr_t;
+typedef void pthread_barrier_t;
+typedef void pthread_spinlock_t;
+typedef void pthread_barrierattr_t;
+typedef u_int pthread_key_t;
+
+
+int pthread_create(pthread_t *newthread, pthread_attr_t *attr, void *start_routine, void *__arg);
+void pthread_exit(void *retval);
+int pthread_join(pthread_t th, void *thread_return);
+int pthread_tryjoin_np(pthread_t th, void *thread_return);
+int pthread_timedjoin_np(pthread_t th, void *thread_return, timespec *abstime);
+int pthread_detach(pthread_t th);
+int pthread_equal(pthread_t thread1, pthread_t thread2);
+
+
+pthread_t pthread_self();
+
+
+int pthread_attr_init(pthread_attr_t *attr);
+int pthread_attr_destroy(pthread_attr_t *attr);
+int pthread_attr_getdetachstate(pthread_attr_t *attr, int *detachstate);
+int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
+int pthread_attr_getguardsize(pthread_attr_t *attr, size_t *guardsize);
+int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize);
+int pthread_attr_getschedparam(pthread_attr_t *attr, sched_param *param);
+int pthread_attr_setschedparam(pthread_attr_t *attr, sched_param *param);
+int pthread_attr_getschedpolicy(pthread_attr_t *attr, int *policy);
+int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy);
+int pthread_attr_getinheritsched(pthread_attr_t *attr, int *inherit);
+int pthread_attr_setinheritsched(pthread_attr_t *attr, int inherit);
+int pthread_attr_getscope(pthread_attr_t *attr, int *scope);
+int pthread_attr_setscope(pthread_attr_t *attr, int scope);
+int pthread_attr_getstackaddr(pthread_attr_t *attr, void *stackaddr);
+int pthread_attr_setstackaddr(pthread_attr_t *attr, void *stackaddr);
+int pthread_attr_getstacksize(pthread_attr_t *attr, size_t *stacksize);
+int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);
+int pthread_attr_getstack(pthread_attr_t *attr, void *stackaddr, size_t *stacksize);
+int pthread_attr_setstack(pthread_attr_t *attr, void *stackaddr, size_t stacksize);
+int pthread_attr_setaffinity_np(pthread_attr_t *attr, size_t cpusetsize, cpu_set_t *cpuset);
+int pthread_attr_getaffinity_np(pthread_attr_t *attr, size_t cpusetsize, cpu_set_t *cpuset);
+int pthread_getattr_np(pthread_t th, pthread_attr_t *attr);
+
+
+int pthread_setschedparam(pthread_t target_thread, int policy, sched_param *param);
+int pthread_getschedparam(pthread_t target_thread, int *policy, sched_param *param);
+int pthread_setschedprio(pthread_t target_thread, int prio);
+int pthread_getconcurrency();
+int pthread_setconcurrency(int level);
+int pthread_yield();
+
+
+int pthread_setaffinity_np(pthread_t th, size_t cpusetsize, cpu_set_t *cpuset);
+int pthread_getaffinity_np(pthread_t th, size_t cpusetsize, cpu_set_t *cpuset);
+int pthread_once(pthread_once_t *once_control, void *init_routine);
+int pthread_setcancelstate(int state, int *oldstate);
+int pthread_setcanceltype(int type, int *oldtype);
+int pthread_cancel(pthread_t th);
+void pthread_testcancel();
+
+
+int pthread_mutex_init(pthread_mutex_t *mutex, pthread_mutexattr_t *mutexattr);
+int pthread_mutex_destroy(pthread_mutex_t *mutex);
+int pthread_mutex_trylock(pthread_mutex_t *mutex);
+int pthread_mutex_lock(pthread_mutex_t *mutex);
+int pthread_mutex_timedlock(pthread_mutex_t *mutex, timespec *abstime);
+int pthread_mutex_unlock(pthread_mutex_t *mutex);
+int pthread_mutex_getprioceiling(pthread_mutex_t *mutex, int *prioceiling);
+int pthread_mutex_setprioceiling(pthread_mutex_t *mutex, int prioceiling, int *old_ceiling);
+int pthread_mutex_consistent_np(pthread_mutex_t *mutex);
+
+
+int pthread_mutexattr_init(pthread_mutexattr_t *attr);
+int pthread_mutexattr_destroy(pthread_mutexattr_t *attr);
+int pthread_mutexattr_getpshared(pthread_mutexattr_t *attr, int *pshared);
+int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr, int pshared);
+int pthread_mutexattr_gettype(pthread_mutexattr_t *attr, int *kind);
+int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int kind);
+int pthread_mutexattr_getprotocol(pthread_mutexattr_t *attr, int *protocol);
+int pthread_mutexattr_setprotocol(pthread_mutexattr_t *attr, int protocol);
+int pthread_mutexattr_getprioceiling(pthread_mutexattr_t *attr, int *prioceiling);
+int pthread_mutexattr_setprioceiling(pthread_mutexattr_t *attr, int prioceiling);
+int pthread_mutexattr_getrobust_np(pthread_mutexattr_t *attr, int *robustness);
+int pthread_mutexattr_setrobust_np(pthread_mutexattr_t *attr, int robustness);
+
+
+int pthread_rwlock_init(pthread_rwlock_t *rwlock, pthread_rwlockattr_t *attr);
+int pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
+int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
+int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
+int pthread_rwlock_timedrdlock(pthread_rwlock_t *rwlock, timespec *abstime);
+int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
+int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);
+int pthread_rwlock_timedwrlock(pthread_rwlock_t *rwlock, timespec *abstime);
+int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
+
+
+int pthread_rwlockattr_init(pthread_rwlockattr_t *attr);
+int pthread_rwlockattr_destroy(pthread_rwlockattr_t *attr);
+int pthread_rwlockattr_getpshared(pthread_rwlockattr_t *attr, int *pshared);
+int pthread_rwlockattr_setpshared(pthread_rwlockattr_t *attr, int pshared);
+int pthread_rwlockattr_getkind_np(pthread_rwlockattr_t *attr, int *pref);
+int pthread_rwlockattr_setkind_np(pthread_rwlockattr_t *attr, int pref);
+
+
+int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr);
+int pthread_cond_destroy(pthread_cond_t *cond);
+int pthread_cond_signal(pthread_cond_t *cond);
+int pthread_cond_broadcast(pthread_cond_t *cond);
+int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
+int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, timespec *abstime);
+
+
+int pthread_condattr_init(pthread_condattr_t *attr);
+int pthread_condattr_destroy(pthread_condattr_t *attr);
+int pthread_condattr_getpshared(pthread_condattr_t *attr, int *pshared);
+int pthread_condattr_setpshared(pthread_condattr_t *attr, int pshared);
+int pthread_condattr_getclock(pthread_condattr_t *attr, __clockid_t *clock_id);
+int pthread_condattr_setclock(pthread_condattr_t *attr, __clockid_t clock_id);
+
+
+int pthread_spin_init(pthread_spinlock_t *lock, int pshared);
+int pthread_spin_destroy(pthread_spinlock_t *lock);
+int pthread_spin_lock(pthread_spinlock_t *lock);
+int pthread_spin_trylock(pthread_spinlock_t *lock);
+int pthread_spin_unlock(pthread_spinlock_t *lock);
+
+
+int pthread_barrier_init(pthread_barrier_t *barrier, pthread_barrierattr_t *attr, u_int count);
+int pthread_barrier_destroy(pthread_barrier_t *barrier);
+int pthread_barrier_wait(pthread_barrier_t *barrier);
+
+
+int pthread_barrierattr_init(pthread_barrierattr_t *attr);
+int pthread_barrierattr_destroy(pthread_barrierattr_t *attr);
+int pthread_barrierattr_getpshared(pthread_barrierattr_t *attr, int *pshared);
+int pthread_barrierattr_setpshared(pthread_barrierattr_t *attr, int pshared);
+
+
+int pthread_key_create(pthread_key_t *key, void *destr_function);
+int pthread_key_delete(pthread_key_t key);
+void* pthread_getspecific(pthread_key_t key);
+int pthread_setspecific(pthread_key_t key, void *pointer);
+
+
+int pthread_getcpuclockid(pthread_t thread_id, __clockid_t *clock_id);
+int pthread_atfork(void *prepare, void *parent, void *child);
diff --git a/etc/latrace.d/pwd.conf b/etc/latrace.d/pwd.conf
new file mode 100644
index 0000000..b2139a5
--- /dev/null
+++ b/etc/latrace.d/pwd.conf
@@ -0,0 +1,29 @@
+
+/* /usr/include/pwd.h */
+
+
+struct passwd {
+ char *pw_name;
+ char *pw_passwd;
+ __uid_t pw_uid;
+ __gid_t pw_gid;
+ char *pw_gecos;
+ char *pw_dir;
+ char *pw_shell;
+};
+
+
+void setpwent();
+void endpwent();
+struct passwd* getpwent();
+struct passwd* fgetpwent(FILE *stream);
+int putpwent(struct passwd *p, FILE *f);
+struct passwd* getpwuid(__uid_t uid);
+struct passwd* getpwnam(char *name);
+
+
+int getpwent_r(struct passwd *resultbuf, char *buffer, size_t buflen, void *result);
+int getpwuid_r(__uid_t uid, struct passwd *resultbuf, char *buffer, size_t buflen, void *result);
+int getpwnam_r(char *name, struct passwd *resultbuf, char *buffer, size_t buflen, void *result);
+int fgetpwent_r(FILE *stream, struct passwd *resultbuf, char *buffer, size_t __buflen, void *result);
+int getpw(__uid_t uid, char *buffer);
diff --git a/etc/latrace.d/resource.conf b/etc/latrace.d/resource.conf
new file mode 100644
index 0000000..a548740
--- /dev/null
+++ b/etc/latrace.d/resource.conf
@@ -0,0 +1,73 @@
+
+/* /usr/include/sys/resource.h */
+
+/* Kinds of resource limit. */
+enum rlimit_resource
+{
+ /* Per-process CPU limit, in seconds. */
+ RLIMIT_CPU = 0,
+ /* Largest file that can be created, in bytes. */
+ RLIMIT_FSIZE = 1,
+ /* Maximum size of data segment, in bytes. */
+ RLIMIT_DATA = 2,
+ /* Maximum size of stack segment, in bytes. */
+ RLIMIT_STACK = 3,
+ /* Largest core file that can be created, in bytes. */
+ RLIMIT_CORE = 4,
+ /* Largest resident set size, in bytes.
+ This affects swapping; processes that are exceeding their
+ resident set size will be more likely to have physical memory
+ taken from them. */
+ RLIMIT_RSS = 5,
+ /* Number of open files. */
+ RLIMIT_NOFILE = 7,
+ RLIMIT_OFILE = RLIMIT_NOFILE, /* BSD name for same. */
+ /* Address space limit. */
+ RLIMIT_AS = 9,
+ /* Number of processes. */
+ RLIMIT_NPROC = 6,
+ /* Locked-in-memory address space. */
+ RLIMIT_MEMLOCK = 8,
+ /* Maximum number of file locks. */
+ RLIMIT_LOCKS = 10,
+ /* Maximum number of pending signals. */
+ RLIMIT_SIGPENDING = 11,
+ /* Maximum bytes in POSIX message queues. */
+ RLIMIT_MSGQUEUE = 12,
+ /* Maximum nice priority allowed to raise to.
+ Nice levels 19 .. -20 correspond to 0 .. 39
+ values of this resource limit. */
+ RLIMIT_NICE = 13,
+ /* Maximum realtime priority allowed for non-priviledged
+ processes. */
+ LIMIT_RTPRIO = 14,
+ RLIMIT_NLIMITS = 15
+};
+
+/* Whose usage statistics do you want? */
+enum rusage_who
+{
+ /* The calling process. */
+ RUSAGE_SELF = 0,
+ /* All of its terminated child processes. */
+ RUSAGE_CHILDREN = -1,
+ /* The calling thread. */
+ RUSAGE_THREAD = 1
+};
+
+enum priority_which
+{
+ PRIO_PROCESS = 0, /* WHO is a process ID. */
+ PRIO_PGRP = 1, /* WHO is a process group ID. */
+ PRIO_USER = 2 /* WHO is a user ID. */
+};
+
+extern int getrlimit(int resource = rlimit_resource, void *rlimits);
+extern int getrlimit64(int resource = rlimit_resource, void *rlimits);
+extern int setrlimit(int resource = rlimit_resource, void *rlimits);
+extern int setrlimit64(int resource = rlimit_resource, void *rlimits);
+
+extern int getrusage(int who = rusage_who, void *usage);
+
+extern int getpriority(int which = priority_which, int who);
+extern int setpriority (int which = priority_which, int who, int prio);
diff --git a/etc/latrace.d/signal.conf b/etc/latrace.d/signal.conf
new file mode 100644
index 0000000..11a9d2a
--- /dev/null
+++ b/etc/latrace.d/signal.conf
@@ -0,0 +1,100 @@
+
+/* /usr/include/signal.h */
+
+enum SIGNALS {
+ SIGHUP = 1,
+ SIGINT = 2,
+ SIGQUIT = 3,
+ SIGILL = 4,
+ SIGTRAP = 5,
+ SIGABRT = 6,
+ SIGIOT = 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,
+ SIGUNUSED = 31,
+ SIGRTMIN = 32,
+ SIGRTMAX = 32
+};
+
+enum SIGNAL_HANDLER {
+ SIG_DFL = 0,
+ SIG_IGN = 1,
+ SIG_ERR = -1
+};
+
+
+void* __sysv_signal(int sig = SIGNALS, void *handler = SIGNAL_HANDLER);
+void* sysv_signal(int sig = SIGNALS, void *handler = SIGNAL_HANDLER);
+void* signal(int sig = SIGNALS, void *handler = SIGNAL_HANDLER);
+void* bsd_signal(int sig = SIGNALS, void *handler = SIGNAL_HANDLER);
+
+
+int kill(__pid_t pid, int sig = SIGNALS);
+int killpg(__pid_t pgrp, int sig = SIGNALS);
+int raise(int sig = SIGNALS);
+
+
+void* ssignal(int sig = SIGNALS, void *handler = SIGNAL_HANDLER);
+int gsignal(int sig = SIGNALS);
+void psignal(int sig = SIGNALS, char *s);
+
+
+int __sigpause(int sig_or_mask, int is_sig);
+int sigpause(int mask);
+int sigblock(int mask);
+
+
+int sigsetmask(int mask);
+int siggetmask();
+int sigemptyset(void *set);
+int sigfillset(void *set);
+int sigaddset(void *set, int signo = SIGNALS);
+int sigdelset(void *set, int signo = SIGNALS);
+int sigismember(void *set, int signo = SIGNALS);
+int sigisemptyset(void *set);
+int sigandset(void *set, void *left, void *right);
+int sigorset(void *set, void *left, void *right);
+int sigprocmask(int how, void *set, void *oset);
+int sigsuspend(void *set);
+int sigaction(int sig = SIGNALS, void *act, void *oact);
+int sigpending(void *set);
+int sigwait(void *set, int *sig);
+int sigwaitinfo(void *set, void *info);
+int sigtimedwait(void *set, void *info, void *__timeout);
+
+
+int sigqueue(__pid_t pid, int sig = SIGNALS, u_int val);
+int sigvec(int sig = SIGNALS, void *vec, void *ovec);
+int sigreturn(void *scp);
+int siginterrupt(int sig = SIGNALS, int interrupt);
+int sigstack(void *ss, void *oss);
+int sigaltstack(void *ss, void *oss);
+int sighold(int sig = SIGNALS);
+int sigrelse(int sig = SIGNALS);
+int sigignore(int sig = SIGNALS);
+void* sigset(int sig = SIGNALS, void *disp);
+int __libc_current_sigrtmin();
+int __libc_current_sigrtmax();
diff --git a/etc/latrace.d/socket.conf b/etc/latrace.d/socket.conf
new file mode 100644
index 0000000..9e30f26
--- /dev/null
+++ b/etc/latrace.d/socket.conf
@@ -0,0 +1,78 @@
+
+/* /usr/include/sys/socket.h */
+
+enum PF_TYPE {
+ PF_UNIX = 1, /* Unix domain sockets */
+ PF_LOCAL = 1, /* POSIX name for AF_UNIX */
+ PF_INET = 2, /* Internet IP Protocol */
+ PF_AX25 = 3, /* Amateur Radio AX.25 */
+ PF_IPX = 4, /* Novell IPX */
+ PF_APPLETALK = 5, /* AppleTalk DDP */
+ PF_NETROM = 6, /* Amateur Radio NET/ROM */
+ PF_BRIDGE = 7, /* Multiprotocol bridge */
+ PF_ATMPVC = 8, /* ATM PVCs */
+ PF_X25 = 9, /* Reserved for X.25 project */
+ PF_INET6 = 10, /* IP version 6 */
+ PF_ROSE = 11, /* Amateur Radio X.25 PLP */
+ PF_DECnet = 12, /* Reserved for DECnet project */
+ PF_NETBEUI = 13, /* Reserved for 802.2LLC project*/
+ PF_SECURITY = 14, /* Security callback pseudo AF */
+ PF_KEY = 15, /* PF_KEY key management API */
+ PF_NETLINK = 16,
+ PF_ROUTE = 16, /* Alias to emulate 4.4BSD */
+ PF_PACKET = 17, /* Packet family */
+ PF_ASH = 18, /* Ash */
+ PF_ECONET = 19, /* Acorn Econet */
+ PF_ATMSVC = 20, /* ATM SVCs */
+ PF_RDS = 21, /* RDS sockets */
+ PF_SNA = 22, /* Linux SNA Project (nutters!) */
+ PF_IRDA = 23, /* IRDA sockets */
+ PF_PPPOX = 24, /* PPPoX sockets */
+ PF_WANPIPE = 25, /* Wanpipe API Sockets */
+ PF_LLC = 26, /* Linux LLC */
+ PF_CAN = 29, /* Controller Area Network */
+ PF_TIPC = 30, /* TIPC sockets */
+ PF_BLUETOOTH = 31, /* Bluetooth sockets */
+ PF_IUCV = 32, /* IUCV sockets */
+ PF_RXRPC = 33, /* RxRPC sockets */
+ PF_ISDN = 34, /* mISDN sockets */
+ PF_PHONET = 35 /* Phonet sockets */
+};
+
+enum SOCK_TYPE {
+ SOCK_STREAM = 1,
+ SOCK_DGRAM = 2,
+ SOCK_RAW = 3,
+ SOCK_RDM = 4,
+ SOCK_SEQPACKET = 5,
+ SOCK_DCCP = 6,
+ SOCK_PACKET = 10
+};
+
+int socket(int domain = PF_TYPE, int type = SOCK_TYPE, int protocol);
+int socketpair(int domain = PF_TYPE, int type = SOCK_TYPE, int protocol, void *fds);
+int bind(int fd, void *addr, socklen_t len);
+int getsockname(int fd, void *addr, socklen_t *len);
+int connect(int fd, void *addr, socklen_t len);
+int getpeername(int fd, void *addr, socklen_t *len);
+
+
+size_t send(int fd, void *buf, size_t n, int flags);
+size_t recv(int fd, void *buf, size_t n, int flags);
+
+
+size_t sendto(int fd, void *buf, size_t n, int flags, void *addr, socklen_t addr_len);
+size_t recvfrom(int fd, void *buf, size_t n, int flags, void *addr, socklen_t *addr_len);
+size_t sendmsg(int fd, void *message, int flags);
+size_t recvmsg(int fd, void *message, int flags);
+
+
+int getsockopt(int fd, int level, int optname, void *optval, socklen_t *optlen);
+int setsockopt(int fd, int level, int optname, void *optval, socklen_t optlen);
+
+
+int listen(int fd, int n);
+int accept(int fd, void *addr, socklen_t *addr_len);
+int shutdown(int fd, int how);
+int sockatmark(int fd);
+int isfdtype(int fd, int fdtype);
diff --git a/etc/latrace.d/stat.conf b/etc/latrace.d/stat.conf
new file mode 100644
index 0000000..fa60e9b
--- /dev/null
+++ b/etc/latrace.d/stat.conf
@@ -0,0 +1,54 @@
+
+/* /usr/include/sys/stat.h */
+
+
+typedef void stat;
+typedef void stat64;
+
+int stat(char *file, stat *buf);
+int fstat(int fd, stat *buf);
+int stat64(char *file, stat64 *buf);
+int fstat64(int fd, stat64 *buf);
+int fstatat(int fd, char *file, stat *buf, int flag);
+int fstatat64(int fd, char *file, stat64 *buf, int flag);
+int lstat(char *file, stat *buf);
+int lstat64(char *file, stat64 *buf);
+
+
+int chmod(char *file, __mode_t mode);
+int lchmod(char *file, __mode_t mode);
+int fchmod(int fd, __mode_t mode);
+int fchmodat(int fd, char *file, __mode_t mode, int flag);
+
+
+__mode_t umask(__mode_t mask);
+__mode_t getumask();
+
+
+int mkdir(char *path, __mode_t mode);
+int mkdirat(int fd, char *path, __mode_t mode);
+
+int mknod(char *path, __mode_t mode, __dev_t dev);
+int mknodat(int fd, char *path, __mode_t mode, __dev_t dev);
+
+
+int mkfifo(char *path, __mode_t mode);
+int mkfifoat(int fd, char *path, __mode_t mode);
+
+
+int utimensat(int fd, char *path, void *times, int flags);
+int futimens(int fd, void *times);
+
+
+int __fxstat(int ver, int fildes, stat *stat_buf);
+int __xstat(int ver, char *filename, stat *stat_buf);
+int __lxstat(int ver, char *filename, stat *stat_buf);
+int __fxstatat(int ver, int fildes, char *filename, stat *stat_buf, int flag);
+int __fxstat64(int ver, int fildes, stat64 *stat_buf);
+int __xstat64(int ver, char *filename, stat64 *stat_buf);
+int __lxstat64(int ver, char *filename, stat64 *stat_buf);
+int __fxstatat64(int ver, int fildes, char *filename, stat64 *stat_buf, int flag);
+
+
+int __xmknod(int ver, char *path, __mode_t mode, __dev_t *dev);
+int __xmknodat(int ver, int fd, char *path, __mode_t mode, __dev_t *dev);
diff --git a/etc/latrace.d/stdio.conf b/etc/latrace.d/stdio.conf
new file mode 100644
index 0000000..c0f37b8
--- /dev/null
+++ b/etc/latrace.d/stdio.conf
@@ -0,0 +1,137 @@
+
+/* /usr/include/stdio.h */
+
+int remove(char *filename);
+int rename(char *old, char *new);
+int renameat(int oldfd, char *old, int newfd, char *new);
+
+
+FILE *tmpfile(void);
+FILE *tmpfile64(void);
+char *tmpnam(char *s);
+char *tmpnam_r(char *s);
+char *tempnam(char *dir, char *pfx);
+
+
+int fclose(FILE *stream);
+int fflush(FILE *stream);
+int fflush_unlocked(FILE *stream);
+int fcloseall(void);
+
+
+FILE* fopen(char *filename, char *modes);
+FILE* freopen(char *filename, char *modes, FILE *stream);
+
+
+FILE* fopen64(char *filename, char *modes);
+FILE* freopen64(char *filename, char *modes, FILE *stream);
+FILE* fdopen(int fd, char *modes);
+FILE* fopencookie(void *magic_cookie, char *modes, void *io_funcs);
+FILE* fmemopen(void *s, size_t len, char *modes);
+FILE* open_memstream(void *bufloc, size_t *sizeloc);
+
+
+void setbuf(FILE *stream, char *buf);
+int setvbuf(FILE *stream, char *buf, int modes, size_t n);
+void setbuffer(FILE *stream, char *buf, size_t size);
+void setlinebuf(FILE *stream);
+
+
+int fprintf(FILE *stream, char *format);
+int printf(char *format);
+int sprintf(char *s, char *format);
+int vfprintf(FILE *s, char *format);
+int vprintf(char *format);
+int vsprintf(char *s, char *format);
+int snprintf(char *s, size_t maxlen, char *format);
+int vsnprintf(char *s, size_t maxlen, char *format);
+int vasprintf(void *ptr, char *f);
+int __asprintf(void *ptr, char *fmt);
+int asprintf(void *ptr, char *fmt);
+int vdprintf(int fd, char *fmt);
+int dprintf(int fd, char *fmt);
+int fscanf(FILE *stream, char *format);
+int scanf(char *format);
+int sscanf(char *s, char *format);
+int vfscanf(FILE *s, char *format);
+int vscanf(char *format);
+int vsscanf(char *s, char *format);
+
+int fgetc(FILE *stream);
+int getc(FILE *stream);
+int getchar();
+int getc_unlocked(FILE *stream);
+int getchar_unlocked();
+int fgetc_unlocked(FILE *__stream);
+int fputc(int c, FILE *stream);
+int putc(int c, FILE *stream);
+int putchar(int c);
+int fputc_unlocked(int c, FILE *stream);
+int putc_unlocked(int c, FILE *stream);
+int putchar_unlocked(int c);
+int getw(FILE *stream);
+int putw(int w, FILE *stream);
+char* fgets(char *s, int n, FILE *stream);
+char* gets(char *s);
+char* fgets_unlocked(char *s, int n, FILE *stream);
+size_t __getdelim(void *lineptr, size_t *n, int delimiter, FILE *stream);
+size_t getdelim(void *lineptr, size_t *n, int delimiter, FILE *stream);
+size_t getline(void *lineptr, size_t *n, FILE *stream);
+int fputs(char *s, FILE *stream);
+int puts(char *s);
+int ungetc(int c, FILE *stream);
+
+
+size_t fread(void *ptr, size_t size, size_t n, FILE *stream);
+size_t fwrite(void *ptr, size_t size, size_t n, FILE *s);
+int fputs_unlocked(char *s, FILE *stream);
+size_t fread_unlocked(void *ptr, size_t size, size_t n, FILE *stream);
+size_t fwrite_unlocked(void *ptr, size_t size, size_t n, FILE *stream);
+int fseek(FILE *stream, long off, int whence);
+long ftell(FILE *stream);
+
+
+void rewind(FILE *stream);
+int fseeko(FILE *stream, __off_t off, int whence);
+__off_t ftello(FILE *stream);
+int fgetpos(FILE *stream, fpos_t *pos);
+int fsetpos(FILE *stream, fpos_t *pos);
+
+
+typedef long __off64_t;
+typedef void fpos64_t;
+
+
+int fseeko64(FILE *stream, __off64_t off, int whence);
+__off64_t ftello64(FILE *stream);
+
+
+int fgetpos64(FILE *stream, fpos64_t *pos);
+int fsetpos64(FILE *stream, fpos64_t *pos);
+
+
+void clearerr(FILE *stream);
+int feof(FILE *stream);
+int ferror(FILE *stream);
+void clearerr_unlocked(FILE *stream);
+int feof_unlocked(FILE *stream);
+int ferror_unlocked(FILE *stream);
+
+
+void perror(char *s);
+
+
+int fileno(FILE *stream);
+int fileno_unlocked(FILE *stream);
+FILE* popen(char *command, char *modes);
+int pclose(FILE *stream);
+char* ctermid(char *s);
+char* cuserid(char *s);
+
+
+int obstack_printf(void *obstack, char *format);
+int obstack_vprintf(void *obstack, char *format);
+void flockfile(FILE *stream);
+int ftrylockfile(FILE *stream);
+void funlockfile(FILE *stream);
+
diff --git a/etc/latrace.d/stdlib.conf b/etc/latrace.d/stdlib.conf
new file mode 100644
index 0000000..63afa71
--- /dev/null
+++ b/etc/latrace.d/stdlib.conf
@@ -0,0 +1,210 @@
+
+/* /usr/include/stdlib.h */
+
+size_t __ctype_get_mb_cur_max(void);
+
+int atoi(char *nptr);
+long atol(char *nptr);
+long atoll(char *nptr);
+long strtol(char *nptr, void *endptr, int base);
+
+
+/* we dont do big numbers so far...
+
+double atof(char *nptr);
+double strtod(char *nptr, void *endptr);
+float strtof(char *nptr, void *endptr);
+long double strtold(char *nptr, void *endptr);
+u_long strtoul(char *nptr, void *endptr, int base);
+long long int strtoq(char *nptr, void *endptr, int base);
+unsigned long long int strtouq(char *nptr, void *endptr, int base);
+long long int strtoll(char *nptr, void *endptr, int base);
+unsigned long long int strtoull(char *nptr, void *endptr, int base);
+long strtol_l(char *nptr, void *endptr, int base, locale_t loc);
+unsigned long int strtoul_l(char *nptr, void *endptr, int base, locale_t loc);
+long long int strtoll_l(char *nptr, void *endptr, int base, locale_t loc);
+unsigned long long int strtoull_l(char *nptr, void *endptr, int base, locale_t loc);
+double strtod_l(char *nptr, void *endptr, locale_t loc);
+float strtof_l(char *nptr, void *endptr, locale_t loc);
+long double strtold_l(char *nptr, void *endptr, locale_t loc);
+
+*/
+
+
+char* l64a(long n);
+long a64l(char *s);
+
+
+long random(void);
+void srandom(u_int seed);
+char* initstate(u_int seed, char* statebuf, size_t statelen);
+char* setstate(char *statebuf);
+
+
+struct random_data
+{
+ int32_t *fptr;
+ int32_t *rptr;
+ int32_t *state;
+ int rand_type;
+ int rand_deg;
+ int rand_sep;
+ int32_t *end_ptr;
+};
+
+int random_r(struct random_data *buf, int32_t *result);
+int srandom_r(u_int seed, struct random_data *buf);
+int initstate_r(u_int seed, char *statebuf, size_t statelen, struct random_data *buf);
+int setstate_r(char *statebuf, struct random_data *buf);
+int rand(void);
+void srand(u_int seed);
+int rand_r(u_int *seed);
+
+
+/* we dont do big numbers so far...
+
+double drand48(void);
+double erand48(void *ptr);
+
+*/
+
+
+long lrand48(void);
+long nrand48(void *xsubi);
+
+long mrand48(void);
+long jrand48(void *xsubi);
+
+void srand48(long seedval);
+u_int* seed48 (void *seed16v);
+
+void lcong48(void *param);
+
+
+/* no struct arrays so far...
+
+struct drand48_data
+{
+ unsigned short int x[3];
+ unsigned short int old_x[3];
+ unsigned short int c;
+ unsigned short int init;
+ unsigned long long int a;
+};
+
+int drand48_r(struct drand48_data *restrict buffer, double *result);
+int erand48_r(unsigned short int xsubi[3], struct drand48_data *restrict buffer, double *result);
+int lrand48_r(struct drand48_data *restrict buffer, long int *restrict result);
+int nrand48_r(unsigned short int xsubi[3], struct drand48_data *restrict buffer, long int *restrict result);
+int mrand48_r(struct drand48_data *restrict buffer, long int *restrict result);
+int jrand48_r(unsigned short int xsubi[3], struct drand48_data *restrict buffer, long int *restrict result);
+int srand48_r(long int seedval, struct drand48_data *buffer);
+int seed48_r(unsigned short int seed16v[3], struct drand48_data *buffer);
+int lcong48_r(unsigned short int param[7], struct drand48_data *buffer);
+
+*/
+
+
+void* malloc(size_t size);
+void* calloc(size_t nmemb, size_t size);
+void* realloc(void *ptr, size_t size);
+void free(void *ptr);
+void cfree(void *ptr);
+void* valloc(size_t size);
+
+
+int posix_memalign(void *memptr, size_t alignment, size_t size);
+void abort(void);
+int atexit(void *func);
+int on_exit(void *func, void *arg);
+void exit(int status);
+void _Exit(int status);
+char* getenv(char *name);
+char* secure_getenv (char *name);
+int putenv(char *string);
+int setenv(char *name, char *value, int replace);
+int unsetenv(char *name);
+int clearenv(void);
+
+
+char* mktemp(char *template);
+int mkstemp(char *template);
+int mkstemp64(char *template);
+char* mkdtemp(char *template);
+int mkostemp(char *template, int flags);
+int mkostemp64(char *template, int flags);
+
+
+int system(char *command);
+char* canonicalize_file_name(char *name);
+char* realpath(char *name, char *resolved);
+
+
+void* bsearch(void *key, void *base, size_t nmemb, size_t size, void *compar);
+void qsort(void *base, size_t nmemb, size_t size, void *compar);
+
+
+int abs(int x);
+long labs(long x);
+
+
+struct div_t
+{
+ int quot;
+ int rem;
+};
+
+struct ldiv_t
+{
+ long quot;
+ long rem;
+};
+
+struct div_t div(int numer, int denom);
+struct ldiv_t ldiv(long numer, long denom);
+
+
+/* we dont do big numbers so far...
+
+long long int llabs (long long int x);
+
+struct lldiv_t {
+ long long int quot;
+ long long int rem;
+};
+
+lldiv_t lldiv(long long int numer, long long int denom);
+char* ecvt(double value, int ndigit, int *decpt, int *sign);
+char* fcvt(double value, int ndigit, int *decpt, int *sign);
+char* gcvt(double value, int ndigit, char *buf);
+char* qecvt(long double value, int ndigit, int *decpt, int *sign);
+char* qfcvt(long double value, int ndigit, int *decpt, int *sign);
+char* qgcvt(long double value, int ndigit, char *buf);
+int ecvt_r(double value, int ndigit, int *decpt, int *sign, char *buf, size_t len);
+int fcvt_r(double value, int ndigit, int *decpt, int *sign, char *buf, size_t len);
+int qecvt_r(long double value, int ndigit, int *decpt, int *sign, char *buf, size_t len);
+int qfcvt_r(long double value, int ndigit, int *decpt, int *sign, char *buf, size_t len);
+
+*/
+
+
+typedef char wchar_t;
+
+int mblen(char *s, size_t n);
+int mbtowc(wchar_t *pwc, char *s, size_t n);
+int wctomb(char *s, wchar_t wchar);
+size_t mbstowcs(wchar_t *pwcs, char *s, size_t n);
+size_t wcstombs(char *s, wchar_t *pwcs, size_t n);
+
+
+int rpmatch(char *response);
+int getsubopt(void *optionp, void *tokens, void *valuep);
+void setkey(char *key);
+int posix_openpt(int oflag);
+int grantpt(int fd);
+int unlockpt(int fd);
+char* ptsname(int fd);
+int ptsname_r(int fd, char *buf, size_t buflen);
+int getpt(void);
+int getloadavg(void *ptr, int nelem);
+void __cxa_finalize(void *ptr);
diff --git a/etc/latrace.d/string.conf b/etc/latrace.d/string.conf
new file mode 100644
index 0000000..1a31096
--- /dev/null
+++ b/etc/latrace.d/string.conf
@@ -0,0 +1,85 @@
+
+/* /usr/include/string.h */
+
+
+void* memcpy(void *dest, void *src, size_t n);
+void* memmove(void *dest, void *src, size_t n);
+void* memccpy(void *dest, void *src, int c, size_t n);
+void* memset(void *s, int c, size_t n);
+int memcmp(void *s1, void *s2, size_t n);
+void* memchr(void *s, int c, size_t n);
+void* rawmemchr(void *s, int c);
+void* memrchr(void *s, int c, size_t n);
+
+
+char* strcpy(char *dest, char *src);
+char* strncpy(char *dest, char *src, size_t n);
+char* strcat(char *dest, char *src);
+char* strncat(char *dest, char *src, size_t n);
+int strcmp(char *s1, char *s2);
+int strncmp(char *s1, char *s2, size_t n);
+int strcoll(char *s1, char *s2);
+size_t strxfrm(char *dest, char *src, size_t n);
+
+
+int strcoll_l(char *s1, char *s2, __locale_t l);
+size_t strxfrm_l(char *dest, char *src, size_t n, __locale_t l);
+
+
+char* strdup(char *s);
+char* strndup(char *string, size_t n);
+char* strchr(char *s, int c);
+char* strrchr(char *s, int c);
+char* strchrnul(char *s, int c);
+size_t strcspn(char *s, char *reject);
+size_t strspn(char *s, char *accept);
+char* strpbrk(char *s, char *accept);
+char* strstr(char *haystack, char *needle);
+char* strtok(char *s, char *delim);
+char* __strtok_r(char *s, char *delim, void *save_ptr);
+char* strtok_r(char *s, char *delim, void *save_ptr);
+
+
+char* strcasestr(char *haystack, char *needle);
+void* memmem(void *haystack, size_t haystacklen, void *needle, size_t needlelen);
+void* __mempcpy(void *dest, void *src, size_t n);
+void* mempcpy(void *dest, void *src, size_t n);
+size_t strlen(char *s);
+size_t strnlen(char *string, size_t maxlen);
+char* strerror(int errnum);
+
+
+int __xpg_strerror_r(int errnum, char *buf, size_t buflen);
+char* strerror_r(int errnum, char *buf, size_t buflen);
+char* strerror_l(int errnum, __locale_t l);
+void __bzero(void *s, size_t n);
+void bcopy(void *src, void *dest, size_t n);
+void bzero(void *s, size_t n);
+int bcmp(void *s1, void *s2, size_t n);
+char* index(char *s, int c);
+char* rindex(char *s, int c);
+
+int ffs(int i);
+int ffsl(long l);
+
+/* we dont do big numbers so far
+
+__extension__ extern int ffsll (long long int __ll)
+
+*/
+
+
+int strcasecmp(char *s1, char *s2);
+int strncasecmp(char *s1, char *s2, size_t n);
+int strcasecmp_l(char *s1, char *s2, __locale_t loc);
+int strncasecmp_l(char *s1, char *s2, size_t n, __locale_t loc);
+char* strsep(void *stringp, char *delim);
+int strverscmp(char *s1, char *s2);
+char* strsignal(int sig);
+char* __stpcpy(char *dest, char *src);
+char* stpcpy(char *dest, char *src);
+char* __stpncpy(char *dest, char *src, size_t n);
+char* stpncpy(char *dest, char *src, size_t n);
+char* strfry(char *string);
+void* memfrob(void *s, size_t n);
+char* basename(char *filename);
diff --git a/etc/latrace.d/syslog.conf b/etc/latrace.d/syslog.conf
new file mode 100644
index 0000000..7869b09
--- /dev/null
+++ b/etc/latrace.d/syslog.conf
@@ -0,0 +1,8 @@
+
+/* /usr/include/sys/syslog.h */
+
+void closelog();
+void openlog(char *ident, int option, int facility);
+int setlogmask(int mask);
+void syslog(int pri, char *fmt);
+void vsyslog(int pri, char *fmt);
diff --git a/etc/latrace.d/term.conf b/etc/latrace.d/term.conf
new file mode 100644
index 0000000..46f2d0a
--- /dev/null
+++ b/etc/latrace.d/term.conf
@@ -0,0 +1,40 @@
+
+/* /usr/include/term.h */
+
+
+typedef void TTY;
+typedef void TERMTYPE;
+typedef void TERMINAL;
+
+
+int _nc_set_tty_mode(TTY *buf);
+int _nc_get_tty_mode(TTY *buf);
+int _nc_read_entry(char *a, char *b, TERMTYPE *c);
+int _nc_read_file_entry (char *a, TERMTYPE *b);
+int _nc_read_termtype (TERMTYPE *a, char *b, int c);
+char* _nc_first_name(char *a);
+int _nc_name_match(char *a, char *b, char *c);
+
+
+TERMINAL* set_curterm(TERMINAL *t);
+int del_curterm(TERMINAL *t);
+
+
+int restartterm(char *a, int b, int *c);
+int setupterm (char *a, int b, int *c);
+char* tigetstr(char *a);
+int putp(char *s);
+int tigetflag(char *a);
+int tigetnum(char *a);
+
+
+char* tparm(char *s);
+char* tparm_varargs(char *s);
+
+
+char* tgetstr(char *s, void *a);
+char* tgoto(char *s, int a, int b);
+int tgetent(char *s, char *a);
+int tgetflag(char *s);
+int tgetnum(char *s);
+int tputs(char *s, int a, void *f);
diff --git a/etc/latrace.d/termios.conf b/etc/latrace.d/termios.conf
new file mode 100644
index 0000000..46fcd85
--- /dev/null
+++ b/etc/latrace.d/termios.conf
@@ -0,0 +1,28 @@
+
+/* /usr/include/termios.h */
+
+typedef u_char cc_t;
+typedef u_int speed_t;
+typedef u_int tcflag_t;
+typedef void termios;
+
+
+speed_t cfgetospeed(termios *termios_p);
+speed_t cfgetispeed(termios *termios_p);
+
+
+int cfsetospeed(termios *termios_p, speed_t speed);
+int cfsetispeed(termios *termios_p, speed_t speed);
+int cfsetspeed(termios *termios_p, speed_t speed);
+
+
+int tcgetattr(int fd, termios *termios_p);
+int tcsetattr(int fd, int optional_actions, termios *termios_p);
+
+
+void cfmakeraw(termios *termios_p);
+int tcsendbreak(int fd, int duration);
+int tcdrain(int fd);
+int tcflush(int fd, int queue_selector);
+int tcflow(int fd, int action);
+__pid_t tcgetsid(int fd);
diff --git a/etc/latrace.d/time.conf b/etc/latrace.d/time.conf
new file mode 100644
index 0000000..739e6b5
--- /dev/null
+++ b/etc/latrace.d/time.conf
@@ -0,0 +1,65 @@
+
+/* /usr/include/time.h */
+
+
+typedef u_int time_t;
+typedef u_int clockid_t;
+typedef void tm;
+typedef void timespec;
+typedef void timer_t;
+typedef void itimerspec;
+
+
+time_t time(time_t *timer);
+
+
+double difftime(time_t time1, time_t time0);
+
+
+time_t mktime(tm *tp);
+
+
+size_t strftime(char *s, size_t maxsize, char *format, tm *tp);
+char* strptime(char *s, char *fmt, tm *tp);
+size_t strftime_l(char *s, size_t maxsize, char *format, tm *tp, __locale_t __loc);
+char* strptime_l(char *s, char *fmt, tm *tp, __locale_t __loc);
+
+
+tm* gmtime(time_t *timer);
+tm* localtime(time_t *timer);
+tm* gmtime_r(time_t *timer, tm *tp);
+tm* localtime_r(time_t *timer, tm *tp);
+
+
+char* asctime(tm *tp);
+char* ctime(time_t *timer);
+char* asctime_r(tm *tp, char *buf);
+char* ctime_r(time_t *timer, char *buf);
+
+
+void tzset();
+int dysize(int year);
+int nanosleep(timespec *requested_time, timespec *remaining);
+
+
+int stime(time_t *when);
+time_t timegm(tm *tp);
+time_t timelocal(tm *tp);
+
+
+int clock_getres(clockid_t clock_id, timespec *res);
+int clock_gettime(clockid_t clock_id, timespec *tp);
+int clock_settime(clockid_t clock_id, timespec *tp);
+int clock_nanosleep(clockid_t clock_id, int flags, timespec *req, timespec *rem);
+int clock_getcpuclockid(pid_t pid, clockid_t *clock_id);
+
+
+int timer_create(clockid_t clock_id, void *evp, timer_t *timerid);
+int timer_delete(timer_t *timerid);
+int timer_settime(timer_t timerid, int flags, itimerspec *value, itimerspec *ovalue);
+int timer_gettime(timer_t timerid, itimerspec *value);
+int timer_getoverrun(timer_t timerid);
+
+
+tm* getdate(char *string);
+int getdate_r(char *string, tm *resbufp);
diff --git a/etc/latrace.d/typedefs.conf b/etc/latrace.d/typedefs.conf
new file mode 100644
index 0000000..cb8adc0
--- /dev/null
+++ b/etc/latrace.d/typedefs.conf
@@ -0,0 +1,27 @@
+
+/* misc typedefs */
+
+typedef int __locale_t;
+
+typedef int int32_t;
+typedef u_int uint32_t;
+typedef uint32_t in_addr_t;
+
+typedef int socklen_t;
+typedef int size_t;
+
+typedef void FILE;
+typedef void DIR;
+typedef long __off_t;
+typedef void fpos_t;
+
+typedef u_int __uid_t;
+typedef u_int uid_t;
+typedef u_int __gid_t;
+typedef u_int gid_t;
+typedef u_int __pid_t;
+typedef u_int pid_t;
+typedef u_int __mode_t;
+typedef u_int mode_t;
+typedef u_short __dev_t;
+typedef u_short dev_t;
diff --git a/etc/latrace.d/unistd.conf b/etc/latrace.d/unistd.conf
new file mode 100644
index 0000000..d7171b3
--- /dev/null
+++ b/etc/latrace.d/unistd.conf
@@ -0,0 +1,170 @@
+
+/* /usr/include/unistd.h */
+
+
+int access(char *name, int type);
+int euidaccess(char *name, int type);
+int eaccess(char *name, int type);
+int faccessat(int fd, char *file, int type, int flag);
+
+
+__off_t lseek(int fd, __off_t offset, int whence);
+__off64_t lseek64(int fd, __off64_t offset, int whence);
+
+
+int close(int fd);
+size_t read(int fd, void *buf, size_t nbytes);
+size_t write(int fd, void *buf, size_t n);
+size_t pread(int fd, void *buf, size_t nbytes, __off_t offset);
+size_t pwrite(int fd, void *buf, size_t n, __off_t offset);
+size_t pread64(int fd, void *buf, size_t nbytes, __off64_t offset);
+size_t pwrite64(int fd, void *buf, size_t n, __off64_t offset);
+
+
+int pipe(void *pipe);
+u_int alarm(u_int seconds);
+u_int sleep(u_int seconds);
+u_int ualarm(u_int __value, u_int interval);
+int usleep(u_int useconds);
+int pause();
+
+
+int chown(char *file, __uid_t owner, __gid_t group);
+int fchown(int fd, __uid_t owner, __gid_t group);
+int lchown(char *file, __uid_t owner, __gid_t group);
+int fchownat(int fd, char *file, __uid_t owner, __gid_t group, int flag);
+int chdir(char *path);
+int fchdir(int fd);
+char* getcwd(char *buf, size_t size);
+
+
+char* get_current_dir_name();
+char* getwd(char *buf);
+
+
+int dup(int fd);
+int dup2(int fd, int fd2);
+
+
+int execve(char *path, void *argv, void *envp);
+int fexecve(int fd, void *argv, void *envp);
+int execv(char *path, void *argv);
+int execle(char *path, char *arg);
+int execl(char *path, char *arg);
+int execvp(char *file, void *argv);
+int execlp(char *file, char *arg);
+
+
+int nice(int inc);
+void _exit(int status);
+long pathconf(char *path, int name);
+long fpathconf(int fd, int name);
+long sysconf(int name);
+size_t confstr(int name, char *buf, size_t len);
+
+
+__pid_t getpid();
+__pid_t getppid();
+__pid_t getpgrp();
+__pid_t __getpgid(__pid_t pid);
+__pid_t getpgid(__pid_t pid);
+int setpgid(__pid_t pid, __pid_t pgid);
+int setpgrp();
+__pid_t setsid();
+__pid_t getsid(__pid_t pid);
+__uid_t getuid();
+__uid_t geteuid();
+__gid_t getgid();
+__gid_t getegid();
+
+
+int getgroups(int size, void *list);
+int group_member(__gid_t gid);
+int setuid(__uid_t uid);
+int setreuid(__uid_t ruid, __uid_t euid);
+int seteuid(__uid_t uid);
+int setgid(__gid_t gid);
+int setregid(__gid_t rgid, __gid_t egid);
+int setegid(__gid_t gid);
+int getresuid(__uid_t *ruid, __uid_t *euid, __uid_t *suid);
+int getresgid(__gid_t *rgid, __gid_t *egid, __gid_t *sgid);
+int setresuid(__uid_t ruid, __uid_t euid, __uid_t suid);
+int setresgid(__gid_t rgid, __gid_t egid, __gid_t sgid);
+
+
+__pid_t fork();
+__pid_t vfork();
+
+
+char* ttyname(int fd);
+int ttyname_r(int fd, char *buf, size_t buflen);
+int isatty(int fd);
+int ttyslot();
+
+
+int link(char *from, char *to);
+int linkat(int fromfd, char *from, int tofd, char *to, int flags);
+int symlink(char *from, char *to);
+size_t readlink(char *path, char *buf, size_t len);
+int symlinkat(char *from, int tofd, char *to);
+size_t readlinkat(int fd, char *path, char *buf, size_t len);
+int unlink(char *name);
+int unlinkat(int fd, char *name, int flag);
+int rmdir(char *path);
+
+
+__pid_t tcgetpgrp(int fd);
+int tcsetpgrp(int fd, __pid_t pgrp_id);
+char* getlogin();
+int getlogin_r(char *name, size_t name_len);
+int setlogin(char *name);
+
+
+int gethostname(char *name, size_t len);
+int sethostname(char *name, size_t len);
+int sethostid(long id);
+int getdomainname(char *name, size_t len);
+int setdomainname(char *name, size_t len);
+
+
+int vhangup();
+int revoke(char *file);
+int profil(u_short *sample_buffer, size_t __size, size_t offset, u_int scale);
+int acct(char *name);
+
+
+char *getusershell();
+void endusershell();
+void setusershell();
+
+
+int daemon(int nochdir, int noclose);
+int chroot(char *path);
+char* getpass(char *prompt);
+int fsync(int fd);
+long gethostid();
+void sync();
+int getpagesize();
+int getdtablesize();
+
+
+int truncate(char *file, __off_t length);
+int truncate64(char *file, __off64_t length);
+int ftruncate(int fd, __off_t length);
+int ftruncate64(int fd, __off64_t length);
+
+
+int brk(void *addr);
+void* sbrk(u_int delta);
+long syscall(long sysno = SYSCALL_NO);
+
+int lockf(int fd, int cmd, __off_t len);
+int lockf64(int fd, int cmd, __off64_t len);
+int fdatasync(int fildes);
+
+
+char* crypt(char *key, char *salt);
+void encrypt(char *block, int edflag);
+
+void swab(void *from, void *to, size_t n);
+char* ctermid(char* s);
diff --git a/etc/latrace.d/utmp.conf b/etc/latrace.d/utmp.conf
new file mode 100644
index 0000000..fb333eb
--- /dev/null
+++ b/etc/latrace.d/utmp.conf
@@ -0,0 +1,30 @@
+
+/* /usr/include/utmp.h */
+
+
+typedef void utmp;
+
+
+int login_tty(int fd);
+void login(utmp *entry);
+int logout(char *ut_line);
+
+
+void logwtmp(char *ut_line, char *ut_name, char *ut_host);
+void updwtmp(char *wtmp_file, utmp *utmp);
+
+
+int utmpname(char *file);
+
+
+utmp* getutent();
+void setutent();
+void endutent();
+utmp* getutid(utmp *id);
+
+
+utmp* getutline(utmp *line);
+utmp* pututline(utmp *utmp_ptr);
+int getutent_r(utmp *buffer, void *result);
+int getutid_r(utmp *id, utmp *buffer, void *result);
+int getutline_r(utmp *line, utmp *buffer, void *result);
diff --git a/etc/latrace.d/wait.conf b/etc/latrace.d/wait.conf
new file mode 100644
index 0000000..427b38d
--- /dev/null
+++ b/etc/latrace.d/wait.conf
@@ -0,0 +1,18 @@
+
+/* /usr/include/sys/wait.h */
+
+
+typedef u_int __WAIT_STATUS;
+typedef u_int idtype_t;
+typedef u_int __id_t;
+
+
+__pid_t wait(__WAIT_STATUS stat_loc);
+__pid_t waitpid(__pid_t pid, int *stat_loc, int options);
+
+
+int waitid(idtype_t idtype, __id_t id, void *infop, int options);
+
+
+__pid_t wait3(__WAIT_STATUS stat_loc, int options, void *usage);
+__pid_t wait4(__pid_t pid, __WAIT_STATUS stat_loc, int options, void *usage);
diff --git a/etc/sysdeps/x86_64/syscall.conf b/etc/sysdeps/x86_64/syscall.conf
new file mode 100644
index 0000000..d655f85
--- /dev/null
+++ b/etc/sysdeps/x86_64/syscall.conf
@@ -0,0 +1,303 @@
+
+/* /usr/include/bits/syscall.h */
+
+enum SYSCALL_NO {
+ SYS_read = 0,
+ SYS_write = 1,
+ SYS_open = 2,
+ SYS_close = 3,
+ SYS_stat = 4,
+ SYS_fstat = 5,
+ SYS_lstat = 6,
+ SYS_poll = 7,
+ SYS_lseek = 8,
+ SYS_mmap = 9,
+ SYS_mprotect = 10,
+ SYS_munmap = 11,
+ SYS_brk = 12,
+ SYS_rt_sigaction = 13,
+ SYS_rt_sigprocmask = 14,
+ SYS_rt_sigreturn = 15,
+ SYS_ioctl = 16,
+ SYS_pread64 = 17,
+ SYS_pwrite64 = 18,
+ SYS_readv = 19,
+ SYS_writev = 20,
+ SYS_access = 21,
+ SYS_pipe = 22,
+ SYS_select = 23,
+ SYS_sched_yield = 24,
+ SYS_mremap = 25,
+ SYS_msync = 26,
+ SYS_mincore = 27,
+ SYS_madvise = 28,
+ SYS_shmget = 29,
+ SYS_shmat = 30,
+ SYS_shmctl = 31,
+ SYS_dup = 32,
+ SYS_dup2 = 33,
+ SYS_pause = 34,
+ SYS_nanosleep = 35,
+ SYS_getitimer = 36,
+ SYS_alarm = 37,
+ SYS_setitimer = 38,
+ SYS_getpid = 39,
+ SYS_sendfile = 40,
+ SYS_socket = 41,
+ SYS_connect = 42,
+ SYS_accept = 43,
+ SYS_sendto = 44,
+ SYS_recvfrom = 45,
+ SYS_sendmsg = 46,
+ SYS_recvmsg = 47,
+ SYS_shutdown = 48,
+ SYS_bind = 49,
+ SYS_listen = 50,
+ SYS_getsockname = 51,
+ SYS_getpeername = 52,
+ SYS_socketpair = 53,
+ SYS_setsockopt = 54,
+ SYS_getsockopt = 55,
+ SYS_clone = 56,
+ SYS_fork = 57,
+ SYS_vfork = 58,
+ SYS_execve = 59,
+ SYS_exit = 60,
+ SYS_wait4 = 61,
+ SYS_kill = 62,
+ SYS_uname = 63,
+ SYS_semget = 64,
+ SYS_semop = 65,
+ SYS_semctl = 66,
+ SYS_shmdt = 67,
+ SYS_msgget = 68,
+ SYS_msgsnd = 69,
+ SYS_msgrcv = 70,
+ SYS_msgctl = 71,
+ SYS_fcntl = 72,
+ SYS_flock = 73,
+ SYS_fsync = 74,
+ SYS_fdatasync = 75,
+ SYS_truncate = 76,
+ SYS_ftruncate = 77,
+ SYS_getdents = 78,
+ SYS_getcwd = 79,
+ SYS_chdir = 80,
+ SYS_fchdir = 81,
+ SYS_rename = 82,
+ SYS_mkdir = 83,
+ SYS_rmdir = 84,
+ SYS_creat = 85,
+ SYS_link = 86,
+ SYS_unlink = 87,
+ SYS_symlink = 88,
+ SYS_readlink = 89,
+ SYS_chmod = 90,
+ SYS_fchmod = 91,
+ SYS_chown = 92,
+ SYS_fchown = 93,
+ SYS_lchown = 94,
+ SYS_umask = 95,
+ SYS_gettimeofday = 96,
+ SYS_getrlimit = 97,
+ SYS_getrusage = 98,
+ SYS_sysinfo = 99,
+ SYS_times = 100,
+ SYS_ptrace = 101,
+ SYS_getuid = 102,
+ SYS_syslog = 103,
+ SYS_getgid = 104,
+ SYS_setuid = 105,
+ SYS_setgid = 106,
+ SYS_geteuid = 107,
+ SYS_getegid = 108,
+ SYS_setpgid = 109,
+ SYS_getppid = 110,
+ SYS_getpgrp = 111,
+ SYS_setsid = 112,
+ SYS_setreuid = 113,
+ SYS_setregid = 114,
+ SYS_getgroups = 115,
+ SYS_setgroups = 116,
+ SYS_setresuid = 117,
+ SYS_getresuid = 118,
+ SYS_setresgid = 119,
+ SYS_getresgid = 120,
+ SYS_getpgid = 121,
+ SYS_setfsuid = 122,
+ SYS_setfsgid = 123,
+ SYS_getsid = 124,
+ SYS_capget = 125,
+ SYS_capset = 126,
+ SYS_rt_sigpending = 127,
+ SYS_rt_sigtimedwait = 128,
+ SYS_rt_sigqueueinfo = 129,
+ SYS_rt_sigsuspend = 130,
+ SYS_sigaltstack = 131,
+ SYS_utime = 132,
+ SYS_mknod = 133,
+ SYS_uselib = 134,
+ SYS_personality = 135,
+ SYS_ustat = 136,
+ SYS_statfs = 137,
+ SYS_fstatfs = 138,
+ SYS_sysfs = 139,
+ SYS_getpriority = 140,
+ SYS_setpriority = 141,
+ SYS_sched_setparam = 142,
+ SYS_sched_getparam = 143,
+ SYS_sched_setscheduler = 144,
+ SYS_sched_getscheduler = 145,
+ SYS_sched_get_priority_max = 146,
+ SYS_sched_get_priority_min = 147,
+ SYS_sched_rr_get_interval = 148,
+ SYS_mlock = 149,
+ SYS_munlock = 150,
+ SYS_mlockall = 151,
+ SYS_munlockall = 152,
+ SYS_vhangup = 153,
+ SYS_modify_ldt = 154,
+ SYS_pivot_root = 155,
+ SYS__sysctl = 156,
+ SYS_prctl = 157,
+ SYS_arch_prctl = 158,
+ SYS_adjtimex = 159,
+ SYS_setrlimit = 160,
+ SYS_chroot = 161,
+ SYS_sync = 162,
+ SYS_acct = 163,
+ SYS_settimeofday = 164,
+ SYS_mount = 165,
+ SYS_umount2 = 166,
+ SYS_swapon = 167,
+ SYS_swapoff = 168,
+ SYS_reboot = 169,
+ SYS_sethostname = 170,
+ SYS_setdomainname = 171,
+ SYS_iopl = 172,
+ SYS_ioperm = 173,
+ SYS_create_module = 174,
+ SYS_init_module = 175,
+ SYS_delete_module = 176,
+ SYS_get_kernel_syms = 177,
+ SYS_query_module = 178,
+ SYS_quotactl = 179,
+ SYS_nfsservctl = 180,
+ SYS_getpmsg = 181,
+ SYS_putpmsg = 182,
+ SYS_afs_syscall = 183,
+ SYS_tuxcall = 184,
+ SYS_security = 185,
+ SYS_gettid = 186,
+ SYS_readahead = 187,
+ SYS_setxattr = 188,
+ SYS_lsetxattr = 189,
+ SYS_fsetxattr = 190,
+ SYS_getxattr = 191,
+ SYS_lgetxattr = 192,
+ SYS_fgetxattr = 193,
+ SYS_listxattr = 194,
+ SYS_llistxattr = 195,
+ SYS_flistxattr = 196,
+ SYS_removexattr = 197,
+ SYS_lremovexattr = 198,
+ SYS_fremovexattr = 199,
+ SYS_tkill = 200,
+ SYS_time = 201,
+ SYS_futex = 202,
+ SYS_sched_setaffinity = 203,
+ SYS_sched_getaffinity = 204,
+ SYS_set_thread_area = 205,
+ SYS_io_setup = 206,
+ SYS_io_destroy = 207,
+ SYS_io_getevents = 208,
+ SYS_io_submit = 209,
+ SYS_io_cancel = 210,
+ SYS_get_thread_area = 211,
+ SYS_lookup_dcookie = 212,
+ SYS_epoll_create = 213,
+ SYS_epoll_ctl_old = 214,
+ SYS_epoll_wait_old = 215,
+ SYS_remap_file_pages = 216,
+ SYS_getdents64 = 217,
+ SYS_set_tid_address = 218,
+ SYS_restart_syscall = 219,
+ SYS_semtimedop = 220,
+ SYS_fadvise64 = 221,
+ SYS_timer_create = 222,
+ SYS_timer_settime = 223,
+ SYS_timer_gettime = 224,
+ SYS_timer_getoverrun = 225,
+ SYS_timer_delete = 226,
+ SYS_clock_settime = 227,
+ SYS_clock_gettime = 228,
+ SYS_clock_getres = 229,
+ SYS_clock_nanosleep = 230,
+ SYS_exit_group = 231,
+ SYS_epoll_wait = 232,
+ SYS_epoll_ctl = 233,
+ SYS_tgkill = 234,
+ SYS_utimes = 235,
+ SYS_vserver = 236,
+ SYS_mbind = 237,
+ SYS_set_mempolicy = 238,
+ SYS_get_mempolicy = 239,
+ SYS_mq_open = 240,
+ SYS_mq_unlink = 241,
+ SYS_mq_timedsend = 242,
+ SYS_mq_timedreceive = 243,
+ SYS_mq_notify = 244,
+ SYS_mq_getsetattr = 245,
+ SYS_kexec_load = 246,
+ SYS_waitid = 247,
+ SYS_add_key = 248,
+ SYS_request_key = 249,
+ SYS_keyctl = 250,
+ SYS_ioprio_set = 251,
+ SYS_ioprio_get = 252,
+ SYS_inotify_init = 253,
+ SYS_inotify_add_watch = 254,
+ SYS_inotify_rm_watch = 255,
+ SYS_migrate_pages = 256,
+ SYS_openat = 257,
+ SYS_mkdirat = 258,
+ SYS_mknodat = 259,
+ SYS_fchownat = 260,
+ SYS_futimesat = 261,
+ SYS_newfstatat = 262,
+ SYS_unlinkat = 263,
+ SYS_renameat = 264,
+ SYS_linkat = 265,
+ SYS_symlinkat = 266,
+ SYS_readlinkat = 267,
+ SYS_fchmodat = 268,
+ SYS_faccessat = 269,
+ SYS_pselect6 = 270,
+ SYS_ppoll = 271,
+ SYS_unshare = 272,
+ SYS_set_robust_list = 273,
+ SYS_get_robust_list = 274,
+ SYS_splice = 275,
+ SYS_tee = 276,
+ SYS_sync_file_range = 277,
+ SYS_vmsplice = 278,
+ SYS_move_pages = 279,
+ SYS_utimensat = 280,
+ SYS_epoll_pwait = 281,
+ SYS_signalfd = 282,
+ SYS_timerfd_create = 283,
+ SYS_eventfd = 284,
+ SYS_fallocate = 285,
+ SYS_timerfd_settime = 286,
+ SYS_timerfd_gettime = 287,
+ SYS_accept4 = 288,
+ SYS_signalfd4 = 289,
+ SYS_eventfd2 = 290,
+ SYS_epoll_create1 = 291,
+ SYS_dup3 = 292,
+ SYS_pipe2 = 293,
+ SYS_inotify_init1 = 294,
+ SYS_preadv = 295,
+ SYS_pwritev = 296
+};
+
diff --git a/package/debian/changelog b/package/debian/changelog
new file mode 100644
index 0000000..2264d76
--- /dev/null
+++ b/package/debian/changelog
@@ -0,0 +1,5 @@
+latrace (0.5.3-1) unstable; urgency=low
+
+ * Debian packaging created.
+
+ -- Akos Pasztory <akos.pasztory@gmail.com> Tue, 24 Feb 2009 21:26:14 +0300
diff --git a/package/debian/conffiles b/package/debian/conffiles
new file mode 100644
index 0000000..31e2607
--- /dev/null
+++ b/package/debian/conffiles
@@ -0,0 +1,30 @@
+/etc/latrace.conf
+/etc/latrace.d/ctype.conf
+/etc/latrace.d/dirent.conf
+/etc/latrace.d/dlfcn.conf
+/etc/latrace.d/fcntl.conf
+/etc/latrace.d/getopt.conf
+/etc/latrace.d/inet.conf
+/etc/latrace.d/ioctl.conf
+/etc/latrace.d/libintl.conf
+/etc/latrace.d/libio.conf
+/etc/latrace.d/locale.conf
+/etc/latrace.d/misc.conf
+/etc/latrace.d/ncurses.conf
+/etc/latrace.d/netdb.conf
+/etc/latrace.d/pthread.conf
+/etc/latrace.d/pwd.conf
+/etc/latrace.d/signal.conf
+/etc/latrace.d/socket.conf
+/etc/latrace.d/stat.conf
+/etc/latrace.d/stdio.conf
+/etc/latrace.d/stdlib.conf
+/etc/latrace.d/string.conf
+/etc/latrace.d/syslog.conf
+/etc/latrace.d/term.conf
+/etc/latrace.d/termios.conf
+/etc/latrace.d/time.conf
+/etc/latrace.d/typedefs.conf
+/etc/latrace.d/unistd.conf
+/etc/latrace.d/utmp.conf
+/etc/latrace.d/wait.conf
diff --git a/package/debian/control b/package/debian/control
new file mode 100644
index 0000000..473c3b2
--- /dev/null
+++ b/package/debian/control
@@ -0,0 +1,18 @@
+Source: latrace
+Section: utils
+Priority: optional
+Maintainer: Akos PASZTORY <akos.pasztory@gmail.com>
+Standards-Version: 3.8.0
+Build-Depends: flex, bison, autoconf
+
+Package: latrace
+Architecture: i386 amd64 armel
+Depends: libc6 (>= 2.5) [armel], libc6 (>= 2.7-1) [i386 amd64]
+Description: traces library calls in dynamically linked programs
+ latrace (similar to ltrace) displays dynamic library calls of a program
+ using the LD_AUDIT feature of newer glibc versions. It is also capable to
+ measure and display various statistics of dynamic calls. If a config file
+ is provided, latrace will display function arguments with detailed output
+ for structures.
+ .
+ See also http://latrace.sourceforge.net/
diff --git a/package/debian/copyright b/package/debian/copyright
new file mode 100644
index 0000000..405f8e8
--- /dev/null
+++ b/package/debian/copyright
@@ -0,0 +1,21 @@
+This package is derived from sources obtained at:
+ http://latrace.sourceforge.net
+Debian packaging by Akos PASZTORY <akos.pasztory@gmail.com>.
+
+Copyright (c) 2008, 2009 Jiri Olsa <olsajiri@gmail.com>
+
+ 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 3 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, see <http://www.gnu.org/licenses/>.
+
+Under Debian systems /usr/share/common-licenses/GPL-3
+contains the full text of the license.
diff --git a/package/debian/rules b/package/debian/rules
new file mode 100644
index 0000000..0295e77
--- /dev/null
+++ b/package/debian/rules
@@ -0,0 +1,47 @@
+#!/usr/bin/make -f
+
+.PHONY: build clean binary-arch binary-indep binary default
+
+pkg := latrace
+pkgdir := debian/$(pkg)
+docdir := $(pkgdir)/usr/share/doc/$(pkg)
+checkdir = @test -e debian/control || ! echo wrong directory
+checkuid = @test "`id -u`" -eq 0 || ! echo need root permissions
+
+default:
+build: debian/stamp-build
+debian/stamp-build:
+ $(checkdir)
+ autoconf
+ ./configure --prefix=/usr --sysconfdir=/etc --libdir=/usr/lib/latrace
+ make
+ touch $@
+clean:
+ $(checkdir)
+ $(checkuid)
+ rm -f debian/stamp-*
+ test ! -f src/autoconf.make || make mrproper
+ rm -rf debian/latrace
+ rm -f debian/files debian/substvars
+binary-indep:
+binary-arch: debian/stamp-build
+ $(checkdir)
+ $(checkuid)
+ install -d $(pkgdir)/DEBIAN $(docdir)
+ make install ROOTDIR="$(CURDIR)/$(pkgdir)"
+ cd $(pkgdir) && strip --strip-unneeded -R .note -R .comment \
+ usr/bin/latrace usr/lib/latrace/libltaudit.so
+ cp -p ChangeLog $(docdir)/changelog
+ cp -p README ReleaseNotes TODO debian/copyright $(docdir)
+ cp -p debian/changelog $(docdir)/changelog.Debian
+ cp -p debian/conffiles $(pkgdir)/DEBIAN
+ gzip -9f $(pkgdir)/usr/share/man/man1/latrace.1
+ gzip -9f $(docdir)/changelog $(docdir)/changelog.Debian
+ dpkg-shlibdeps $(pkgdir)/usr/bin/latrace
+ dpkg-gencontrol -P$(pkgdir)
+ cd $(pkgdir) && find * -path DEBIAN -prune -o -type f -print0 | \
+ xargs -r0 md5sum > DEBIAN/md5sums
+ chown -R root:root $(pkgdir)
+ chmod -R u+w,go=rX $(pkgdir)
+ dpkg-deb -b $(pkgdir) ..
+binary: binary-arch binary-indep
diff --git a/package/rpm/latrace.spec b/package/rpm/latrace.spec
new file mode 100644
index 0000000..2234f1b
--- /dev/null
+++ b/package/rpm/latrace.spec
@@ -0,0 +1,52 @@
+Name: latrace
+Version: 0.5.6
+Release: 1%{?dist}
+Summary: LD_AUDIT feature frontend for glibc 2.4+
+Group: Development/Debuggers
+License: GPLv3+
+BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root
+URL: http://latrace.sourceforge.net/
+Source: http://downloads.sourceforge.net/latrace/%{name}-%{version}.tar.bz2
+ExclusiveArch: %{ix86} x86_64 arm
+BuildRequires: autoconf bison asciidoc xmlto
+
+%description
+allows you to trace library calls and get their statistics in a
+manner similar to the strace utility (syscall tracing)
+
+%prep
+%setup -q
+
+%build
+autoconf
+%configure
+make V=1
+
+%install
+rm -rf %{buildroot}
+make install ROOTDIR=%{buildroot} V=1
+
+%post -p /sbin/ldconfig
+
+%postun -p /sbin/ldconfig
+
+%clean
+rm -rf %{buildroot}
+
+%files
+%defattr(-,root,root,-)
+%doc README ReleaseNotes TODO COPYING
+%config(noreplace) %{_sysconfdir}/*
+%{_libdir}/libltaudit.so.%{version}
+%{_bindir}/latrace
+%{_mandir}/man1/*
+
+%changelog
+* Sun Jul 05 2009 Jiri Olsa <olsajiri@gmail.com> 0.5.6-1
+- updates based on the Fedora review comments
+
+* Thu Jul 02 2009 Jiri Olsa <olsajiri@gmail.com> 0.5.5-2
+- minor updates based on the Fedora review comments
+
+* Sat Jun 13 2009 Jiri Olsa <olsajiri@gmail.com> 0.5.5-1
+- initial spec file
diff --git a/src/Makefile b/src/Makefile
new file mode 100644
index 0000000..93f01ad
--- /dev/null
+++ b/src/Makefile
@@ -0,0 +1,67 @@
+# Copyright (C) 2008, 2009 Jiri Olsa <olsajiri@gmail.com>
+#
+# This file is part of the latrace.
+#
+# The latrace 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 3 of the License, or
+# (at your option) any later version.
+#
+# The latrace 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 the latrace (file COPYING). If not, see
+# <http://www.gnu.org/licenses/>.
+
+
+# libltaudit.so
+AUDIT_BIN=libltaudit.so.$(LT_VER)
+AUDIT_LDFLAGS="-Wl,-init=audit_init" "-Wl,-soname,$(AUDIT_BIN)" -fPIC -shared
+AUDIT_LIBS=-liberty
+AUDIT_OBJS=\
+ src/audit.o \
+ src/audit-init.o \
+ src/fifo.o \
+ src/args-bison.o \
+ src/args-flex.o \
+ src/args.o \
+ src/output.o \
+ src/objsearch.o \
+ src/sysdeps/$(CONFIG_SYSDEP_DIR)/stack.o
+
+OBJS+=$(AUDIT_OBJS)
+PROGRAMS+= $(AUDIT_BIN)
+
+$(AUDIT_BIN): $(AUDIT_OBJS)
+ $(QUIET_LD)$(CC) $(AUDIT_LDFLAGS) -o $@ $(AUDIT_OBJS) $(AUDIT_LIBS)
+
+install::
+ $(call install,$(AUDIT_BIN),$(libdir),755)
+
+# latrace binary
+LATRACE_BIN=latrace
+LATRACE_LIB=-liberty
+LATRACE_OBJS=\
+ src/latrace.o \
+ src/config.o \
+ src/run.o \
+ src/stats.o \
+ src/fifo.o \
+ src/thread.o \
+ src/output.o
+
+OBJS+=$(LATRACE_OBJS)
+PROGRAMS+=$(LATRACE_BIN)
+CPPFLAGS+=-DCONFIG_LIBDIR=\"$(libdir)\"
+CPPFLAGS+=-DLT_ARGS_DEF_DIR=\"$(confdir)\"
+CPPFLAGS+=-DLT_ARGS_DEF_CONF=\"$(sysconfdir)/latrace.conf\"
+
+$(LATRACE_BIN): $(LATRACE_OBJS)
+ $(QUIET_LD)$(CC) $(LDFLAGS) -o $@ $(LATRACE_OBJS) $(LATRACE_LIBS) $(LATRACE_LIB)
+
+install::
+ $(call install,$(LATRACE_BIN),$(bindir),755)
+
diff --git a/src/args-bison.y b/src/args-bison.y
new file mode 100644
index 0000000..64c88be
--- /dev/null
+++ b/src/args-bison.y
@@ -0,0 +1,302 @@
+/*
+ Copyright (C) 2008, 2009 Jiri Olsa <olsajiri@gmail.com>
+
+ This file is part of the latrace.
+
+ The latrace 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 3 of the License, or
+ (at your option) any later version.
+
+ The latrace 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 the latrace (file COPYING). If not, see
+ <http://www.gnu.org/licenses/>.
+*/
+
+
+%{
+
+#define YYERROR_VERBOSE 1
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "config.h"
+
+int yylex (void);
+void yyerror(const char *m);
+
+static struct lt_config_shared *scfg;
+static int struct_alive = 0;
+
+#define ERROR(fmt, args...) \
+do { \
+ char ebuf[1024]; \
+ sprintf(ebuf, fmt, ## args); \
+ yyerror(ebuf); \
+ YYERROR; \
+} while(0)
+
+#define CHK_TYPEDEF(ret, base, new, pointer) \
+do { \
+ switch(ret) { \
+ case -1: \
+ ERROR("unknown typedef - %s%s%s\n", base, (pointer ? "* " : " "), new); \
+ break; \
+ case 1: \
+ ERROR("typedef alrady defined - %s%s%s\n", base, (pointer ? "* " : " "), new); \
+ break; \
+ case 2: \
+ ERROR("typedef limit reached(%d) - %s%s%s\n", \
+ LT_ARGS_DEF_TYPEDEF_NUM, base, (pointer ? "* " : " "), new); \
+ break; \
+ }; \
+} while(0)
+
+#define GET_LIST_HEAD(head) \
+do { \
+ if (NULL == (head = (struct lt_list_head*) malloc(sizeof(*head)))) \
+ ERROR("failed to allocate list head"); \
+ lt_init_list_head(head); \
+} while(0)
+
+%}
+
+%token NAME FILENAME STRUCT ENUM TYPEDEF INCLUDE END POINTER
+
+%union
+{
+ char *s;
+ struct lt_arg *arg;
+ struct lt_enum_elem *enum_elem;
+ struct lt_list_head *head;
+}
+
+%type <s> NAME
+%type <s> FILENAME
+%type <head> STRUCT_DEF
+%type <head> ENUM_DEF
+%type <s> ENUM_REF
+%type <enum_elem> ENUM_ELEM
+%type <head> ARGS
+%type <arg> DEF
+
+%%
+entry:
+entry struct_def
+|
+entry enum_def
+|
+entry func_def
+|
+entry type_def
+|
+entry include_def
+|
+entry END
+{
+ if (lt_args_buf_close(scfg))
+ return 0;
+}
+|
+/* left blank intentionally */
+
+/* struct definitions */
+struct_def:
+STRUCT NAME '{' STRUCT_DEF '}' ';'
+{
+ switch(lt_args_add_struct(scfg, $2, $4)) {
+ case -1:
+ ERROR("failed to add struct %s\n", $2);
+ case 1:
+ ERROR("struct limit reached(%d) - %s\n", LT_ARGS_DEF_STRUCT_NUM, $2);
+ };
+
+ /* force creation of the new list head */
+ struct_alive = 0;
+}
+
+STRUCT_DEF:
+STRUCT_DEF DEF ';'
+{
+ struct lt_arg *def = $2;
+ struct lt_list_head *h = $1;
+
+ if (!struct_alive++)
+ GET_LIST_HEAD(h);
+
+ lt_list_add_tail(&def->args_list, h);
+ $$ = h;
+}
+| /* left blank intentionally,
+ XXX this could be done like the args_def, but user needs to be
+ able to create an empty structure, so thats why we play
+ with the global struct_alive thingie...
+ there could be better way probably */
+{
+}
+
+/* enum definitions */
+enum_def:
+ENUM NAME '{' ENUM_DEF '}' ';'
+{
+ switch(lt_args_add_enum(scfg, $2, $4)) {
+ case -1:
+ ERROR("failed to add enum %s\n", $2);
+ case 1:
+ ERROR("enum limit reached(%d) - %s\n", LT_ARGS_DEF_STRUCT_NUM, $2);
+ };
+}
+
+ENUM_DEF:
+ENUM_DEF ',' ENUM_ELEM
+{
+ struct lt_enum_elem *enum_elem = $3;
+ struct lt_list_head *h = $1;
+
+ lt_list_add_tail(&enum_elem->list, h);
+ $$ = h;
+}
+| ENUM_ELEM
+{
+ struct lt_list_head *h;
+ struct lt_enum_elem *enum_elem = $1;
+
+ GET_LIST_HEAD(h);
+ lt_list_add_tail(&enum_elem->list, h);
+ $$ = h;
+}
+
+ENUM_ELEM:
+NAME '=' NAME
+{
+ if (NULL == ($$ = lt_args_get_enum(scfg, $1, $3)))
+ ERROR("failed to add enum '%s = %s'\n", $1, $3);
+}
+|
+NAME
+{
+ if (NULL == ($$ = lt_args_get_enum(scfg, $1, NULL)))
+ ERROR("failed to add enum '%s = undef'\n", $1);
+}
+
+type_def:
+TYPEDEF NAME NAME ';'
+{
+ int ret = lt_args_add_typedef(scfg, $2, $3, 0);
+ CHK_TYPEDEF(ret, $2, $3, 0);
+}
+|
+TYPEDEF NAME POINTER NAME ';'
+{
+ int ret = lt_args_add_typedef(scfg, $2, $4, 1);
+ CHK_TYPEDEF(ret, $2, $4, 1);
+}
+
+/* function definitions */
+func_def:
+DEF '(' ARGS ')' ';'
+{
+ struct lt_arg *arg = $1;
+
+ if (lt_args_add_sym(scfg, arg, $3))
+ ERROR("failed to add symbol %s\n", arg->name);
+
+ /* force cration of the new list head */
+ $3 = NULL;
+}
+
+ARGS:
+ARGS ',' DEF
+{
+ struct lt_arg *def = $3;
+ struct lt_list_head *h = $1;
+
+ lt_list_add_tail(&def->args_list, h);
+ $$ = h;
+}
+| DEF
+{
+ struct lt_list_head *h;
+ struct lt_arg *def = $1;
+
+ GET_LIST_HEAD(h);
+ lt_list_add_tail(&def->args_list, h);
+ $$ = h;
+}
+| NAME
+{
+ GET_LIST_HEAD($$);
+}
+| /* left intentionaly blank */
+{
+ GET_LIST_HEAD($$);
+}
+
+DEF:
+NAME NAME ENUM_REF
+{
+ struct lt_arg *arg;
+
+ if (NULL == (arg = lt_args_getarg(scfg, $1, $2, 0, 1, $3)))
+ ERROR("unknown argument type - %s\n", $1);
+
+ $$ = arg;
+}
+|
+NAME POINTER NAME ENUM_REF
+{
+ struct lt_arg *arg;
+ if (NULL == (arg = lt_args_getarg(scfg, $1, $3, 1, 1, $4)))
+ ERROR("unknown argument type - %s\n", $1);
+
+ $$ = arg;
+}
+|
+STRUCT NAME NAME
+{
+ struct lt_arg *arg;
+ if (NULL == (arg = lt_args_getarg(scfg, $2, $3, 0, 1, NULL)))
+ ERROR("unknown argument type - %s\n", $2);
+
+ $$ = arg;
+}
+|
+STRUCT NAME POINTER NAME ENUM_REF
+{
+ struct lt_arg *arg;
+ if (NULL == (arg = lt_args_getarg(scfg, $2, $4, 1, 1, $5)))
+ ERROR("unknown argument type - %s\n", $2);
+
+ $$ = arg;
+}
+
+ENUM_REF:
+'=' NAME
+{
+ $$ = $2;
+}
+|
+{
+ $$ = NULL;
+}
+
+/* include definitions */
+include_def: INCLUDE '"' FILENAME '"'
+{
+ if (lt_args_buf_open(scfg, $3))
+ ERROR("failed to process include");
+}
+
+%%
+
+int lt_args_parse_init(struct lt_config_shared *cfg)
+{
+ scfg = cfg;
+ return 0;
+}
diff --git a/src/args-flex.l b/src/args-flex.l
new file mode 100644
index 0000000..e00b619
--- /dev/null
+++ b/src/args-flex.l
@@ -0,0 +1,89 @@
+/*
+ Copyright (C) 2008, 2009 Jiri Olsa <olsajiri@gmail.com>
+
+ This file is part of the latrace.
+
+ The latrace 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 3 of the License, or
+ (at your option) any later version.
+
+ The latrace 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 the latrace (file COPYING). If not, see
+ <http://www.gnu.org/licenses/>.
+*/
+
+
+%{
+
+#include <string.h>
+
+#include "config.h"
+#include "args-bison.h"
+
+struct lt_args_include* lt_args_buf_get(void);
+
+%}
+
+alphnum [-0-9a-zA-Z_]
+name ({alphnum})+
+filename ([-0-9a-zA-Z\./_])+
+
+%x comment include
+%%
+
+"/*" BEGIN(comment);
+<comment>[^*\n]* /* eat anything that's not a '*' */
+<comment>"*"+[^*/\n]* /* eat up '*'s not followed by '/'s */
+<comment>\n { lt_args_buf_get()->lineno++; }
+<comment>"*"+"/" BEGIN(INITIAL);
+
+"#include" { BEGIN(include); return INCLUDE; }
+<include>{filename} { yylval.s = strdup(yytext); return FILENAME; }
+<include>"\"" { return '"'; }
+<include>\n { BEGIN(INITIAL); }
+<include>. { ; }
+
+"extern" { ; }
+"const" { ; }
+<<EOF>> { return END; }
+"struct" { return STRUCT; }
+"enum" { return ENUM; }
+"typedef" { return TYPEDEF; }
+{name} { yylval.s = strdup(yytext); return NAME; }
+"\*"+ { return POINTER; }
+")" { return ')'; }
+"(" { return '('; }
+"}" { return '}'; }
+"{" { return '{'; }
+";" { return ';'; }
+"," { return ','; }
+"=" { return '='; }
+\ { ; }
+\n { lt_args_buf_get()->lineno++; }
+. { ; }
+
+%%
+
+#ifndef yywrap
+int yywrap()
+{
+ return 1;
+ /* XXX not to get the compiler 'not used' warning */
+ yyunput(0, NULL);
+ input();
+}
+#endif
+
+void yyerror(const char *m)
+{
+ printf("latrace config file [%s] line %d: %s\n",
+ lt_args_buf_get()->file,
+ lt_args_buf_get()->lineno,
+ m);
+}
diff --git a/src/args.c b/src/args.c
new file mode 100644
index 0000000..4bb1252
--- /dev/null
+++ b/src/args.c
@@ -0,0 +1,1066 @@
+/*
+ Copyright (C) 2008, 2009 Jiri Olsa <olsajiri@gmail.com>
+
+ This file is part of the latrace.
+
+ The latrace 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 3 of the License, or
+ (at your option) any later version.
+
+ The latrace 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 the latrace (file COPYING). If not, see
+ <http://www.gnu.org/licenses/>.
+*/
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <search.h>
+#include <setjmp.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+
+#include "config.h"
+
+
+#define YY_BUF_SIZE 16384
+#define MAX_INCLUDE_DEPTH 10
+#define LT_EQUAL " = "
+
+
+extern int errno;
+
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+YY_BUFFER_STATE yy_create_buffer(FILE *file, int size);
+extern FILE *yyin;
+
+int yyparse();
+void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer);
+void yy_delete_buffer(YY_BUFFER_STATE b);
+
+int lt_args_parse_init(struct lt_config_shared *cfg);
+static struct lt_args_include include_stack[MAX_INCLUDE_DEPTH];
+static int include_stack_ptr = 0;
+static int enum_init = 0;
+
+
+/* hardcoded POD types */
+static struct lt_arg args_def_pod[] = {
+ {
+ .dtype = LT_ARGS_DTYPE_POD,
+ .type_id = LT_ARGS_TYPEID_VOID,
+ .type_len = sizeof(void),
+ .type_name = "void",
+ .pointer = 0,
+ .name = "",
+ .mmbcnt = 0,
+ .arch = NULL,
+ .en = NULL,
+ .args_head = NULL,
+ .args_list = { NULL, NULL }
+ },
+ {
+ .dtype = LT_ARGS_DTYPE_POD,
+ .type_id = LT_ARGS_TYPEID_SHORT,
+ .type_len = sizeof(short),
+ .type_name = "short",
+ .pointer = 0,
+ .name = "",
+ .mmbcnt = 0,
+ .arch = NULL,
+ .en = NULL,
+ .args_head = NULL,
+ .args_list = { NULL, NULL }
+ },
+ {
+ .dtype = LT_ARGS_DTYPE_POD,
+ .type_id = LT_ARGS_TYPEID_USHORT,
+ .type_len = sizeof(unsigned short),
+ .type_name = "u_short",
+ .pointer = 0,
+ .name = "",
+ .mmbcnt = 0,
+ .arch = NULL,
+ .en = NULL,
+ .args_head = NULL,
+ .args_list = { NULL, NULL }
+ },
+ {
+ .dtype = LT_ARGS_DTYPE_POD,
+ .type_id = LT_ARGS_TYPEID_INT,
+ .type_len = sizeof(int),
+ .type_name = "int",
+ .pointer = 0,
+ .name = "",
+ .mmbcnt = 0,
+ .arch = NULL,
+ .en = NULL,
+ .args_head = NULL,
+ .args_list = { NULL, NULL }
+ },
+ {
+ .dtype = LT_ARGS_DTYPE_POD,
+ .type_id = LT_ARGS_TYPEID_UINT,
+ .type_len = sizeof(unsigned int),
+ .type_name = "u_int",
+ .pointer = 0,
+ .name = "",
+ .mmbcnt = 0,
+ .arch = NULL,
+ .en = NULL,
+ .args_head = NULL,
+ .args_list = { NULL, NULL }
+ },
+ {
+ .dtype = LT_ARGS_DTYPE_POD,
+ .type_id = LT_ARGS_TYPEID_LONG,
+ .type_len = sizeof(long),
+ .type_name = "long",
+ .pointer = 0,
+ .name = "",
+ .mmbcnt = 0,
+ .arch = NULL,
+ .en = NULL,
+ .args_head = NULL,
+ .args_list = { NULL, NULL }
+ },
+ {
+ .dtype = LT_ARGS_DTYPE_POD,
+ .type_id = LT_ARGS_TYPEID_ULONG,
+ .type_len = sizeof(unsigned long),
+ .type_name = "u_long",
+ .pointer = 0,
+ .name = "",
+ .mmbcnt = 0,
+ .arch = NULL,
+ .en = NULL,
+ .args_head = NULL,
+ .args_list = { NULL, NULL }
+ },
+ {
+ .dtype = LT_ARGS_DTYPE_POD,
+ .type_id = LT_ARGS_TYPEID_CHAR,
+ .type_len = sizeof(char),
+ .type_name = "char",
+ .pointer = 0,
+ .name = "",
+ .mmbcnt = 0,
+ .arch = NULL,
+ .en = NULL,
+ .args_head = NULL,
+ .args_list = { NULL, NULL }
+ },
+ {
+ .dtype = LT_ARGS_DTYPE_POD,
+ .type_id = LT_ARGS_TYPEID_UCHAR,
+ .type_len = sizeof(unsigned char),
+ .type_name = "u_char",
+ .pointer = 0,
+ .name = "",
+ .mmbcnt = 0,
+ .arch = NULL,
+ .en = NULL,
+ .args_head = NULL,
+ .args_list = { NULL, NULL }
+ },
+ {
+ .dtype = LT_ARGS_DTYPE_POD,
+ .type_id = LT_ARGS_TYPEID_LLONG,
+ .type_len = sizeof(long long),
+ .type_name = "llong",
+ .pointer = 0,
+ .name = "",
+ .mmbcnt = 0,
+ .arch = NULL,
+ .en = NULL,
+ .args_head = NULL,
+ .args_list = { NULL, NULL }
+ },
+ {
+ .dtype = LT_ARGS_DTYPE_POD,
+ .type_id = LT_ARGS_TYPEID_ULLONG,
+ .type_len = sizeof(unsigned long long),
+ .type_name = "u_llong",
+ .pointer = 0,
+ .name = "",
+ .mmbcnt = 0,
+ .arch = NULL,
+ .en = NULL,
+ .args_head = NULL,
+ .args_list = { NULL, NULL }
+ },
+ {
+ .dtype = LT_ARGS_DTYPE_POD,
+ .type_id = LT_ARGS_TYPEID_DOUBLE,
+ .type_len = sizeof(double),
+ .type_name = "double",
+ .pointer = 0,
+ .name = "",
+ .mmbcnt = 0,
+ .arch = NULL,
+ .en = NULL,
+ .args_head = NULL,
+ .args_list = { NULL, NULL }
+ },
+ {
+ .dtype = LT_ARGS_DTYPE_POD,
+ .type_id = LT_ARGS_TYPEID_FLOAT,
+ .type_len = sizeof(float),
+ .type_name = "float",
+ .pointer = 0,
+ .name = "",
+ .mmbcnt = 0,
+ .arch = NULL,
+ .en = NULL,
+ .args_head = NULL,
+ .args_list = { NULL, NULL }
+ },
+};
+
+#define LT_ARGS_DEF_POD_NUM (sizeof(args_def_pod)/sizeof(struct lt_arg))
+
+/* struct, typedef, enum */
+static struct lt_arg args_def_struct[LT_ARGS_DEF_STRUCT_NUM];
+static struct lt_arg args_def_typedef[LT_ARGS_DEF_TYPEDEF_NUM];
+static int args_def_struct_cnt = 0;
+static int args_def_typedef_cnt = 0;
+static struct hsearch_data args_enum_tab;
+
+static struct lt_enum* getenum(struct lt_config_shared *cfg, char *name)
+{
+ struct lt_enum *en;
+ ENTRY e, *ep;
+
+ PRINT_VERBOSE(cfg->verbose, 1, "request for <%s>\n", name);
+
+ if (!enum_init) {
+ PRINT_VERBOSE(cfg->verbose, 1, "no enum added so far\n", name);
+ return NULL;
+ }
+
+ e.key = name;
+ hsearch_r(e, FIND, &ep, &args_enum_tab);
+
+ if (!ep) {
+ PRINT_VERBOSE(cfg->verbose, 1, "failed to find enum <%s>\n", name);
+ return NULL;
+ }
+
+ en = (struct lt_enum*) ep->data;
+
+ PRINT_VERBOSE(cfg->verbose, 1, "found %p <%s>\n", en, en->name);
+ return en;
+}
+
+static int enum_comp(const void *ep1, const void *ep2)
+{
+ struct lt_enum_elem *e1 = (struct lt_enum_elem*) ep1;
+ struct lt_enum_elem *e2 = (struct lt_enum_elem*) ep2;
+
+ return e1->val - e2->val;
+}
+
+static struct lt_enum_elem* get_enumelem(struct lt_config_shared *cfg,
+ long val, struct lt_enum *en)
+{
+ struct lt_enum_elem key;
+ key.val = val;
+
+ PRINT_VERBOSE(cfg->verbose, 1, "looking for %p <%s> value %ld\n",
+ en, en->name, val);
+
+ return bsearch(&key, en->elems, en->cnt,
+ sizeof(struct lt_enum_elem), enum_comp);
+}
+
+int lt_args_add_enum(struct lt_config_shared *cfg, char *name,
+ struct lt_list_head *h)
+{
+ ENTRY e, *ep;
+ struct lt_enum_elem *elem, *last = NULL;
+ struct lt_enum *en;
+ int i = 0;
+
+ if (NULL == (en = malloc(sizeof(*en))))
+ return -1;
+
+ memset(en, 0x0, sizeof(*en));
+ en->name = name;
+
+ /* Initialize the hash table holding enum names */
+ if (!enum_init) {
+ if (!hcreate_r(LT_ARGS_DEF_ENUM_NUM, &args_enum_tab)) {
+ perror("failed to create has table:");
+ return -1;
+ }
+ enum_init = 1;
+ }
+
+ e.key = en->name;
+ e.data = en;
+
+ if (!hsearch_r(e, ENTER, &ep, &args_enum_tab)) {
+ perror("hsearch_r failed");
+ free(en);
+ /* we dont want to exit just because
+ we ran out of our symbol limit */
+ PRINT_VERBOSE(cfg->verbose, 3,
+ "reach the enum number limit %u\n",
+ LT_ARGS_DEF_ENUM_NUM);
+ }
+
+ /* We've got enum inside the hash, let's prepare the enum itself.
+ The 'elems' field is going to be the qsorted list of
+ 'struct enum_elem's */
+ lt_list_for_each_entry(elem, h, list)
+ en->cnt++;
+
+ if (NULL == (en->elems = malloc(sizeof(struct lt_enum_elem) * en->cnt)))
+ return -1;
+
+ PRINT_VERBOSE(cfg->verbose, 3, "enum %s (%d elems)\n",
+ en->name, en->cnt);
+
+ lt_list_for_each_entry(elem, h, list) {
+
+ if (elem->undef) {
+ if (!last)
+ elem->val = 0;
+ else
+ elem->val = last->val + 1;
+ elem->undef = 0;
+ }
+
+ PRINT_VERBOSE(cfg->verbose, 3, "\t %s = %d\n",
+ elem->name, elem->val);
+
+ en->elems[i++] = *elem;
+ last = elem;
+ }
+
+ qsort(en->elems, en->cnt, sizeof(struct lt_enum_elem), enum_comp);
+ return 0;
+}
+
+struct lt_enum_elem* lt_args_get_enum(struct lt_config_shared *cfg,
+ char *name, char *val)
+{
+ struct lt_enum_elem* elem;
+
+ if (NULL == (elem = malloc(sizeof(*elem))))
+ return NULL;
+
+ memset(elem, 0x0, sizeof(*elem));
+ elem->undef = 1;
+
+ if (val) {
+ long num = strtol(val, (char **) NULL, 10);
+ if ((errno == ERANGE && (num == LONG_MAX || num == LONG_MIN)) ||
+ (errno != 0 && num == 0))
+ return NULL;
+
+ elem->val = num;
+ elem->undef = 0;
+ }
+
+ elem->name = strdup(name);
+
+ PRINT_VERBOSE(cfg->verbose, 3, "enum elem %s = %d, undef = %d\n",
+ elem->name, elem->val, elem->undef);
+ return elem;
+}
+
+int lt_args_add_struct(struct lt_config_shared *cfg, char *type_name,
+ struct lt_list_head *h)
+{
+ struct lt_arg *arg, sarg;
+
+ if ((args_def_struct_cnt + 1) == LT_ARGS_DEF_STRUCT_NUM)
+ return 1;
+
+ /* check if the struct name is already
+ defined as a type */
+ if (lt_args_getarg(cfg, type_name, NULL, 0, 1, NULL))
+ return -1;
+
+ memset(&sarg, 0, sizeof(sarg));
+ sarg.dtype = LT_ARGS_DTYPE_STRUCT;
+ sarg.type_id = LT_ARGS_TYPEID_CUSTOM + args_def_struct_cnt;
+ sarg.type_name = type_name;
+ sarg.args_head = h;
+
+ PRINT_VERBOSE(cfg->verbose, 3, "struct [%s] type %d\n",
+ sarg.type_name, sarg.type_id);
+
+ lt_list_for_each_entry(arg, sarg.args_head, args_list) {
+
+ PRINT_VERBOSE(cfg->verbose, 3, "\t %s %s %u\n",
+ arg->type_name, arg->name, arg->type_len);
+
+ /* This is not what sizeof would return on the structure.
+ The sizeof is arch dependent, this is pure sum. */
+ sarg.type_len += arg->type_len;
+ sarg.mmbcnt++;
+ }
+
+ args_def_struct[args_def_struct_cnt++] = sarg;
+
+ PRINT_VERBOSE(cfg->verbose, 3, "%d.struct - final len = %u\n",
+ args_def_struct_cnt, sarg.type_len);
+ return 0;
+}
+
+int lt_args_add_sym(struct lt_config_shared *cfg, struct lt_arg *ret,
+ struct lt_list_head *h)
+{
+ ENTRY e, *ep;
+ struct lt_args_sym *sym;
+ struct lt_arg *arg;
+ int i = 0;
+
+ PRINT_VERBOSE(cfg->verbose, 3, "got symbol '%s %s'\n",
+ ret->type_name, ret->name);
+
+ if (NULL == (sym = (struct lt_args_sym*) malloc(sizeof(*sym))))
+ return -1;
+
+ memset(sym, 0, sizeof(*sym));
+ sym->name = ret->name;
+
+ sym->argcnt = 1;
+ lt_list_for_each_entry(arg, h, args_list)
+ sym->argcnt++;
+
+ sym->args = (struct lt_arg**) malloc(sym->argcnt * sizeof(struct lt_arg**));
+ if (!sym->args)
+ /* no need to fre sym, since we are going
+ to exit the program anyway */
+ return -1;
+
+ PRINT_VERBOSE(cfg->verbose, 3, "got return %s, ptr %d\n",
+ ret->type_name, ret->pointer);
+
+ sym->args[i++] = ret;
+ lt_list_for_each_entry(arg, h, args_list) {
+ PRINT_VERBOSE(cfg->verbose, 3, "\t '%s %s'\n",
+ arg->type_name, arg->name);
+ sym->args[i++] = arg;
+ }
+
+ e.key = sym->name;
+ e.data = sym;
+
+ if (!hsearch_r(e, ENTER, &ep, &cfg->args_tab)) {
+ perror("hsearch_r failed");
+ free(sym);
+ /* we dont want to exit just because
+ we ran out of our symbol limit */
+ PRINT_VERBOSE(cfg->verbose, 3, "reach the symbol number limit %u\n",
+ LT_ARGS_TAB);
+ } else
+ PRINT_VERBOSE(cfg->verbose, 3, "got symbol %s (%d args)\n",
+ sym->name, sym->argcnt);
+
+ return 0;
+}
+
+static struct lt_arg* argdup(struct lt_config_shared *cfg, struct lt_arg *asrc)
+{
+ struct lt_arg *arg, *a;
+ struct lt_list_head *h;
+
+ PRINT_VERBOSE(cfg->verbose, 2, "got arg '%s %s', dtype %d\n",
+ asrc->type_name, asrc->name, asrc->dtype);
+
+ if (NULL == (arg = malloc(sizeof(*arg)))) {
+ perror("malloc failed");
+ return NULL;
+ }
+
+ *arg = *asrc;
+
+ if (arg->dtype != LT_ARGS_DTYPE_STRUCT)
+ return arg;
+
+ /* For structures we need also to copy all its arguments. */
+
+ if (NULL == (h = (struct lt_list_head*) malloc(sizeof(*h)))) {
+ perror("malloc failed");
+ return NULL;
+ }
+
+ lt_init_list_head(h);
+
+ lt_list_for_each_entry(a, asrc->args_head, args_list) {
+ struct lt_arg *aa;
+
+ /* XXX Not sure how safe is this one...
+ might need some attention in future :) */
+ if (NULL == (aa = argdup(cfg, a)))
+ return NULL;
+
+ lt_list_add_tail(&aa->args_list, h);
+ }
+
+ arg->args_head = h;
+ return arg;
+}
+
+static struct lt_arg* find_arg(struct lt_config_shared *cfg, char *type,
+ struct lt_arg argsdef[], int size, int create)
+{
+ int i;
+
+ for(i = 0; i < size; i++) {
+ struct lt_arg *arg;
+ struct lt_arg adef = argsdef[i];
+
+ PRINT_VERBOSE(cfg->verbose, 3, "%d. looking for [%s] - [%s]\n",
+ i, type, adef.type_name);
+
+ if (strcmp(type, adef.type_name))
+ continue;
+
+ if (!create)
+ return &argsdef[i];
+
+ arg = argdup(cfg, &adef);
+
+ PRINT_VERBOSE(cfg->verbose, 3, "found %d\n", arg->type_id);
+ return arg;
+ }
+
+ return NULL;
+}
+
+struct lt_arg* lt_args_getarg(struct lt_config_shared *cfg, char *type,
+ char *name, int pointer, int create, char *enum_name)
+{
+ struct lt_arg *arg;
+
+ do {
+ if ((arg = find_arg(cfg, type,
+ args_def_pod, LT_ARGS_DEF_POD_NUM, create)))
+ break;
+
+ if ((arg = find_arg(cfg, type,
+ args_def_struct, args_def_struct_cnt, create)))
+ break;
+
+ if ((arg = find_arg(cfg, type,
+ args_def_typedef, args_def_typedef_cnt, create)))
+ break;
+
+ return NULL;
+
+ } while(0);
+
+ if (!create)
+ return arg;
+
+ /* Find out the enum definition if the enum
+ name is provided. */
+ if (enum_name)
+ arg->en = getenum(cfg, enum_name);
+
+ arg->name = strdup(name);
+
+ /* If the type is already a pointer (could be for typedef),
+ give it a chance to show up. There's only one pointer for
+ the arg, since there's no reason to go dreper. */
+ if (!arg->pointer)
+ arg->pointer = pointer;
+
+ return arg;
+}
+
+int lt_args_add_typedef(struct lt_config_shared *cfg, char *base,
+ char *new, int pointer)
+{
+ struct lt_arg *arg;
+ int i;
+
+ if ((args_def_typedef_cnt + 1) == LT_ARGS_DEF_TYPEDEF_NUM)
+ return 2;
+
+ /* check if the typedef name is already
+ defined as a type */
+ if (lt_args_getarg(cfg, new, NULL, 0, 0, NULL))
+ return 1;
+
+ do {
+ if ((arg = find_arg(cfg, base,
+ args_def_pod, LT_ARGS_DEF_POD_NUM, 0)))
+ break;
+
+ if ((arg = find_arg(cfg, base,
+ args_def_typedef, args_def_typedef_cnt, 0)))
+ break;
+
+ PRINT_VERBOSE(cfg->verbose, 3, "%s not found\n", base);
+ return -1;
+
+ } while(0);
+
+ PRINT_VERBOSE(cfg->verbose, 3, "got [%s]\n", new);
+
+ args_def_typedef[i = args_def_typedef_cnt++] = *arg;
+
+ arg = &args_def_typedef[i];
+ arg->type_name = strdup(new);
+ arg->pointer = pointer;
+
+ lt_init_list_head(&arg->args_list);
+
+ PRINT_VERBOSE(cfg->verbose, 3, "%d.typedef - got [%s] [%s]\n",
+ args_def_typedef_cnt, base, arg->type_name);
+ return 0;
+}
+
+int lt_args_init(struct lt_config_shared *cfg)
+{
+ char *file = LT_ARGS_DEF_CONF;
+ int ret = 0;
+
+ if (!hcreate_r(LT_ARGS_TAB, &cfg->args_tab)) {
+ perror("failed to create has table:");
+ return -1;
+ }
+
+ lt_args_parse_init(cfg);
+
+ if (*cfg->args_def)
+ file = cfg->args_def;
+
+ PRINT_VERBOSE(cfg->verbose, 1, "arguments definition file %s\n", file);
+
+ if (lt_args_buf_open(cfg, file))
+ return -1;
+
+ if (yyparse()) {
+ printf("failed to parse config file %s\n", file);
+ ret = -1;
+ }
+
+ if (fclose(yyin)) {
+ perror("failed to close " LT_ARGS_DEF_CONF);
+ return -1;
+ }
+
+ return ret;
+}
+
+static struct lt_args_sym* getsym(struct lt_config_shared *cfg, char *sym)
+{
+ struct lt_args_sym *a;
+ ENTRY e, *ep;
+
+ PRINT_VERBOSE(cfg->verbose, 1, "request for <%s>\n", sym);
+
+ e.key = sym;
+ hsearch_r(e, FIND, &ep, &cfg->args_tab);
+
+ if (!ep)
+ return NULL;
+
+ a = (struct lt_args_sym*) ep->data;
+
+ PRINT_VERBOSE(cfg->verbose, 1, "found %p <%s>\n", a, a->name);
+ return a;
+}
+
+static int getstr_addenum(struct lt_config_shared *cfg, struct lt_arg *arg,
+ char *argbuf, int alen, long val)
+{
+ char *enstr = NULL;
+ struct lt_enum_elem *elem;
+
+ if (!arg->en)
+ return 0;
+
+ if (NULL != (elem = get_enumelem(cfg, val, arg->en)))
+ enstr = elem->name;
+
+ if (enstr)
+ return snprintf(argbuf, alen, "%s", enstr);
+
+ return 0;
+}
+
+static int getstr_pod(struct lt_config_shared *cfg, int dspname, struct lt_arg *arg,
+ void *pval, char *argbuf, int *arglen)
+{
+ int len = 0, alen = *arglen;
+ int namelen = strlen(arg->name);
+
+ PRINT_VERBOSE(cfg->verbose, 1, "\t arg '%s %s', pval %p, len %d, pointer %d, dtype %d, type_id %d\n",
+ arg->type_name, arg->name, pval, alen, arg->pointer, arg->dtype, arg->type_id);
+
+ if (alen < 5)
+ return 0;
+
+ *arglen = 0;
+
+ if ((dspname) &&
+ (namelen < (alen - 5 - sizeof(LT_EQUAL)))) {
+ *arglen = sprintf(argbuf, "%s"LT_EQUAL, arg->name);
+ argbuf += *arglen;
+ alen -= *arglen;
+ }
+
+ /* Get enum resolve for pointers now, the rest
+ POD is done in ARGS_SPRINTF macro. The char
+ pointers need special handling later. */
+ if ((arg->pointer) &&
+ (arg->type_id != LT_ARGS_TYPEID_CHAR)) {
+
+ void *ptr = *((void**) pval);
+
+ /* Try to get enumed value first. */
+ len = getstr_addenum(cfg, arg, argbuf, alen, (long)ptr);
+
+ /* If there's no enum resolved,
+ just display the ptr value */
+ if (!len) {
+ if (ptr)
+ len = snprintf(argbuf, alen, "%p", ptr);
+ else
+ len = snprintf(argbuf, alen, "NULL");
+ }
+
+ goto out;
+ }
+
+#define ARGS_SPRINTF(FMT, TYPE) \
+do { \
+ if (!(len = getstr_addenum(cfg, arg, argbuf, alen, \
+ (long) *((TYPE*) pval)))) \
+ len = snprintf(argbuf, alen, FMT, *((TYPE*) pval)); \
+} while(0)
+
+ switch(arg->type_id) {
+ case LT_ARGS_TYPEID_SHORT: ARGS_SPRINTF("%hd", short); break;
+ case LT_ARGS_TYPEID_USHORT: ARGS_SPRINTF("%hu", unsigned short); break;
+ case LT_ARGS_TYPEID_INT: ARGS_SPRINTF("%d", int); break;
+ case LT_ARGS_TYPEID_UINT: ARGS_SPRINTF("%u", unsigned int); break;
+ case LT_ARGS_TYPEID_LONG: ARGS_SPRINTF("%ld", long); break;
+ case LT_ARGS_TYPEID_ULONG: ARGS_SPRINTF("%lu", unsigned long); break;
+ case LT_ARGS_TYPEID_LLONG: ARGS_SPRINTF("%lld", long long); break;
+ case LT_ARGS_TYPEID_ULLONG: ARGS_SPRINTF("%llu", unsigned long long); break;
+ case LT_ARGS_TYPEID_DOUBLE: ARGS_SPRINTF("%lf", double); break;
+ case LT_ARGS_TYPEID_FLOAT: ARGS_SPRINTF("%f", float); break;
+#undef ARGS_SPRINTF
+ case LT_ARGS_TYPEID_CHAR:
+ if (arg->pointer) {
+
+ void *val = *((void**) pval);
+
+ if (val) {
+ char *s = val;
+ int slen = strlen(s);
+ int left = alen;
+
+ if ((slen + 2) > left) {
+ snprintf(argbuf, left, "\"%s", s);
+ strncpy(argbuf + left - sizeof("...\"") + 1, "...\"", sizeof("...\""));
+ } else {
+ strcpy(argbuf, "\"");
+ strcat(argbuf, s);
+ strcat(argbuf, "\"");
+ }
+ } else
+ len = snprintf(argbuf, alen, "NULL");
+ } else {
+
+ if (*((char*) pval) <= ' ')
+ len = snprintf(argbuf, alen, "0x%02x",
+ *((char*) pval));
+ else
+ len = snprintf(argbuf, alen, "0x%02x \'%c\'",
+ *((char*) pval), *((char*) pval));
+ }
+ break;
+
+ case LT_ARGS_TYPEID_VOID:
+ len = snprintf(argbuf, alen, "void");
+ break;
+ }
+
+ if (LT_ARGS_DTYPE_STRUCT == arg->dtype) {
+ if (pval)
+ len = snprintf(argbuf, alen, "v(%p)", pval);
+ else
+ len = snprintf(argbuf, alen, "v(REG)");
+
+ }
+
+out:
+ *arglen += strlen(argbuf);
+
+ PRINT_VERBOSE(cfg->verbose, 1, "\t arg out len %d - [%s]\n",
+ *arglen, argbuf);
+ return 0;
+}
+
+int lt_args_cb_arg(struct lt_config_shared *cfg, struct lt_arg *arg, void *pval,
+ struct lt_args_data *data, int last, int dspname)
+{
+ int len = data->arglen;
+
+ PRINT_VERBOSE(cfg->verbose, 1, "arg '%s %s', pval %p, last %d\n",
+ arg->type_name, arg->name, pval, last);
+
+ getstr_pod(cfg, dspname, arg, pval,
+ data->args_buf + data->args_totlen, &len);
+ data->args_totlen += len;
+
+ if (!last) {
+ strcat(data->args_buf, ", ");
+ data->args_totlen += 2;
+ }
+
+ return 0;
+}
+
+int lt_args_cb_struct(struct lt_config_shared *cfg, int type, struct lt_arg *arg,
+ void *pval, struct lt_args_data *data, int last)
+{
+ PRINT_VERBOSE(cfg->verbose, 1,
+ "type %d, arg '%s %s', pval %p, last %d, pointer %d\n",
+ type, arg->type_name, arg->name, pval, last, arg->pointer);
+
+ /* initiall call for the structure argument */
+ if (type == LT_ARGS_STRUCT_ITSELF) {
+
+ data->argsd_totlen += sprintf(data->argsd_buf + data->argsd_totlen,
+ "struct %s %s = { ",
+ arg->type_name, arg->name);
+ return 0;
+
+ /* subsequent calls for all structure arguments */
+ } else if (type == LT_ARGS_STRUCT_ARG) {
+
+ int len = cfg->args_detail_maxlen - data->argsd_totlen;
+
+ getstr_pod(cfg, 1, arg, pval, data->argsd_buf + data->argsd_totlen, &len);
+ data->argsd_totlen += len;
+
+ if (!last) {
+ strcat(data->argsd_buf, ", ");
+ data->argsd_totlen += 2;
+ } else
+ data->argsd_totlen += sprintf(data->argsd_buf +
+ data->argsd_totlen, " }\n");
+ }
+
+ return 0;
+}
+
+static int getargs(struct lt_config_shared *cfg, struct lt_args_sym *asym,
+ La_regs *regs, char **abuf, char **adbuf)
+{
+ struct lt_args_data data;
+ int arglen;
+ char *buf, *bufd;
+
+ if (NULL == (buf = malloc(cfg->args_maxlen)))
+ return -1;
+
+ memset(&data, 0, sizeof(data));
+
+ *buf = 0;
+ *abuf = buf;
+
+ if (cfg->args_detailed) {
+ if (NULL == (bufd = malloc(cfg->args_detail_maxlen)))
+ return -1;
+
+ *bufd = 0;
+ *adbuf = bufd;
+ data.argsd_buf = bufd;
+ data.argsd_len = cfg->args_detail_maxlen;
+ }
+
+
+ /* makeup the final space for each
+ argument textual representation */
+ arglen = (cfg->args_maxlen
+ - ((asym->argcnt - 1) * 2) /* args separating commas */
+ )/ asym->argcnt;
+
+
+ data.arglen = arglen;
+ data.args_buf = buf;
+ data.args_len = cfg->args_maxlen;
+
+ return lt_stack_process(cfg, asym, regs, &data);
+}
+
+static FILE* open_include(struct lt_config_shared *cfg, char *file)
+{
+ FILE *f;
+ char fn[LT_MAXFILE];
+
+ /* we got an absolute path */
+ if ((NULL != (f = fopen(file, "r")))) {
+ PRINT_VERBOSE(cfg->verbose, 1, "open ok [%s]\n", file);
+ return f;
+ }
+
+ PRINT_VERBOSE(cfg->verbose, 1, "open failed [%s]: %s\n",
+ file, strerror(errno));
+
+ /* give up if there was already the absolute name */
+ if (*file == '/') {
+ printf("open failed [%s]: %s\n", file, strerror(errno));
+ return NULL;
+ }
+
+ /* not an absolute name, give it a chance
+ inside of the /etc config directory */
+ if (strlen(file) > (LT_MAXFILE - sizeof(LT_ARGS_DEF_DIR))) {
+ printf("file name length crossed the max %u: %s\n",
+ (u_int) (LT_MAXFILE - sizeof(LT_ARGS_DEF_DIR)), file);
+ return NULL;
+ }
+
+ sprintf(fn, "%s/%s", LT_ARGS_DEF_DIR, file);
+
+ if ((NULL == (f = fopen(fn, "r")))) {
+ PRINT_VERBOSE(cfg->verbose, 1, "open failed [%s]: %s\n",
+ fn, strerror(errno));
+ printf("open failed [%s]: %s\n", file, strerror(errno));
+ return NULL;
+ }
+
+ PRINT_VERBOSE(cfg->verbose, 1, "open ok [%s]\n", fn);
+ return f;
+}
+
+int lt_args_buf_open(struct lt_config_shared *cfg, char *file)
+{
+ struct lt_args_include *inc;
+
+ PRINT_VERBOSE(cfg->verbose, 1, "opening buffer for [%s] depth %d\n",
+ file, include_stack_ptr);
+
+ if ((include_stack_ptr + 1) == MAX_INCLUDE_DEPTH) {
+ printf("include depth overstep");
+ return -1;
+ }
+
+ if (NULL == (yyin = open_include(cfg, file)))
+ return -1;
+
+ inc = &include_stack[include_stack_ptr++];
+ memset(inc, 0, sizeof(*inc));
+
+ inc->yyin = yyin;
+ inc->file = strdup(file);
+ inc->lineno = 1;
+ inc->yybuf = yy_create_buffer(yyin, YY_BUF_SIZE);
+
+ yy_switch_to_buffer(inc->yybuf);
+
+ PRINT_VERBOSE(cfg->verbose, 1, "opened buffer for [%s] depth %d\n",
+ file, include_stack_ptr);
+ return 0;
+}
+
+int lt_args_buf_close(struct lt_config_shared *cfg)
+{
+ struct lt_args_include *inc = &include_stack[--include_stack_ptr];
+
+ PRINT_VERBOSE(cfg->verbose, 1, "buffer closed [%s], depth [%d]\n",
+ inc->file, include_stack_ptr);
+
+ free(inc->file);
+
+ /* EOF with no other includes on stack */
+ if (!include_stack_ptr)
+ return -1;
+
+ /* looks like the base buffer is cleaned up by the
+ flex itself, so we do the actual cleaning
+ only for includes */
+ yy_delete_buffer(inc->yybuf);
+ fclose(inc->yyin);
+
+ inc = &include_stack[include_stack_ptr - 1];
+ yy_switch_to_buffer(inc->yybuf);
+ return 0;
+}
+
+struct lt_args_include* lt_args_buf_get(void)
+{
+ struct lt_args_include *inc = &include_stack[include_stack_ptr - 1];
+ return inc;
+}
+
+int lt_args_sym_entry(struct lt_config_shared *cfg, char *sym, La_regs *regs,
+ char **argbuf, char **argdbuf)
+{
+ struct lt_args_sym *asym;
+
+ if (NULL == (asym = getsym(cfg, sym)))
+ return -1;
+
+ return getargs(cfg, asym, regs, argbuf, argdbuf);
+}
+
+static int getargs_ret(struct lt_config_shared *cfg, struct lt_args_sym *asym,
+ La_retval *regs, char **abuf, char **adbuf)
+{
+ struct lt_args_data data;
+ int arglen, totlen;
+ char *buf, *bufd;
+
+ if (NULL == (buf = malloc(cfg->args_maxlen)))
+ return -1;
+
+ memset(&data, 0, sizeof(data));
+
+ *buf = 0;
+ *abuf = buf;
+
+ /* TODO get together with getargs function somehow... */
+ if (cfg->args_detailed) {
+
+ if (NULL == (bufd = malloc(cfg->args_detail_maxlen)))
+ return -1;
+
+ *bufd = 0;
+ *adbuf = bufd;
+ data.argsd_buf = bufd;
+ data.argsd_len = cfg->args_detail_maxlen;
+ }
+
+ arglen = cfg->args_maxlen - sizeof(LT_EQUAL);
+ totlen = sizeof(LT_EQUAL) - 1;
+ strcat(buf, LT_EQUAL);
+
+ data.arglen = arglen;
+ data.args_buf = buf;
+ data.args_len = cfg->args_maxlen;
+ data.args_totlen = totlen;
+
+ return lt_stack_process_ret(cfg, asym, regs, &data);
+}
+
+int lt_args_sym_exit(struct lt_config_shared *cfg, char *sym, La_regs *inregs, La_retval *outregs,
+ char **argbuf, char **argdbuf)
+{
+ struct lt_args_sym *asym;
+
+ if (NULL == (asym = getsym(cfg, sym)))
+ return -1;
+
+ return getargs_ret(cfg, asym, outregs, argbuf, argdbuf);
+}
diff --git a/src/audit-init.c b/src/audit-init.c
new file mode 100644
index 0000000..5ab978c
--- /dev/null
+++ b/src/audit-init.c
@@ -0,0 +1,196 @@
+/*
+ Copyright (C) 2008, 2009 Jiri Olsa <olsajiri@gmail.com>
+
+ This file is part of the latrace.
+
+ The latrace 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 3 of the License, or
+ (at your option) any later version.
+
+ The latrace 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 the latrace (file COPYING). If not, see
+ <http://www.gnu.org/licenses/>.
+*/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "config.h"
+
+struct lt_config_audit cfg;
+
+static int read_config(char *dir)
+{
+ int fd;
+ off_t len;
+ char file[LT_MAXFILE];
+
+ memset(&cfg, 0, sizeof(cfg));
+
+ cfg.dir = dir;
+ sprintf(file, "%s/config", dir);
+
+ if (-1 == (fd = open(file, O_RDONLY))) {
+ perror("open failed");
+ return -1;
+ }
+
+ if (-1 == read(fd, &cfg.sh, sizeof(cfg.sh))) {
+ perror("read failed");
+ return -1;
+ }
+
+ if (-1 == (len = lseek(fd, 0, SEEK_END))) {
+ perror("lseek failed");
+ return -1;
+ }
+
+ if (len != sizeof(cfg.sh)) {
+ printf("config file size differs\n");
+ return -1;
+ }
+
+ if (LT_MAGIC != cfg.sh.magic) {
+ printf("config file magic check failed\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int get_names(struct lt_config_audit *cfg, char *names, char **ptr)
+{
+ char* s;
+ int cnt = 0;
+
+ PRINT_VERBOSE(cfg->sh.verbose, 1, "names: [%s] max: %d\n",
+ names, LT_NAMES_MAX);
+
+ s = strchr(names, LT_NAMES_SEP);
+ while(NULL != (s = strchr(names, LT_NAMES_SEP)) && (cnt < LT_NAMES_MAX)) {
+ *s = 0x0;
+ PRINT_VERBOSE(cfg->sh.verbose, 1, "got: %s", names);
+ ptr[cnt++] = names;
+ names = ++s;
+ }
+
+ if (cnt) {
+ ptr[cnt++] = names;
+ PRINT_VERBOSE(cfg->sh.verbose, 1, "got: %s\n", names);
+ }
+
+ if (!cnt && *names) {
+ ptr[0] = names;
+ cnt = 1;
+ PRINT_VERBOSE(cfg->sh.verbose, 1, "got: %s\n", names);
+ }
+
+ ptr[cnt] = NULL;
+
+ if (!cnt)
+ return -1;
+
+ PRINT_VERBOSE(cfg->sh.verbose, 1, "got %d entries\n", cnt);
+ return cnt;
+}
+
+int audit_init(int argc, char **argv, char **env)
+{
+ if (-1 == read_config(getenv("LT_DIR")))
+ return -1;
+
+ /* -Aa */
+ if (cfg.sh.args_enabled && lt_args_init(&cfg.sh))
+ return -1;
+
+ /* -t */
+ if ((*cfg.sh.libs_to) &&
+ (-1 == (cfg.libs_to_cnt = get_names(&cfg, cfg.sh.libs_to, cfg.libs_to)))) {
+ printf("latrace failed to parse libs to\n");
+ return -1;
+ }
+
+ /* -f */
+ if ((*cfg.sh.libs_from) &&
+ (-1 == (cfg.libs_from_cnt = get_names(&cfg, cfg.sh.libs_from, cfg.libs_from)))) {
+ printf("latrace failed to parse libs from\n");
+ return -1;
+ }
+
+ /* -l */
+ if ((*cfg.sh.libs_both) &&
+ (-1 == (cfg.libs_both_cnt = get_names(&cfg, cfg.sh.libs_both, cfg.libs_both)))) {
+ printf("latrace failed to parse libs from\n");
+ return -1;
+ }
+
+ /* -s */
+ if ((*cfg.sh.symbols) &&
+ (-1 == (cfg.symbols_cnt = get_names(&cfg, cfg.sh.symbols, cfg.symbols)))) {
+ printf("latrace failed to parse symbols\n");
+ return -1;
+ }
+
+ /* -b */
+ if ((*cfg.sh.flow_below) &&
+ (-1 == (cfg.flow_below_cnt = get_names(&cfg, cfg.sh.flow_below, cfg.flow_below)))) {
+ printf("latrace failed to parse symbols in flow-below option\n");
+ return -1;
+ }
+
+ /* -L */
+ if (*cfg.sh.libs_subst) {
+
+ char *ptr[LT_NAMES_MAX];
+ int cnt;
+
+ if (-1 == (cnt = get_names(&cfg, cfg.sh.libs_subst, ptr))) {
+ printf("latrace failed to parse input for subst option\n");
+ return -1;
+ }
+
+ if (-1 == lt_objsearch_init(&cfg, ptr, cnt)) {
+ printf("latrace failed to nitialize subst option\n");
+ return -1;
+ }
+ }
+
+ /* -o */
+ cfg.sh.fout = stdout;
+ if ((*cfg.sh.output) && (NULL == (cfg.sh.fout = fopen(cfg.sh.output, "w")))) {
+ printf("latrace failed to open output file %s\n", cfg.sh.output);
+ return -1;
+ }
+
+ /* -E */
+ if (cfg.sh.not_follow_exec)
+ unsetenv("LD_AUDIT");
+
+ /* -F */
+ if (cfg.sh.not_follow_fork)
+ cfg.sh.pid = getpid();
+
+ cfg.init_ok = 1;
+ return 0;
+}
+
+void finalize(void) __attribute__((destructor));
+
+void
+finalize(void)
+{
+ if ((!cfg.sh.pipe) && (*cfg.sh.output))
+ fclose(cfg.sh.fout);
+}
diff --git a/src/audit.c b/src/audit.c
new file mode 100644
index 0000000..d50a01f
--- /dev/null
+++ b/src/audit.c
@@ -0,0 +1,287 @@
+/*
+ Copyright (C) 2008, 2009 Jiri Olsa <olsajiri@gmail.com>
+
+ This file is part of the latrace.
+
+ The latrace 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 3 of the License, or
+ (at your option) any later version.
+
+ The latrace 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 the latrace (file COPYING). If not, see
+ <http://www.gnu.org/licenses/>.
+*/
+
+
+#include <link.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <bits/wordsize.h>
+#include <gnu/lib-names.h>
+#include <stdlib.h>
+
+#include "config.h"
+
+
+extern struct lt_config_audit cfg;
+
+static __thread int pipe_fd = 0;
+static __thread int flow_below_stack = 0;
+
+
+static int check_names(char *name, char **ptr)
+{
+ char *n;
+
+ for(n = *ptr; n; n = *(++ptr)) {
+ if (strstr(name, n)) {
+ PRINT_VERBOSE(cfg.sh.verbose, 2,
+ "return %d for name %s\n", 1, name);
+ return 1;
+ }
+ }
+
+ PRINT_VERBOSE(cfg.sh.verbose, 2, "return %d for name %s\n",
+ 0, name);
+ return 0;
+}
+
+static int check_flow_below(const char *symname, int in)
+{
+ int ret = flow_below_stack;
+
+ if (check_names((char*) symname, cfg.flow_below))
+ in ? ret = ++flow_below_stack : flow_below_stack--;
+
+ return ret;
+}
+
+static int sym_entry(const char *symname, char *lib_from, char *lib_to,
+ La_regs *regs)
+{
+ int argret;
+ char *argbuf = "", *argdbuf = "";
+
+ PRINT_VERBOSE(cfg.sh.verbose, 2, "%s@%s\n", symname, lib_to);
+
+ if (cfg.flow_below_cnt && !check_flow_below(symname, 1))
+ return 0;
+
+ argret = cfg.sh.args_enabled ?
+ lt_args_sym_entry(&cfg.sh, (char*) symname, regs, &argbuf, &argdbuf) : -1;
+
+ if (cfg.sh.pipe) {
+ char buf[FIFO_MSG_MAXLEN];
+ int len;
+
+ if (!pipe_fd)
+ pipe_fd = lt_fifo_create(&cfg, cfg.dir);
+
+ len = lt_fifo_msym_get(&cfg, buf, FIFO_MSG_TYPE_ENTRY,
+ (char*) symname, lib_to, argbuf, argdbuf);
+
+ return lt_fifo_send(&cfg, pipe_fd, buf, len);
+ }
+
+ cfg.sh.indent_depth++;
+
+ lt_out_entry(&cfg.sh, symname, lib_to,
+ argbuf, argdbuf);
+
+ if (!argret) {
+ free(argbuf);
+ if (cfg.sh.args_detailed && (*argdbuf))
+ free(argdbuf);
+ }
+
+ return 0;
+}
+
+static int sym_exit(const char *symname, char *lib_from, char *lib_to,
+ const La_regs *inregs, La_retval *outregs)
+{
+ int argret;
+ char *argbuf = "", *argdbuf = "";
+
+ PRINT_VERBOSE(cfg.sh.verbose, 2, "%s@%s\n", symname, lib_to);
+
+ if (cfg.flow_below_cnt && !check_flow_below(symname, 0))
+ return 0;
+
+ argret = cfg.sh.args_enabled ?
+ lt_args_sym_exit(&cfg.sh, (char*) symname,
+ (La_regs*) inregs, outregs, &argbuf, &argdbuf) : -1;
+
+ if (cfg.sh.pipe) {
+ char buf[FIFO_MSG_MAXLEN];
+ int len;
+
+ len = lt_fifo_msym_get(&cfg, buf, FIFO_MSG_TYPE_EXIT,
+ (char*) symname, lib_to, argbuf, argdbuf);
+
+ return lt_fifo_send(&cfg, pipe_fd, buf, len);
+ }
+
+ lt_out_exit(&cfg.sh, symname, lib_from,
+ argbuf, argdbuf);
+
+ cfg.sh.indent_depth--;
+
+ if (!argret) {
+ free(argbuf);
+
+ if (cfg.sh.args_detailed && (*argdbuf))
+ free(argdbuf);
+ }
+
+ return 0;
+}
+
+static int check_pid()
+{
+ pid_t pid = getpid();
+
+ PRINT_VERBOSE(cfg.sh.verbose, 1, "tid = %d, cfg tid = %d\n",
+ pid, cfg.sh.pid);
+
+ if (pid != cfg.sh.pid)
+ return -1;
+
+ return 0;
+}
+
+#define CHECK_PID(ret) \
+do { \
+ if (cfg.sh.not_follow_fork && \
+ check_pid()) \
+ return ret; \
+} while(0)
+
+unsigned int la_version(unsigned int v)
+{
+ return v;
+}
+
+unsigned int la_objopen(struct link_map *l, Lmid_t a, uintptr_t *cookie)
+{
+ char *name = l->l_name;
+
+ if (!cfg.init_ok)
+ return 0;
+
+ if (!name)
+ return 0;
+
+ /* executable itself */
+ if (!(*name))
+ return LA_FLG_BINDTO | LA_FLG_BINDFROM;
+
+ /* audit all as default */
+ if ((!cfg.libs_to_cnt) &&
+ (!cfg.libs_from_cnt) &&
+ (!cfg.libs_both_cnt))
+ return LA_FLG_BINDTO | LA_FLG_BINDFROM;
+
+ if (check_names(name, cfg.libs_to))
+ return LA_FLG_BINDTO;
+
+ if (check_names(name, cfg.libs_from))
+ return LA_FLG_BINDFROM;
+
+ if (check_names(name, cfg.libs_both))
+ return LA_FLG_BINDTO | LA_FLG_BINDFROM;
+
+ /* wrong library name specified ? */
+ return 0;
+}
+
+static unsigned int la_symbind(const char *symname)
+{
+ unsigned int flags = 0;
+
+ if (cfg.symbols_cnt) {
+ flags = LA_SYMB_NOPLTENTER;
+ if (check_names((char*) symname, cfg.symbols))
+ flags = 0;
+ }
+
+ return flags;
+}
+
+void la_activity(uintptr_t *cookie, unsigned int act)
+{
+ PRINT_VERBOSE(cfg.sh.verbose, 2, "entry\n");
+}
+
+char* la_objsearch(const char *name, uintptr_t *cookie, unsigned int flag)
+{
+ if (flag == LA_SER_ORIG)
+ return (char*) name;
+
+ return lt_objsearch(&cfg, name, cookie, flag);
+}
+
+void la_preinit(uintptr_t *__cookie)
+{
+ PRINT_VERBOSE(cfg.sh.verbose, 2, "entry\n");
+}
+
+unsigned int la_objclose(uintptr_t *__cookie)
+{
+ PRINT_VERBOSE(cfg.sh.verbose, 2, "entry\n");
+ return 0;
+}
+
+uintptr_t la_symbind32(Elf32_Sym *sym, unsigned int ndx, uintptr_t *refcook,
+ uintptr_t *defcook, unsigned int *flags, const char *symname)
+{
+ *flags = la_symbind(symname);
+ return sym->st_value;
+}
+
+uintptr_t la_symbind64(Elf64_Sym *sym, unsigned int ndx, uintptr_t *refcook,
+ uintptr_t *defcook, unsigned int *flags, const char *symname)
+{
+ *flags = la_symbind(symname);
+ return sym->st_value;
+}
+
+ElfW(Addr)
+pltenter(ElfW(Sym) *sym, unsigned int ndx, uintptr_t *refcook,
+ uintptr_t *defcook, La_regs *regs, unsigned int *flags,
+ const char *symname, long int *framesizep)
+{
+ struct link_map *lr = (struct link_map*) *refcook;
+ struct link_map *ld = (struct link_map*) *defcook;
+
+ CHECK_PID(sym->st_value);
+
+ sym_entry(symname, lr ? lr->l_name : NULL, ld ? ld->l_name : NULL, regs);
+ *framesizep = cfg.sh.framesize;
+ return sym->st_value;
+}
+
+unsigned int pltexit(ElfW(Sym) *sym, unsigned int ndx, uintptr_t *refcook,
+ uintptr_t *defcook, const La_regs *inregs, La_retval *outregs,
+ const char *symname)
+{
+ struct link_map *lr = (struct link_map*) *refcook;
+ struct link_map *ld = (struct link_map*) *defcook;
+
+ CHECK_PID(0);
+
+ sym_exit(symname, lr ? lr->l_name : NULL, ld ? ld->l_name : NULL, inregs, outregs);
+ return 0;
+}
diff --git a/src/audit.h b/src/audit.h
new file mode 100644
index 0000000..edb72d3
--- /dev/null
+++ b/src/audit.h
@@ -0,0 +1,102 @@
+/*
+ Copyright (C) 2008, 2009 Jiri Olsa <olsajiri@gmail.com>
+
+ This file is part of the latrace.
+
+ The latrace 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 3 of the License, or
+ (at your option) any later version.
+
+ The latrace 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 the latrace (file COPYING). If not, see
+ <http://www.gnu.org/licenses/>.
+*/
+
+
+#ifndef AUDIT_H
+#define AUDIT_H
+
+#include <link.h>
+
+/* stolen from glibc :) */
+#ifdef __i386__
+# define pltenter la_i86_gnu_pltenter
+# define pltexit la_i86_gnu_pltexit
+# define La_regs La_i86_regs
+# define La_retval La_i86_retval
+# define int_retval lrv_eax
+#elif defined __x86_64__
+# define pltenter la_x86_64_gnu_pltenter
+# define pltexit la_x86_64_gnu_pltexit
+# define La_regs La_x86_64_regs
+# define La_retval La_x86_64_retval
+# define int_retval lrv_rax
+#elif defined __arm__
+# define pltenter la_arm_gnu_pltenter
+# define pltexit la_arm_gnu_pltexit
+# define La_regs La_arm_regs
+# define La_retval La_arm_retval
+# define int_retval lrv_reg[0]
+#elif defined __powerpc__ && __WORDSIZE == 32
+# define pltenter la_ppc32_gnu_pltenter
+# define pltexit la_ppc32_gnu_pltexit
+# define La_regs La_ppc32_regs
+# define La_retval La_ppc32_retval
+# define int_retval lrv_r3
+#elif defined __powerpc__ && __WORDSIZE == 64
+# define pltenter la_ppc64_gnu_pltenter
+# define pltexit la_ppc64_gnu_pltexit
+# define La_regs La_ppc64_regs
+# define La_retval La_ppc64_retval
+# define int_retval lrv_r3
+#elif defined __sh__
+# define pltenter la_sh_gnu_pltenter
+# define pltexit la_sh_gnu_pltexit
+# define La_regs La_sh_regs
+# define La_retval La_sh_retval
+# define int_retval lrv_r0
+#elif defined __alpha__
+# define pltenter la_alpha_gnu_pltenter
+# define pltexit la_alpha_gnu_pltexit
+# define La_regs La_alpha_regs
+# define La_retval La_alpha_retval
+# define int_retval lrv_r0
+#elif defined __s390__ && __WORDSIZE == 32
+# define pltenter la_s390_32_gnu_pltenter
+# define pltexit la_s390_32_gnu_pltexit
+# define La_regs La_s390_32_regs
+# define La_retval La_s390_32_retval
+# define int_retval lrv_r2
+#elif defined __s390__ && __WORDSIZE == 64
+# define pltenter la_s390_64_gnu_pltenter
+# define pltexit la_s390_64_gnu_pltexit
+# define La_regs La_s390_64_regs
+# define La_retval La_s390_64_retval
+# define int_retval lrv_r2
+#elif defined __ia64__
+# define pltenter la_ia64_gnu_pltenter
+# define pltexit la_ia64_gnu_pltexit
+# define La_regs La_ia64_regs
+# define La_retval La_ia64_retval
+# define int_retval lrv_r8
+#elif defined __sparc__ && __WORDSIZE == 32
+# define pltenter la_sparc32_gnu_pltenter
+# define pltexit la_sparc32_gnu_pltexit
+# define La_regs La_sparc32_regs
+# define La_retval La_sparc32_retval
+# define int_retval lrv_reg[0]
+#elif defined __sparc__ && __WORDSIZE == 64
+# define pltenter la_sparc64_gnu_pltenter
+# define pltexit la_sparc64_gnu_pltexit
+# define La_regs La_sparc64_regs
+# define La_retval La_sparc64_retval
+# define int_retval lrv_reg[0]
+#endif
+
+#endif // !AUDIT_H
diff --git a/src/autoconf.h.in b/src/autoconf.h.in
new file mode 100644
index 0000000..efcc490
--- /dev/null
+++ b/src/autoconf.h.in
@@ -0,0 +1,36 @@
+/*
+ Copyright (C) 2008, 2009 Jiri Olsa <olsajiri@gmail.com>
+
+ This file is part of the latrace.
+
+ The latrace 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 3 of the License, or
+ (at your option) any later version.
+
+ The latrace 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 the latrace (file COPYING). If not, see
+ <http://www.gnu.org/licenses/>.
+*/
+
+
+#ifndef AUTOCONF_H
+
+/* Temporary directory prefix. */
+#undef CONFIG_LT_CONFIG
+
+/* Version define. */
+#undef LT_VER
+
+/* x86 define. */
+#undef LT_ARCH_X86
+
+/* x86_64 define. */
+#undef LT_ARCH_X86_64
+
+#endif
diff --git a/src/autoconf.make.in b/src/autoconf.make.in
new file mode 100644
index 0000000..c162165
--- /dev/null
+++ b/src/autoconf.make.in
@@ -0,0 +1,42 @@
+# Copyright (C) 2008, 2009 Jiri Olsa <olsajiri@gmail.com>
+#
+# This file is part of the latrace.
+#
+# The latrace 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 3 of the License, or
+# (at your option) any later version.
+#
+# The latrace 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 the latrace (file COPYING). If not, see
+# <http://www.gnu.org/licenses/>.
+
+
+# @configure_input@
+
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+bindir = @bindir@
+libdir = @libdir@
+datadir = @datadir@
+mandir = @mandir@
+datarootdir = @datarootdir@
+sysconfdir = @sysconfdir@
+
+RM = rm
+FIND = find
+CC = @CC@
+LEX = @LEX@
+YACC = @YACC@
+CPPFLAGS = @CPPFLAGS@
+CFLAGS = @CFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+
+CONFIG_SYSDEP_DIR = @CONFIG_SYSDEP_DIR@
+LT_VER = @LT_VER@
diff --git a/src/config.c b/src/config.c
new file mode 100644
index 0000000..42d28b2
--- /dev/null
+++ b/src/config.c
@@ -0,0 +1,293 @@
+/*
+ Copyright (C) 2008, 2009 Jiri Olsa <olsajiri@gmail.com>
+
+ This file is part of the latrace.
+
+ The latrace 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 3 of the License, or
+ (at your option) any later version.
+
+ The latrace 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 the latrace (file COPYING). If not, see
+ <http://www.gnu.org/licenses/>.
+*/
+
+
+#include <string.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "config.h"
+
+static void usage() NORETURN;
+static void usage()
+{
+ printf("usage: latrace [-ltfsbcCpADaoyIiBdvTFELVh] command [arg ... ]\n\n");
+ printf(" -l, --libs lib1,lib2... audit from and to lib1, lib2 ...\n");
+ printf(" -t, --libs-to lib1,lib2... audit to lib1, lib2 ...\n");
+ printf(" -f, --libs-from lib1,lib2... audit from lib1, lib2 ...\n");
+ printf(" -s, --sym sym1,sym2... audit symbols sym1, sym2 ... \n");
+ printf(" -L, --lib-subst s1,s2... objsearch LD_AUDIT interface (see man page)\n");
+ printf("\n");
+ printf(" -c, --counts display statistics counts of symbols\n");
+ printf(" -C, --sort-counts stat implies -c, plus sort the statistics by 'stat':\n");
+ printf(" time,per,call,ucall,lib,sym (default is call)\n");
+ printf(" -p, --pipe use pipe to latrace process to send audit data\n");
+ printf(" latrace app is then the one displaying the output\n");
+ printf("\n");
+ printf(" -A, --enable-args enable arguments output (definitions from /etc/latrace.conf)\n");
+ printf(" -D, --detail-args display struct arguments in more detail\n");
+ printf(" -a, --args file arguments definition file, implies \'-A\'\n");
+ printf("\n");
+ printf(" -y, --framesize number framesize for storing the stack before pltexit (default 1000)\n");
+ printf(" -F, --not-follow-fork dont follow fork calls - childs\n");
+ printf(" -E, --not-follow-exec dont follow exec calls\n");
+ printf("\n");
+ printf(" -b, --flow-below sym1,sym2... display flow only for sym1, sym2 ... \n");
+ printf(" -I, --no-indent-sym do not indent symbols based on the their stack depth\n");
+ printf(" -i, --indent-sym indent_size specify indent size specification\n");
+ printf(" -B, --braces allways display braces {}\n");
+ printf(" -d, --demangle run the symbol name throught the C++ demangler\n");
+ printf(" -T, --hide-tid dont display thread id\n");
+ printf(" -o, --output file store output to file\n");
+ printf("\n");
+ printf(" -v, --verbose verbose output\n");
+ printf(" -V, --version display version\n");
+ printf(" -h, --help display help\n");
+ printf("\n");
+
+ exit(1);
+}
+
+static void version() NORETURN;
+static void version()
+{
+ printf("latrace version " LT_VER "\n");
+ exit(0);
+}
+
+static struct lt_config_tv counts_sort[] = {
+ { .type = LT_CSORT_TIME, .name = "time" },
+ { .type = LT_CSORT_PERCENT, .name = "per" },
+ { .type = LT_CSORT_CALL, .name = "call" },
+ { .type = LT_CSORT_UCALL, .name = "ucall" },
+ { .type = LT_CSORT_LIB, .name = "lib" },
+ { .type = LT_CSORT_SYM, .name = "sym" }
+};
+
+#define COUNTS_SORT_NUM (sizeof(counts_sort)/sizeof(struct lt_config_tv))
+
+static int get_type(struct lt_config_app *cfg, struct lt_config_tv *tv,
+ int num, char *name)
+{
+ int i;
+
+ for(i = 0; i < num; i++)
+ if (!strcmp(name, tv[i].name))
+ return tv[i].type;
+
+ printf("failed to find name: %s\n", name);
+ return -1;
+}
+
+int lt_config(struct lt_config_app *cfg, int argc, char **argv)
+{
+ memset(cfg, 0, sizeof(*cfg));
+
+ /* default values settings */
+ cfg->sh.magic = LT_MAGIC;
+ cfg->sh.framesize = 1000;
+ cfg->sh.fout = stdout;
+ cfg->sh.indent_sym = 1;
+ cfg->sh.indent_size = 2;
+ cfg->sh.args_maxlen = LR_ARGS_MAXLEN;
+ cfg->sh.args_detail_maxlen = LR_ARGS_DETAIL_MAXLEN;
+ cfg->csort = LT_CSORT_CALL;
+
+ while (1) {
+ int c;
+ int option_index = 0;
+ static struct option long_options[] = {
+ {"sym", required_argument, 0, 's'},
+ {"libs", required_argument, 0, 'l'},
+ {"libs-to", required_argument, 0, 't'},
+ {"libs-from", required_argument, 0, 'f'},
+ {"no-indent-sym", no_argument, 0, 'I'},
+ {"indent-sym", required_argument, 0, 'i'},
+ {"braces", no_argument, 0, 'B'},
+ {"demangle", no_argument, 0, 'd'},
+ {"flow-below", required_argument, 0, 'b'},
+ {"counts", no_argument, 0, 'c'},
+ {"sort-counts", required_argument, 0, 'C'},
+ {"pipe", no_argument, 0, 'p'},
+ {"output", required_argument, 0, 'o'},
+ {"args", required_argument, 0, 'a'},
+ {"enable-args", required_argument, 0, 'A'},
+ {"detail-args", required_argument, 0, 'D'},
+ {"framesize", required_argument, 0, 'y'},
+ {"lib-subst", required_argument, 0, 'L'},
+ {"verbose", no_argument, 0, 'v'},
+ {"hide-tid", no_argument, 0, 'T'},
+ {"not-follow-fork", no_argument, 0, 'F'},
+ {"not-follow-exec", no_argument, 0, 'E'},
+ {"version", no_argument, 0, 'V'},
+ {"help", no_argument, 0, 'h'},
+ {0, 0, 0, 0}
+ };
+
+ c = getopt_long(argc, argv, "+s:l:t:f:vhi:BdIb:cC:y:L:po:a:ADVTFE",
+ long_options, &option_index);
+
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 'l':
+ if (strlen(optarg) > LT_LIBS_MAXSIZE)
+ return -1;
+
+ strncpy(cfg->sh.libs_both, optarg, strlen(optarg));
+ break;
+
+ case 't':
+ if (strlen(optarg) > LT_LIBS_MAXSIZE)
+ return -1;
+
+ strncpy(cfg->sh.libs_to, optarg, strlen(optarg));
+ break;
+
+ case 'f':
+ if (strlen(optarg) > LT_LIBS_MAXSIZE)
+ return -1;
+
+ strncpy(cfg->sh.libs_from, optarg, strlen(optarg));
+ break;
+
+ case 's':
+ if (strlen(optarg) > LT_SYMBOLS_MAXSIZE)
+ return -1;
+
+ strncpy(cfg->sh.symbols, optarg, strlen(optarg));
+ break;
+
+ case 'b':
+ if (strlen(optarg) > LT_SYMBOLS_MAXSIZE)
+ return -1;
+
+ strncpy(cfg->sh.flow_below, optarg, strlen(optarg));
+ break;
+
+ case 'v':
+ cfg->sh.verbose++;
+ break;
+
+ case 'T':
+ cfg->sh.hide_tid = 1;
+ break;
+
+ case 'F':
+ cfg->sh.not_follow_fork = 1;
+ break;
+
+ case 'E':
+ cfg->sh.not_follow_exec = 1;
+ break;
+
+ case 'i':
+ cfg->sh.indent_size = atoi(optarg);
+ break;
+
+ case 'B':
+ cfg->sh.braces = 1;
+ break;
+
+ case 'd':
+ cfg->sh.demangle = 1;
+ break;
+
+ case 'I':
+ cfg->sh.indent_sym = 0;
+ break;
+
+ case 'y':
+ cfg->sh.framesize = atoi(optarg);
+ break;
+
+ case 'L':
+ if (strlen(optarg) > LT_SYMBOLS_MAXSIZE)
+ return -1;
+
+ strncpy(cfg->sh.libs_subst, optarg, strlen(optarg));
+ break;
+
+ case 'C':
+
+ if (-1 == (cfg->csort = get_type(cfg, counts_sort, COUNTS_SORT_NUM, optarg)))
+ usage();
+ /* falling through */
+ case 'c':
+ cfg->sh.counts = 1;
+ /* falling through */
+ case 'p':
+ cfg->sh.pipe = 1;
+ break;
+
+ case 'a':
+ strcpy(cfg->sh.args_def, optarg);
+ /* falling through */
+ case 'A':
+ cfg->sh.args_enabled = 1;
+ break;
+
+ case 'D':
+ cfg->sh.args_detailed = 1;
+ break;
+
+ case 'o':
+ strcpy(cfg->sh.output, optarg);
+ break;
+
+ case 'V':
+ version();
+ break;
+
+ case 'h':
+ usage();
+ break;
+
+ default:
+ printf("unknown option '%c'", c);
+ } // switch (c)
+ } // while(1)
+
+ if (optind < argc) {
+ int i_arg = 1;
+ cfg->prog = argv[optind++];
+ cfg->arg[0] = cfg->prog;
+
+ while ((optind < argc) && (i_arg < LT_NUM_ARG)) {
+ cfg->arg[i_arg++] = argv[optind++];
+ }
+ cfg->arg_num = i_arg;
+ }
+
+ if (!cfg->prog) {
+ printf("failed: no program specified\n");
+ usage();
+ }
+
+ if ((cfg->sh.pipe) && (*cfg->sh.output) &&
+ (NULL == (cfg->sh.fout = fopen(cfg->sh.output, "w")))) {
+ printf("failed to fopen output file %s\n", cfg->sh.output);
+ usage();
+ }
+
+ return 0;
+}
diff --git a/src/config.h b/src/config.h
new file mode 100644
index 0000000..680ab07
--- /dev/null
+++ b/src/config.h
@@ -0,0 +1,417 @@
+/*
+ Copyright (C) 2008, 2009 Jiri Olsa <olsajiri@gmail.com>
+
+ This file is part of the latrace.
+
+ The latrace 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 3 of the License, or
+ (at your option) any later version.
+
+ The latrace 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 the latrace (file COPYING). If not, see
+ <http://www.gnu.org/licenses/>.
+*/
+
+
+#ifndef CONFIG_H
+#define CONFIG_H
+
+#include <stdio.h>
+#include <search.h>
+#include <sys/time.h>
+#include <sys/syscall.h>
+#include <stdint.h>
+#include <unistd.h>
+
+#include "audit.h"
+#include "list.h"
+#include "autoconf.h"
+
+#ifdef __GNUC__
+#define NORETURN __attribute__((__noreturn__))
+#else
+#define NORETURN
+#ifndef __attribute__
+#define __attribute__(x)
+#endif
+#endif
+
+/* TODO put this to autoconf.h */
+#define LT_VERSION_MINOR 1
+#define LT_VERSION_MAJOR 0
+#define LT_VERSION (LT_VERSION_MAJOR*256 + LT_VERSION_MINOR)
+
+#define LT_NAMES_MAX 50
+#define LT_NAMES_SEP ','
+
+#define LT_SYM_HMAX 1000
+
+#define LT_ARGS_DEF_STRUCT_NUM 1000
+#define LT_ARGS_DEF_TYPEDEF_NUM 1000
+#define LT_ARGS_DEF_ENUM_NUM 1000
+
+
+enum {
+ LT_CSORT_TIME = 0,
+ LT_CSORT_PERCENT,
+ LT_CSORT_CALL,
+ LT_CSORT_UCALL,
+ LT_CSORT_LIB,
+ LT_CSORT_SYM
+};
+
+struct lt_config_tv {
+ int type;
+ char *name;
+};
+
+struct lt_config_shared {
+#define LT_MAGIC ((LT_VERSION << 16) + 0xdead)
+ unsigned int magic;
+
+#define LT_LIBS_MAXSIZE 200
+ char libs_to[LT_LIBS_MAXSIZE];
+ char libs_both[LT_LIBS_MAXSIZE];
+ char libs_from[LT_LIBS_MAXSIZE];
+
+ char libs_subst[LT_LIBS_MAXSIZE];
+
+#define LT_SYMBOLS_MAXSIZE 200
+ char symbols[LT_SYMBOLS_MAXSIZE];
+
+ char flow_below[LT_SYMBOLS_MAXSIZE];
+
+#define LT_MAXFILE 200
+ char output[LT_MAXFILE];
+ FILE *fout;
+
+ char args_def[LT_MAXFILE];
+ char args_enabled;
+ char args_detailed;
+#define LR_ARGS_MAXLEN 1000
+ int args_maxlen;
+#define LR_ARGS_DETAIL_MAXLEN 1000
+ int args_detail_maxlen;
+#define LT_ARGS_TAB 10000
+ struct hsearch_data args_tab;
+
+ int verbose;
+ int debug;
+ int indent_sym;
+ int indent_size;
+ int braces;
+ int demangle;
+ int counts;
+ int pipe;
+ int hide_tid;
+ int not_follow_exec;
+ int not_follow_fork;
+ unsigned int framesize;
+
+ /* for 'not_follow_fork' */
+ pid_t pid;
+
+ /* used by both app and lib */
+ unsigned int indent_depth;
+};
+
+struct lt_config_app {
+ struct lt_config_shared sh;
+
+ char *prog;
+#define LT_NUM_ARG 500
+ char *arg[LT_NUM_ARG];
+ int arg_num;
+
+ int csort;
+
+ struct lt_thread *threads;
+ struct lt_thread *iter;
+};
+
+enum {
+ LT_OS_PATH = 1, /* '=' */
+ LT_OS_PTN, /* '%' */
+ LT_OS_PTN2PATH, /* '~' */
+};
+
+struct lt_objsearch {
+ int type;
+ char *src;
+ char *dst;
+};
+
+struct lt_config_audit {
+ struct lt_config_shared sh;
+
+ char *libs_to[LT_NAMES_MAX];
+ int libs_to_cnt;
+
+ char *libs_from[LT_NAMES_MAX];
+ int libs_from_cnt;
+
+ char *libs_both[LT_NAMES_MAX];
+ int libs_both_cnt;
+
+ char *symbols[LT_NAMES_MAX];
+ int symbols_cnt;
+
+ char *flow_below[LT_NAMES_MAX];
+ int flow_below_cnt;
+
+ struct lt_objsearch subst[LT_NAMES_MAX];
+ int subst_cnt;
+
+ char *dir;
+ int init_ok;
+};
+
+#define FIFO_MSG_MAXLEN 2000
+
+/* common message data */
+struct lt_fifo_mbase {
+#define FIFO_MSG_TYPE_ENTRY 1
+#define FIFO_MSG_TYPE_EXIT 2
+ uint32_t type;
+ struct timeval tv;
+ pid_t tid;
+ int len; /* the rest of the message size */
+};
+
+/* symbol message */
+struct lt_fifo_msym {
+ struct lt_fifo_mbase h;
+
+ int sym;
+ int lib;
+ int arg;
+ int argd;
+ char data[0];
+};
+
+struct lt_stats_sym {
+ char *name;
+ char *sym;
+ char *lib;
+
+ struct timeval tv_cur;
+ struct timeval tv_all;
+
+ unsigned int call;
+
+ /* post mortem statistics */
+ float percent;
+ unsigned int usec_call;
+};
+
+struct lt_thread {
+ /* global */
+ int fifo_fd;
+ pid_t tid;
+
+ /* start/stop time */
+ struct timeval tv_start;
+ struct timeval tv_stop;
+
+ /* symbol statistics */
+ struct lt_stats_sym **sym_array;
+ struct hsearch_data sym_htab;
+ unsigned int sym_cnt;
+ unsigned int sym_max;
+
+ struct lt_thread *next;
+};
+
+enum {
+ LT_ARGS_DTYPE_POD = 1,
+ LT_ARGS_DTYPE_STRUCT,
+};
+
+enum {
+ LT_ARGS_TYPEID_VOID = 1,
+ LT_ARGS_TYPEID_SHORT,
+ LT_ARGS_TYPEID_USHORT,
+ LT_ARGS_TYPEID_INT,
+ LT_ARGS_TYPEID_UINT,
+ LT_ARGS_TYPEID_LONG,
+ LT_ARGS_TYPEID_ULONG,
+ LT_ARGS_TYPEID_CHAR,
+ LT_ARGS_TYPEID_UCHAR,
+ LT_ARGS_TYPEID_LLONG,
+ LT_ARGS_TYPEID_ULLONG,
+ LT_ARGS_TYPEID_DOUBLE,
+ LT_ARGS_TYPEID_FLOAT,
+
+ LT_ARGS_TYPEID_CUSTOM = 1000
+};
+
+struct lt_enum_elem {
+ char *name;
+ long val;
+ int undef;
+ struct lt_list_head list;
+};
+
+struct lt_enum {
+ char *name;
+ int cnt;
+ struct lt_enum_elem *elems;
+};
+
+struct lt_arg {
+ /* argument type */
+ int dtype;
+
+ /* argument type properties */
+ int type_id;
+ u_int type_len;
+ char *type_name;
+
+ /* argument value properties */
+ int pointer;
+ char *name;
+
+ /* for structures only */
+ int mmbcnt;
+
+ /* architecture dependent */
+ void *arch;
+
+ /* enum record */
+ struct lt_enum *en;
+
+ /* struct arguments head */
+ struct lt_list_head *args_head;
+ /* nested arguments list if present */
+ struct lt_list_head args_list;
+};
+
+struct lt_args_sym {
+ char *name;
+
+ int argcnt;
+#define LT_ARGS_RET 0
+ struct lt_arg **args;
+};
+
+struct lt_args_include {
+ FILE *yyin;
+ void *yybuf;
+ char *file;
+ int lineno;
+};
+
+/* used in lt_args_cb_struct for argument type */
+enum {
+ LT_ARGS_STRUCT_ITSELF = 0,
+ LT_ARGS_STRUCT_ARG
+};
+
+struct lt_args_data {
+ int arglen;
+
+ /* function arguments */
+ char *args_buf;
+ int args_len;
+ int args_totlen;
+
+ /* detailed structs */
+ char *argsd_buf;
+ int argsd_len;
+ int argsd_totlen;
+};
+
+/* global */
+int lt_config(struct lt_config_app *cfg, int argc, char **argv);
+int lt_run(struct lt_config_app *cfg);
+
+/* fifo */
+int lt_fifo_create(struct lt_config_audit *cfg, char *dir);
+int lt_fifo_open(struct lt_config_app *cfg, char *name);
+int lt_fifo_send(struct lt_config_audit *cfg, int fd, char *buf, int len);
+int lt_fifo_recv(struct lt_config_app *cfg, struct lt_thread *t,
+ void *buf, int bufsize);
+int lt_fifo_msym_get(struct lt_config_audit *cfg, char *buf, int type,
+ char *symname, char *libto, char *arg, char *argd);
+
+/* counts */
+int lt_stats_init(struct lt_config_app *cfg);
+int lt_stats_sym(struct lt_config_app *cfg, struct lt_thread *t,
+ struct lt_fifo_msym* m);
+int lt_stats_alloc(struct lt_config_app *cfg, struct lt_thread *t);
+int lt_stats_show(struct lt_config_app *cfg);
+
+/* thread */
+struct lt_thread *lt_thread_add(struct lt_config_app *cfg, int fd, pid_t pid);
+struct lt_thread *lt_thread_first(struct lt_config_app *cfg);
+struct lt_thread *lt_thread_next(struct lt_config_app *cfg);
+
+/* arguments */
+int lt_args_init(struct lt_config_shared *cfg);
+int lt_args_sym_entry(struct lt_config_shared *cfg, char *sym, La_regs *regs,
+ char **argbuf, char **argdbuf);
+int lt_args_sym_exit(struct lt_config_shared *cfg, char *sym, La_regs *inregs,
+ La_retval *outregs, char **argbuf, char **argdbuf);
+int lt_args_add_enum(struct lt_config_shared *cfg, char *name,
+ struct lt_list_head *h);
+struct lt_enum_elem* lt_args_get_enum(struct lt_config_shared *cfg, char *name, char *val);
+int lt_args_add_struct(struct lt_config_shared *cfg, char *type_name,
+ struct lt_list_head *h);
+int lt_args_add_sym(struct lt_config_shared *cfg, struct lt_arg *sym,
+ struct lt_list_head *h);
+int lt_args_add_typedef(struct lt_config_shared *cfg, char *base,
+ char *new, int pointer);
+int lt_args_buf_open(struct lt_config_shared *cfg, char *file);
+int lt_args_buf_close(struct lt_config_shared *cfg);
+struct lt_arg* lt_args_getarg(struct lt_config_shared *cfg, char *type,
+ char *name, int pointer, int create, char *enum_name);
+int lt_args_cb_arg(struct lt_config_shared *cfg, struct lt_arg *arg,
+ void *pval, struct lt_args_data *data, int last,
+ int dspname);
+int lt_args_cb_struct(struct lt_config_shared *cfg, int type,
+ struct lt_arg *arg, void *pval,
+ struct lt_args_data *data, int last);
+
+/* output */
+int lt_out_entry(struct lt_config_shared *cfg, const char *symname,
+ char *lib_to, char *argbuf, char *argdbuf);
+int lt_out_exit(struct lt_config_shared *cfg, const char *symname,
+ char *lib_to, char *argbuf, char *argdbuf);
+
+/* stack handling */
+int lt_stack_process(struct lt_config_shared *cfg, struct lt_args_sym *asym,
+ La_regs *regs, struct lt_args_data *data);
+int lt_stack_process_ret(struct lt_config_shared *cfg, struct lt_args_sym *asym,
+ La_retval *regs, struct lt_args_data *data);
+
+/* la_objsearch */
+int lt_objsearch_init(struct lt_config_audit *cfg, char **ptr, int cnt);
+char* lt_objsearch(struct lt_config_audit *cfg, const char *name,
+ uintptr_t *cookie, unsigned int flag);
+
+#define PRINT(fmt, args...) \
+do { \
+ char lpbuf[1024]; \
+ sprintf(lpbuf, "[%d %s:%05d] %s", \
+ (pid_t) syscall(SYS_gettid), \
+ __FUNCTION__, \
+ __LINE__, \
+ fmt); \
+ printf(lpbuf, ## args); \
+} while(0)
+
+#define PRINT_VERBOSE(verbose, cond, fmt, args...) \
+do { \
+ if (cond > verbose) \
+ break; \
+ PRINT(fmt, ## args); \
+} while(0)
+
+
+#endif // !CONFIG_H
diff --git a/src/fifo.c b/src/fifo.c
new file mode 100644
index 0000000..08aad32
--- /dev/null
+++ b/src/fifo.c
@@ -0,0 +1,150 @@
+/*
+ Copyright (C) 2008, 2009 Jiri Olsa <olsajiri@gmail.com>
+
+ This file is part of the latrace.
+
+ The latrace 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 3 of the License, or
+ (at your option) any later version.
+
+ The latrace 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 the latrace (file COPYING). If not, see
+ <http://www.gnu.org/licenses/>.
+*/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <unistd.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+
+#include "config.h"
+
+
+int lt_fifo_create(struct lt_config_audit *cfg, char *dir)
+{
+ int fd;
+ char fifo[100];
+
+ sprintf(fifo, "%s/fifo-%d", dir, (pid_t) syscall(SYS_gettid));
+
+ if (-1 == mkfifo(fifo, 0666)) {
+ perror("mkfifo failed");
+ return -1;
+ }
+
+ if (-1 == (fd = open(fifo, O_WRONLY))) {
+ perror("open fifo failed");
+ return -1;
+ }
+
+ return fd;
+}
+
+int lt_fifo_open(struct lt_config_app *cfg, char *name)
+{
+ int fd;
+
+ if (-1 == (fd = open(name, O_RDONLY)))
+ perror("open fifo failed");
+
+ PRINT_VERBOSE(cfg->sh.verbose, 1, "pipe openned fd: %d\n", fd);
+ return fd;
+}
+
+int lt_fifo_send(struct lt_config_audit *cfg, int fd, char *buf, int len)
+{
+ static unsigned int written = 0;
+
+ if (-1 == write(fd, buf, len)) {
+ perror("write failed");
+ return -1;
+ }
+
+ written += len;
+ PRINT_VERBOSE(cfg->sh.verbose, 1, "sending %d, total %u\n",
+ len, written);
+ return 0;
+}
+
+int lt_fifo_recv(struct lt_config_app *cfg, struct lt_thread *t, void *buf,
+ int bufsize)
+{
+ static unsigned int red = 0;
+ ssize_t size;
+ struct lt_fifo_mbase *h = buf;
+
+ if (-1 == (size = read(t->fifo_fd, h, sizeof(struct lt_fifo_mbase)))) {
+ perror("read failed");
+ return -1;
+ }
+
+ if (size == 0)
+ return -1;
+
+ red += size;
+
+ PRINT_VERBOSE(cfg->sh.verbose, 1, "received %d\n", h->len);
+
+ if ((size + h->len) > bufsize) {
+ printf("thread %d - buffer max size reached\n", t->tid);
+ return -1;
+ }
+
+ if (-1 == (size = read(t->fifo_fd, buf + sizeof(*h), h->len))) {
+ perror("read failed");
+ return -1;
+ }
+
+ red += size;
+
+ PRINT_VERBOSE(cfg->sh.verbose, 1, "received %d, total %u\n",
+ size + sizeof(*h), red);
+ return 0;
+}
+
+int lt_fifo_msym_get(struct lt_config_audit *cfg, char *buf, int type,
+ char *symname, char *libto, char *arg, char *argd)
+{
+ struct lt_fifo_msym *m = (struct lt_fifo_msym*) buf;
+ int len_data, len = sizeof(struct lt_fifo_msym);
+
+ /* TODO need proper buf size checking */
+ m->h.type = type;
+ m->h.tid = (pid_t) syscall(SYS_gettid);
+ gettimeofday(&m->h.tv, NULL);
+
+ m->sym = 0;
+ m->lib = strlen(symname);
+ m->arg = m->lib + strlen(libto) + 1;
+ m->argd = m->arg + strlen(arg) + 1;
+
+ len_data = sprintf(m->data, "%s %s %s %s", symname, libto, arg, argd);
+
+ m->data[m->lib++] = 0x0;
+ m->data[m->arg++] = 0x0;
+ m->data[m->argd++] = 0x0;
+ m->data[len_data++] = 0x0;
+
+ len += len_data;
+ m->h.len = len_data + (sizeof(*m) - sizeof(struct lt_fifo_mbase));
+
+ PRINT_VERBOSE(cfg->sh.verbose, 1, "sending data %d <%s> <%s> <%s> <%s>\n",
+ m->h.len,
+ m->data + m->sym,
+ m->data + m->lib,
+ m->data + m->arg,
+ m->data + m->argd);
+ return len;
+}
diff --git a/src/latrace.c b/src/latrace.c
new file mode 100644
index 0000000..9527fcf
--- /dev/null
+++ b/src/latrace.c
@@ -0,0 +1,45 @@
+/*
+ Copyright (C) 2008, 2009 Jiri Olsa <olsajiri@gmail.com>
+
+ This file is part of the latrace.
+
+ The latrace 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 3 of the License, or
+ (at your option) any later version.
+
+ The latrace 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 the latrace (file COPYING). If not, see
+ <http://www.gnu.org/licenses/>.
+*/
+
+
+#include <stdio.h>
+
+#include "config.h"
+
+
+static struct lt_config_app cfg;
+
+
+int main(int argc, char **argv)
+{
+ if (-1 == lt_config(&cfg, argc, argv))
+ return -1;
+
+ if (-1 == lt_run(&cfg))
+ return -1;
+
+ if ((cfg.sh.pipe) && (*cfg.sh.output))
+ fclose(cfg.sh.fout);
+
+ if (cfg.sh.counts)
+ lt_stats_show(&cfg);
+
+ return 0;
+}
diff --git a/src/list.h b/src/list.h
new file mode 100644
index 0000000..d54f67b
--- /dev/null
+++ b/src/list.h
@@ -0,0 +1,103 @@
+/*
+ Copyright (c) 2003-2006 Thomas Graf <tgraf@suug.ch>
+
+ Taken from the libnl project and customized to fit for latrace.
+ Released undder following license notice.
+
+ Copyright (C) 2008, 2009 Jiri Olsa <olsajiri@gmail.com>
+
+ This file is part of the latrace.
+
+ The latrace 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 3 of the License, or
+ (at your option) any later version.
+
+ The latrace 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 the latrace (file COPYING). If not, see
+ <http://www.gnu.org/licenses/>.
+*/
+
+
+#ifndef LIST_H
+#define LIST_H
+
+struct lt_list_head
+{
+ struct lt_list_head * next;
+ struct lt_list_head * prev;
+};
+
+
+static inline void __lt_list_add(struct lt_list_head *obj,
+ struct lt_list_head *prev,
+ struct lt_list_head *next)
+{
+ prev->next = obj;
+ obj->prev = prev;
+ next->prev = obj;
+ obj->next = next;
+}
+
+static inline void lt_list_add_tail(struct lt_list_head *obj,
+ struct lt_list_head *head)
+{
+ __lt_list_add(obj, head->prev, head);
+}
+
+static inline void lt_list_add_head(struct lt_list_head *obj,
+ struct lt_list_head *head)
+{
+ __lt_list_add(obj, head, head->next);
+}
+
+static inline void lt_list_del(struct lt_list_head *obj)
+{
+ obj->next->prev = obj->prev;
+ obj->prev->next = obj->next;
+}
+
+static inline int lt_list_empty(struct lt_list_head *head)
+{
+ return head->next == head;
+}
+
+#define lt_container_of(ptr, type, member) ({ \
+ const typeof( ((type *)0)->member ) *__mptr = (ptr); \
+ (type *)( (char *)__mptr - ((size_t) &((type *)0)->member));})
+
+#define lt_list_entry(ptr, type, member) \
+ lt_container_of(ptr, type, member)
+
+#define lt_list_at_tail(pos, head, member) \
+ ((pos)->member.next == (head))
+
+#define lt_list_at_head(pos, head, member) \
+ ((pos)->member.prev == (head))
+
+#define LT_LIST_HEAD(name) \
+ struct lt_list_head name = { &(name), &(name) }
+
+#define lt_list_first_entry(head, type, member) \
+ lt_list_entry((head)->next, type, member)
+
+#define lt_list_for_each_entry(pos, head, member) \
+ for (pos = lt_list_entry((head)->next, typeof(*pos), member); \
+ &(pos)->member != (head); \
+ (pos) = lt_list_entry((pos)->member.next, typeof(*(pos)), member))
+
+#define lt_list_for_each_entry_safe(pos, n, head, member) \
+ for (pos = lt_list_entry((head)->next, typeof(*pos), member), \
+ n = lt_list_entry(pos->member.next, typeof(*pos), member); \
+ &(pos)->member != (head); \
+ pos = n, n = lt_list_entry(n->member.next, typeof(*n), member))
+
+#define lt_init_list_head(head) \
+ do { (head)->next = (head); (head)->prev = (head); } while (0)
+
+#endif
diff --git a/src/objsearch.c b/src/objsearch.c
new file mode 100644
index 0000000..ae0823f
--- /dev/null
+++ b/src/objsearch.c
@@ -0,0 +1,192 @@
+/*
+ Copyright (C) 2008, 2009 Jiri Olsa <olsajiri@gmail.com>
+
+ This file is part of the latrace.
+
+ The latrace 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 3 of the License, or
+ (at your option) any later version.
+
+ The latrace 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 the latrace (file COPYING). If not, see
+ <http://www.gnu.org/licenses/>.
+*/
+
+
+#include <string.h>
+
+#include "config.h"
+
+
+static int add_subst(struct lt_config_audit *cfg, char *subst)
+{
+ struct lt_objsearch *s;
+ char *dst, *src = subst;
+ int type;
+
+ if (cfg->subst_cnt == LT_NAMES_MAX)
+ return -1;
+
+ do {
+ if ((dst = strchr(subst, '='))) {
+ type = LT_OS_PATH;
+ break;
+ }
+
+ if ((dst = strchr(subst, '%'))) {
+ type = LT_OS_PTN;
+ break;
+ }
+
+ if ((dst = strchr(subst, '~'))) {
+ type = LT_OS_PTN2PATH;
+ break;
+ }
+
+ } while(0);
+
+ if (!dst)
+ return -1;
+
+ *dst++ = 0x0;
+
+ PRINT_VERBOSE(cfg->sh.verbose, 2, "adding subst type %d, src [%s], dst [%s]\n",
+ type, src, dst);
+
+ s = &cfg->subst[cfg->subst_cnt++];
+ s->type = type;
+ s->src = src;
+ s->dst = dst;
+
+ return 0;
+}
+
+/*
+ Comparing src with the name, if matched
+ replace the name with dst.
+
+ name -> /lib/krava.so
+ src -> /lib/krava.so
+ dst -> /lib/debil.so
+
+ ret -> /lib/debil.so
+*/
+static int match_path(struct lt_config_audit *cfg, const char *name,
+ struct lt_objsearch *s, char **ret)
+{
+ PRINT_VERBOSE(cfg->sh.verbose, 2, "name [%s], src [%s], dst [%s]\n",
+ name, s->src, s->dst);
+
+ *ret = s->dst;
+
+ if (!strcmp(name, s->src))
+ return 1;
+
+ return 0;
+}
+
+/*
+ Matching src in the name, if found,
+ replace the src with dst part.
+
+ name -> /lib/krava.so
+ src -> krava
+ dst -> debil
+
+ ret -> /lib/debil.so
+*/
+static int match_ptn(struct lt_config_audit *cfg, const char *name,
+ struct lt_objsearch *s, char **ret)
+{
+ char *pat, *r;
+
+ PRINT_VERBOSE(cfg->sh.verbose, 2, "name [%s], src [%s], dst [%s]\n",
+ name, s->src, s->dst);
+
+ pat = strstr(name, s->src);
+ if (!pat)
+ return 0;
+
+ r = *ret = malloc(strlen(name) + strlen(s->dst));
+ if (!r) {
+ perror("malloc failed");
+ return 0;
+ }
+
+ strncpy(r, name, pat - name);
+ r += (pat - name);
+ strcpy(r, s->dst);
+ strcat(r, pat + strlen(s->src));
+
+ PRINT_VERBOSE(cfg->sh.verbose, 2, "return %s\n", *ret);
+
+ return 1;
+}
+
+/*
+ Looking for src in the name, if found,
+ replace the name with dst.
+
+ name -> /lib/krava.so
+ src -> krava
+ dst -> /lib/krava1.so
+
+ ret -> /lib/krava1.so
+*/
+static int match_ptn2path(struct lt_config_audit *cfg, const char *name,
+ struct lt_objsearch *s, char **ret)
+{
+ PRINT_VERBOSE(cfg->sh.verbose, 2, "name [%s], src [%s], dst [%s]\n",
+ name, s->src, s->dst);
+
+ *ret = s->dst;
+ if (strstr(name, s->src))
+ return 1;
+
+ return 0;
+}
+
+static int match(struct lt_config_audit *cfg, const char *name,
+ struct lt_objsearch *s, char **ret)
+{
+ switch(s->type) {
+ case LT_OS_PATH:
+ return match_path(cfg, name, s, ret);
+ case LT_OS_PTN:
+ return match_ptn(cfg, name, s, ret);
+ case LT_OS_PTN2PATH:
+ return match_ptn2path(cfg, name, s, ret);
+ };
+
+ return 0;
+}
+
+int lt_objsearch_init(struct lt_config_audit *cfg, char **ptr, int cnt)
+{
+ int i;
+
+ for(i = 0; i < cnt; i++)
+ if (-1 == add_subst(cfg, ptr[i]))
+ return -1;
+
+ return 0;
+}
+
+char* lt_objsearch(struct lt_config_audit *cfg, const char *name,
+ uintptr_t *cookie, unsigned int flag)
+{
+ int i;
+ char *ret = NULL;
+
+ for(i = 0; i < cfg->subst_cnt; i++)
+ if (match(cfg, name, &cfg->subst[i], &ret))
+ return ret;
+
+ return (char*) name;
+}
diff --git a/src/output.c b/src/output.c
new file mode 100644
index 0000000..b8e8bed
--- /dev/null
+++ b/src/output.c
@@ -0,0 +1,125 @@
+/*
+ Copyright (C) 2008, 2009 Jiri Olsa <olsajiri@gmail.com>
+
+ This file is part of the latrace.
+
+ The latrace 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 3 of the License, or
+ (at your option) any later version.
+
+ The latrace 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 the latrace (file COPYING). If not, see
+ <http://www.gnu.org/licenses/>.
+*/
+
+#include <stdlib.h>
+
+#include "config.h"
+
+static char spaces[] = " ";
+
+static int print_details(struct lt_config_shared *cfg, char *argdbuf)
+{
+ fprintf(cfg->fout, "%s\n", argdbuf);
+ return 0;
+}
+
+#define PRINT_TID() \
+do { \
+ fprintf(cfg->fout, "%5d ", (pid_t) syscall(SYS_gettid)); \
+} while(0)
+
+/* libiberty external */
+extern char* cplus_demangle(const char *mangled, int options);
+
+#define DEMANGLE(sym, d) \
+do { \
+ char *dem; \
+ dem = cplus_demangle(sym, 0); \
+ if (dem) { \
+ sym = dem; \
+ d = 1; \
+ } \
+} while(0)
+
+int lt_out_entry(struct lt_config_shared *cfg, const char *symname, char *lib_to,
+ char *argbuf, char *argdbuf)
+{
+ int demangled = 0;
+
+ /* Print thread ID */
+ if (!cfg->hide_tid)
+ PRINT_TID();
+
+ /* Print indentation. */
+ if (cfg->indent_depth && cfg->indent_sym)
+ fprintf(cfg->fout, "%.*s", cfg->indent_depth * cfg->indent_size, spaces);
+
+ /* Demangle the symbol if needed */
+ if (cfg->demangle)
+ DEMANGLE(symname, demangled);
+
+ /* Print the symbol and arguments. */
+ if (*argbuf)
+ fprintf(cfg->fout, "%s(%s) [%s] {\n", symname, argbuf, lib_to);
+ else
+ fprintf(cfg->fout, "%s [%s] %c\n",
+ symname, lib_to,
+ cfg->braces ? '{' : ' ');
+
+ if (demangled)
+ free((char*) symname);
+
+ /* Print arguments' details. */
+ if (cfg->args_detailed && *argdbuf)
+ print_details(cfg, argdbuf);
+
+ fflush(NULL);
+ return 0;
+}
+
+int lt_out_exit(struct lt_config_shared *cfg, const char *symname, char *lib_to,
+ char *argbuf, char *argdbuf)
+{
+ int demangled = 0;
+
+ if (!*argbuf && (!cfg->braces))
+ return 0;
+
+ /* Print thread ID */
+ if (!cfg->hide_tid)
+ PRINT_TID();
+
+ /* Print indentation. */
+ if (cfg->indent_depth && cfg->indent_sym)
+ fprintf(cfg->fout, "%.*s", cfg->indent_depth * cfg->indent_size, spaces);
+
+ /* We got here, because we have '-B' option enabled. */
+ if (!*argbuf && (cfg->braces)) {
+ fprintf(cfg->fout, "}\n");
+ return 0;
+ }
+
+ /* Demangle the symbol if needed */
+ if (cfg->demangle)
+ DEMANGLE(symname, demangled);
+
+ /* Print the symbol and arguments. */
+ fprintf(cfg->fout, "} %s%s\n", symname, argbuf);
+
+ if (demangled)
+ free((char*) symname);
+
+ /* Print arguments' details. */
+ if (cfg->args_detailed && *argdbuf)
+ print_details(cfg, argdbuf);
+
+ fflush(NULL);
+ return 0;
+}
diff --git a/src/run.c b/src/run.c
new file mode 100644
index 0000000..23eb983
--- /dev/null
+++ b/src/run.c
@@ -0,0 +1,319 @@
+/*
+ Copyright (C) 2008, 2009 Jiri Olsa <olsajiri@gmail.com>
+
+ This file is part of the latrace.
+
+ The latrace 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 3 of the License, or
+ (at your option) any later version.
+
+ The latrace 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 the latrace (file COPYING). If not, see
+ <http://www.gnu.org/licenses/>.
+*/
+
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/select.h>
+#include <sys/inotify.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <string.h>
+#include <errno.h>
+
+#include "config.h"
+
+extern char **environ;
+extern struct timeval tv_program_start;
+extern struct timeval tv_program_stop;
+
+
+static int store_config(struct lt_config_app *cfg, char *file)
+{
+ int fd;
+
+ if (-1 == (fd = open(file, O_CREAT | O_TRUNC | O_RDWR,
+ S_IRUSR))) {
+ perror("open failed");
+ return -1;
+ }
+
+ if (-1 == write(fd, &cfg->sh, sizeof(cfg->sh))) {
+ perror("read failed");
+ return -1;
+ }
+
+ close(fd);
+ return 0;
+}
+
+static int set_dir_notify(char *dir)
+{
+ int fd;
+
+ if (-1 == (fd = inotify_init())) {
+ perror("inotify_init failed");
+ return -1;
+ }
+
+ if (-1 == inotify_add_watch(fd, dir, IN_CREATE)) {
+ perror("inotify_add_watch failed");
+ return -1;
+ }
+
+ return fd;
+}
+
+static int get_fifo_dir(char *buf, int len)
+{
+ snprintf(buf, len , "%s-XXXXXX", CONFIG_LT_CONFIG);
+ if (NULL == mkdtemp(buf)) {
+ perror("mkdtemp failed");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int get_fifo(struct lt_config_app *cfg, int notify_fd,
+ char *dir, pid_t *pid)
+{
+ char str_fifo[LT_MAXFILE];
+ unsigned char buf[1000];
+ struct inotify_event *event = (struct inotify_event*) buf;
+
+ if (-1 == read(notify_fd, event, 1000)) {
+ perror("read notify failed");
+ return -1;
+ }
+
+ sscanf(event->name, "fifo-%d", pid);
+ sprintf(str_fifo, "%s/%s", dir, event->name);
+
+ PRINT_VERBOSE(cfg->sh.verbose, 1, "thread id %d, got fifo: %s\n",
+ *pid, str_fifo);
+
+ return lt_fifo_open(cfg, str_fifo);
+}
+
+static int process_fifo(struct lt_config_app *cfg, struct lt_thread *t)
+{
+ static char buf[FIFO_MSG_MAXLEN];
+
+ struct lt_fifo_mbase *mbase = (struct lt_fifo_mbase*) buf;
+
+ if (-1 == lt_fifo_recv(cfg, t, mbase, FIFO_MSG_MAXLEN))
+ return -1;
+
+ if ((FIFO_MSG_TYPE_ENTRY != mbase->type) &&
+ (FIFO_MSG_TYPE_EXIT != mbase->type)) {
+ PRINT_VERBOSE(cfg->sh.verbose, 1, "unexpected message type %d\n",
+ mbase->type);
+ return -1;
+ }
+
+ struct lt_fifo_msym *msym = (struct lt_fifo_msym*) buf;
+
+ if (cfg->sh.counts)
+ return lt_stats_sym(cfg, t, msym);
+
+ if (FIFO_MSG_TYPE_ENTRY == msym->h.type) {
+
+ cfg->sh.indent_depth++;
+ lt_out_entry(&cfg->sh,
+ msym->data + msym->sym,
+ msym->data + msym->lib,
+ msym->data + msym->arg,
+ msym->data + msym->argd);
+
+ } else if (FIFO_MSG_TYPE_EXIT == msym->h.type) {
+
+ lt_out_exit(&cfg->sh,
+ msym->data + msym->sym,
+ msym->data + msym->lib,
+ msym->data + msym->arg,
+ msym->data + msym->argd);
+
+ cfg->sh.indent_depth--;
+ }
+
+ return 0;
+}
+
+static int process(struct lt_config_app *cfg, pid_t pid, char *dir, int notify_fd)
+{
+ int finish = 0, getin = 1;
+ int max_fd = notify_fd;
+ fd_set cfg_set, wrk_set;
+ int status;
+
+ FD_ZERO(&cfg_set);
+ FD_SET(notify_fd, &cfg_set);
+
+ while(!waitpid(pid, &status, WNOHANG) ||
+ /* let all the thread fifo close */
+ (finish) ||
+ /* Get inside at least once, in case the traced program
+ finished before we got here. Another case is if there's
+ an input on notify descriptor, we want to try another
+ select to be sure we dont miss any other event. */
+ (getin))
+ {
+
+ struct timeval tv = { 0, 100 };
+ struct lt_thread *t;
+ int ret;
+
+ getin = 0;
+
+ wrk_set = cfg_set;
+ if (-1 == (ret = select(max_fd + 1, &wrk_set, NULL, NULL, &tv))) {
+ perror("select failed");
+ return -1;
+ }
+
+ if (!ret)
+ continue;
+
+ /* process notify */
+ if (FD_ISSET(notify_fd, &wrk_set)) {
+ int fd;
+ pid_t pid;
+
+ /* try to get any event at least once again */
+ getin = 1;
+
+ if (-1 == (fd = get_fifo(cfg, notify_fd, dir, &pid)))
+ continue;
+
+ if (NULL == (t = lt_thread_add(cfg, fd, pid))) {
+ close(fd);
+ continue;
+ }
+
+ finish++;
+
+ FD_SET(fd, &cfg_set);
+ max_fd = (max_fd < fd ? fd : max_fd);
+ ret--;
+ }
+
+ /* process fifo */
+ for(t = cfg->threads; t ; t = t->next) {
+ if (FD_ISSET(t->fifo_fd, &wrk_set)) {
+ if (-1 == process_fifo(cfg, t)) {
+ FD_CLR(t->fifo_fd, &cfg_set);
+ gettimeofday(&t->tv_stop, NULL);
+ finish--;
+ }
+ ret--;
+ }
+ }
+ }
+
+ return status;
+}
+
+static int remove_dir(struct lt_config_app *cfg, char *name)
+{
+ DIR *dir;
+ struct dirent *d;
+
+ if (NULL == (dir = opendir(name))) {
+ perror("opendir failed");
+ return -1;
+ }
+
+ while((d = readdir(dir))) {
+ char file[LT_MAXFILE];
+
+ if (!strcmp(".", d->d_name) ||
+ (!strcmp("..", d->d_name)))
+ continue;
+
+ sprintf(file, "%s/%s", name, d->d_name);
+ if (-1 == (unlink(file)))
+ perror("unlink failed");
+ }
+
+ closedir(dir);
+
+ if (-1 == remove(name)) {
+ perror("remove failed");
+ return -1;
+ }
+
+ return 0;
+}
+
+int lt_run(struct lt_config_app *cfg)
+{
+ pid_t child_pid;
+ char str_dir[LT_MAXFILE];
+ char str_cfg[LT_MAXFILE];
+ int status;
+ int notify_fd = -1;
+
+ if (-1 == get_fifo_dir(str_dir, LT_MAXFILE))
+ return -1;
+
+ sprintf(str_cfg, "%s/config", str_dir);
+ if (-1 == store_config(cfg, str_cfg))
+ return -1;
+
+ if (cfg->sh.pipe &&
+ (-1 == (notify_fd = set_dir_notify(str_dir))))
+ return -1;
+
+ gettimeofday(&tv_program_start, NULL);
+
+ if (0 == (child_pid = fork())) {
+ char str_audit[100];
+
+ sprintf(str_audit, "%s/libltaudit.so.%s", CONFIG_LIBDIR, LT_VER);
+ setenv("LD_AUDIT", str_audit, 1);
+ setenv("LT_DIR", str_dir, 1);
+
+ PRINT_VERBOSE(cfg->sh.verbose, 1, "executing %s\n", cfg->prog);
+
+ if (-1 == execvp(cfg->prog, cfg->arg)) {
+ printf("execve failed for \"%s\" : %s\n",
+ cfg->prog, strerror(errno));
+ return -1;
+ }
+ } else if (child_pid < 0) {
+ perror("fork failed");
+ return -1;
+ }
+
+ if (cfg->sh.pipe)
+ status = process(cfg, child_pid, str_dir, notify_fd);
+ else
+ waitpid(child_pid, &status, 0);
+
+ gettimeofday(&tv_program_stop, NULL);
+
+ printf("\n%s finished - ", cfg->prog);
+
+ if (WIFEXITED(status)) {
+ printf("exited, status=%d\n", WEXITSTATUS(status));
+ } else if (WIFSIGNALED(status)) {
+ printf("killed by signal %d\n", WTERMSIG(status));
+ }
+
+ remove_dir(cfg, str_dir);
+ return 0;
+}
diff --git a/src/stats.c b/src/stats.c
new file mode 100644
index 0000000..59e0d9c
--- /dev/null
+++ b/src/stats.c
@@ -0,0 +1,328 @@
+/*
+ Copyright (C) 2008, 2009 Jiri Olsa <olsajiri@gmail.com>
+
+ This file is part of the latrace.
+
+ The latrace 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 3 of the License, or
+ (at your option) any later version.
+
+ The latrace 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 the latrace (file COPYING). If not, see
+ <http://www.gnu.org/licenses/>.
+*/
+
+
+#include <search.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <setjmp.h>
+
+#include "config.h"
+
+
+struct timeval tv_program_start;
+struct timeval tv_program_stop;
+
+/* res = a - b*/
+static int tv_sub(struct timeval *res, struct timeval *a, struct timeval *b)
+{
+ res->tv_sec = a->tv_sec - b->tv_sec;
+
+ if (a->tv_usec > b->tv_usec)
+ res->tv_usec = a->tv_usec - b->tv_usec;
+ else {
+ res->tv_usec = a->tv_usec + (1000000 - b->tv_usec);
+ if (res->tv_sec)
+ res->tv_sec--;
+ }
+
+ return 0;
+}
+
+/* res = a + b*/
+static int tv_add(struct timeval *res, struct timeval *a, struct timeval *b)
+{
+ struct timeval tv;
+ tv.tv_sec = a->tv_sec + b->tv_sec;
+ tv.tv_usec = a->tv_usec + b->tv_usec;
+ if (tv.tv_usec > 1000000) {
+ tv.tv_usec -= 1000000;
+ tv.tv_sec++;
+ }
+
+ *res = tv;
+ return 0;
+}
+
+int lt_stats_alloc(struct lt_config_app *cfg, struct lt_thread *t)
+{
+ int i;
+
+ if (!t->sym_array) {
+ if (!hcreate_r(t->sym_max = LT_SYM_HMAX, &t->sym_htab)) {
+ perror("hcreate_r failed");
+ return -1;
+ }
+
+ t->sym_array = (struct lt_stats_sym**) malloc(
+ t->sym_max * sizeof(struct lt_stats_sym*));
+
+ if (!t->sym_array) {
+ perror("malloc failed");
+ return -1;
+ }
+
+ return 0;
+ }
+
+
+ PRINT_VERBOSE(cfg->sh.verbose, 1,
+ "too bad, out of symbols, reallocation... %p - %d\n",
+ t->sym_array, t->sym_cnt);
+
+ /* hash table reallocation */
+ t->sym_max += LT_SYM_HMAX;
+ hdestroy_r(&t->sym_htab);
+
+ PRINT_VERBOSE(cfg->sh.verbose, 1, "creating new hash table\n");
+
+ if (!hcreate_r(t->sym_max, &t->sym_htab)) {
+ perror("hcreate_r failed");
+ return -1;
+ }
+
+ t->sym_array = (struct lt_stats_sym**) realloc(t->sym_array,
+ t->sym_max * sizeof(struct lt_stats_sym*));
+
+ if (!t->sym_array) {
+ perror("realloc failed");
+ return -1;
+ }
+
+ PRINT_VERBOSE(cfg->sh.verbose, 1,
+ "adding symbols to new hash table %p\n",
+ t->sym_array);
+
+ for(i = 0; i < t->sym_cnt; i++) {
+ ENTRY e, *ep;
+ struct lt_stats_sym *sym;
+
+ sym = t->sym_array[i];
+ e.key = sym->name;
+ e.data = sym;
+
+ PRINT_VERBOSE(cfg->sh.verbose, 1,
+ "adding symbol %s\n", sym->name);
+
+ if (0 == hsearch_r(e, ENTER, &ep, &t->sym_htab)) {
+ printf("failed to add hash item during reallocation\n");
+ return -1;
+ }
+ }
+
+ PRINT_VERBOSE(cfg->sh.verbose, 1, "reallocation ok\n");
+ return 0;
+}
+
+int lt_stats_sym(struct lt_config_app *cfg, struct lt_thread *t,
+ struct lt_fifo_msym* m)
+{
+ ENTRY e, *ep;
+ char buf[1000];
+ struct lt_stats_sym *sym;
+ jmp_buf env;
+ int realloc = 0;
+
+ sprintf(buf, "%s%s", m->data + m->sym, m->data + m->lib);
+ e.key = strdup(buf);
+ e.data = 0;
+
+ /* array got out of space */
+ if ((t->sym_cnt == t->sym_max) && (-1 == lt_stats_alloc(cfg, t)))
+ return -1;
+
+ /* hash table got out of space */
+ if (setjmp(env))
+ realloc = 1;
+
+ if (0 == hsearch_r(e, ENTER, &ep, &t->sym_htab)) {
+ if (!realloc) {
+ if (-1 == lt_stats_alloc(cfg, t))
+ return -1;
+ longjmp(env, 1);
+ }
+ return -1;
+ }
+
+ if (!ep->data) {
+ sym = malloc(sizeof(struct lt_stats_sym));
+ memset(sym, 0, sizeof(struct lt_stats_sym));
+
+ ep->data = sym;
+
+ sym->name = e.key;
+ sym->sym = strdup(m->data + m->sym);
+ sym->lib = strdup(m->data + m->lib);
+
+ t->sym_array[t->sym_cnt] = sym;
+ t->sym_cnt++;
+
+ PRINT_VERBOSE(cfg->sh.verbose, 1,
+ "adding symbol %d %s\n", t->sym_cnt, sym->name);
+ } else
+ free(e.key);
+
+ sym = ep->data;
+ if (FIFO_MSG_TYPE_ENTRY == m->h.type) {
+ sym->call++;
+ sym->tv_cur = m->h.tv;
+ }
+
+ if (FIFO_MSG_TYPE_EXIT == m->h.type) {
+ struct timeval tv;
+ tv_sub(&tv, &m->h.tv, &sym->tv_cur);
+ tv_add(&sym->tv_all, &sym->tv_all, &tv);
+ }
+
+ return 0;
+}
+
+static int csort;
+
+static int qsort_compar(const void *a, const void *b)
+{
+ struct lt_stats_sym *data_a = *((struct lt_stats_sym**) a);
+ struct lt_stats_sym *data_b = *((struct lt_stats_sym**) b);
+
+ if (csort == LT_CSORT_TIME) {
+ if (data_a->tv_all.tv_sec != data_b->tv_all.tv_sec)
+ return data_b->tv_all.tv_sec - data_a->tv_all.tv_sec;
+ return data_b->tv_all.tv_usec - data_a->tv_all.tv_usec;
+ }
+
+ if (csort == LT_CSORT_PERCENT) {
+ int percent_a = data_a->percent * 100000;
+ int percent_b = data_b->percent * 100000;
+ return percent_b - percent_a;
+ }
+
+ if (csort == LT_CSORT_CALL) {
+ return data_b->call - data_a->call;
+ }
+
+ if (csort == LT_CSORT_UCALL) {
+ return data_b->usec_call - data_a->usec_call;
+ }
+
+ if (csort == LT_CSORT_LIB) {
+ int ret = strcmp(data_a->lib, data_b->lib);
+ if (ret)
+ return ret;
+ return strcmp(data_a->sym, data_b->sym);
+ }
+
+ if (csort == LT_CSORT_SYM) {
+ int ret = strcmp(data_a->sym, data_b->sym);
+ if (ret)
+ return ret;
+ return strcmp(data_a->lib, data_b->lib);
+ }
+
+ return 0;
+}
+
+static int lt_stats_show_thread(struct lt_config_app *cfg, struct lt_thread *t)
+{
+ int i;
+ struct timeval tv_thread_real;
+ struct timeval tv_thread_accu = { 0, 0};
+ float time_global;
+
+ PRINT_VERBOSE(cfg->sh.verbose, 1, "counting total time\n");
+ for(i = 0; i < t->sym_cnt; i++) {
+ struct lt_stats_sym *sym = t->sym_array[i];
+ tv_add(&tv_thread_accu, &tv_thread_accu, &sym->tv_all);
+ }
+
+ time_global = tv_thread_accu.tv_sec * 1000000 + tv_thread_accu.tv_usec;
+
+ PRINT_VERBOSE(cfg->sh.verbose, 1, "counting post mortem statistics\n");
+
+ for(i = 0; i < t->sym_cnt; i++) {
+ struct lt_stats_sym *sym = t->sym_array[i];
+ u_int time_sym = sym->tv_all.tv_sec*1000000 + sym->tv_all.tv_usec;
+
+ sym->percent = time_sym / (time_global/100);
+ sym->usec_call = time_sym/sym->call;
+ }
+
+ PRINT_VERBOSE(cfg->sh.verbose, 1, "sorting\n");
+
+ csort = cfg->csort;
+ qsort(t->sym_array, t->sym_cnt, sizeof(struct lt_stats_sym*), qsort_compar);
+
+ PRINT_VERBOSE(cfg->sh.verbose, 1, "printing\n");
+
+ tv_sub(&tv_thread_real, &t->tv_stop, &t->tv_start);
+ printf("\nThread %d (runtime %u.%06u sec)\n",
+ t->tid, (u_int) tv_thread_real.tv_sec, (u_int) tv_thread_real.tv_usec);
+ printf("%3s %-6s %10s %10s %10s %-30s\n",
+ "sec", "usec", "%", "usec/call", "calls", "symbol");
+ printf("%3s %-6s %10s %10s %10s %-30s\n",
+ "---", "------", "----------", "----------", "----------", "------------------------------");
+
+ for(i = 0; i < t->sym_cnt; i++) {
+ struct lt_stats_sym *sym = t->sym_array[i];
+
+ /* sec:usec */
+ printf("%3u:%06u ", (u_int) sym->tv_all.tv_sec, (u_int) sym->tv_all.tv_usec);
+
+ /* % */
+ printf("%10f ", sym->percent);
+
+ /* usec/call */
+ printf("%10u ", sym->usec_call);
+
+ /* call */
+ printf("%10u ", sym->call);
+
+ if (LT_CSORT_LIB == cfg->csort) {
+ /* calls symbol */
+ printf("%s ", sym->lib);
+ printf("%s\n", sym->sym);
+ } else {
+ printf("%s@", sym->sym);
+ printf("%s\n", sym->lib);
+ }
+ }
+
+ return 0;
+}
+
+int lt_stats_show(struct lt_config_app *cfg)
+{
+ struct lt_thread *t;
+
+ struct timeval tv_program_real;
+ tv_sub(&tv_program_real, &tv_program_stop, &tv_program_start);
+
+ printf("\n--------------------------------------------------------------------------\n");
+ printf("Statistics for [%s] total runtime: %u.%06u sec\n",
+ cfg->prog,
+ (u_int) tv_program_real.tv_sec,
+ (u_int) tv_program_real.tv_usec);
+
+ for(t = lt_thread_first(cfg); t; t = lt_thread_next(cfg))
+ lt_stats_show_thread(cfg, t);
+
+ return 0;
+}
+
diff --git a/src/sysdeps/arm/stack.c b/src/sysdeps/arm/stack.c
new file mode 100644
index 0000000..d1388e0
--- /dev/null
+++ b/src/sysdeps/arm/stack.c
@@ -0,0 +1,269 @@
+/*
+ ARM EABI argument extraction
+
+ Copyright (C) 2009 Akos Pasztory <akos.pasztory@gmail.com>
+
+ This file is part of the latrace.
+
+ The latrace 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 3 of the License, or
+ (at your option) any later version.
+
+ The latrace 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 the latrace (file COPYING). If not, see
+ <http://www.gnu.org/licenses/>.
+*/
+
+
+#include "config.h"
+
+static inline unsigned long align_up(unsigned long v, unsigned long a)
+{
+ return (v + a-1) & ~(a-1);
+}
+
+/*
+ * The .arch field is split the following way:
+ * -- valid :1
+ * -- size :15
+ * -- offset :16
+ */
+
+static inline void arch_set(struct lt_arg *arg,
+ unsigned int size, unsigned int offs)
+{
+ arg->arch = (void *)((size << 16) | offs | 0x80000000);
+}
+
+static inline int arch_valid(struct lt_arg *arg)
+{
+ return (unsigned int)arg->arch & 0x80000000;
+}
+
+static inline unsigned int arch_get_size(struct lt_arg *arg)
+{
+ return ((unsigned int)arg->arch & ~0x80000000) >> 16;
+}
+
+static inline unsigned int arch_get_offs(struct lt_arg *arg)
+{
+ return (unsigned int)arg->arch & 0xffff;
+}
+
+/* Processes a struct entirely in memory. */
+static int process_struct_mem(struct lt_config_shared *cfg, struct lt_arg *arg,
+ void *pval, struct lt_args_data *data)
+{
+ int i;
+ unsigned long npval;
+ struct lt_arg *a;
+
+ lt_args_cb_struct(cfg, LT_ARGS_STRUCT_ITSELF, arg, 0, data, 0);
+ npval = (unsigned long)pval;
+ i = 0;
+ lt_list_for_each_entry(a, arg->args_head, args_list) {
+ lt_args_cb_struct(cfg, LT_ARGS_STRUCT_ARG, a,
+ (void *)(npval + arch_get_offs(a)),
+ data, i+1 == arg->mmbcnt);
+ ++i;
+ }
+ return 0;
+}
+
+/* Returns a bytearray slice from OFFS with SIZE length, treating the
+ * registers and the stack consecutively. Return value is static,
+ * only valid until the next get() call. */
+static void *get(unsigned long offs, int size, La_regs *regs)
+{
+ /* NB: size of buf is fixed. But if we only copy POD types, hopefully
+ * it won't become a problem. */
+ static __thread char buf[64];
+ int i;
+
+ for (i = 0; i < size; ++i) {
+ if (offs+i < 16)
+ buf[i] = ((char *)regs->lr_reg)[offs+i];
+ else
+ buf[i] = *(char *)(regs->lr_sp + (offs+i-16));
+ }
+ return buf;
+}
+
+/* Calculate member sizes and offsets of a structure. Returns the
+ * size of the entire structure. */
+static unsigned int calcstruct(struct lt_arg *arg)
+{
+ unsigned int maxl, moffs;
+ struct lt_arg *a;
+
+ /* XXX: this is incorrect for struct-in-struct... */
+ maxl = moffs = 0;
+ lt_list_for_each_entry(a, arg->args_head, args_list) {
+ /* We need to know the strictest aligned member to
+ * determine the size of the entire struct. */
+ if (a->type_len > maxl)
+ maxl = a->type_len;
+ /* Align members naturally. */
+ moffs = align_up(moffs, a->type_len);
+ arch_set(a, a->type_len, moffs);
+ moffs += a->type_len;
+ }
+ return align_up(moffs, maxl);
+}
+
+/* Calculates all offsets and `real' (padded) sizes of arguments
+ * (including struct members). Stores them in ->arch. */
+static void calcofs(struct lt_args_sym *asym)
+{
+ int i;
+ unsigned int offs;
+ struct lt_arg *arg;
+
+ /* If function returns a struct by value larger than a word,
+ * it is stored in callee-allocated memory and r0 contains the
+ * address. */
+ arg = asym->args[LT_ARGS_RET];
+ offs = 0;
+ if (arg->dtype == LT_ARGS_DTYPE_STRUCT) {
+ if (!arg->pointer)
+ offs = 4;
+ arch_set(arg, calcstruct(arg), 0);
+ }
+ for (i = 1; i < asym->argcnt; ++i) {
+ unsigned int asize;
+
+ arg = asym->args[i];
+ /* Struct sizes/offsets should be calculated at all times. */
+ if (arg->dtype == LT_ARGS_DTYPE_STRUCT)
+ calcstruct(arg);
+ if (arg->dtype != LT_ARGS_DTYPE_STRUCT || arg->pointer) {
+ /* Non-composite type. */
+ /* Size is 4 if arg is smaller than a word. */
+ asize = arg->type_len;
+ if (asize < 4)
+ asize = 4;
+ /* Types are aligned to their sizes. */
+ offs = align_up(offs, asize);
+ arch_set(arg, asize, offs);
+ } else {
+ /* Composite type. */
+ asize = calcstruct(arg);
+ arch_set(arg, asize, offs);
+ }
+ offs += asize;
+ /* If we are allocating from registers (4*4 bytes),
+ * each arg must start in a new one. */
+ if (offs < 16)
+ offs = align_up(offs, 4);
+ }
+}
+
+/*
+ * -- args which fit are in r0..r3, rest is on the stack
+ * -- if return type is struct, r0 contains the address for it
+ * -- dword sized args must be aligned at even registers
+ * -- one argument may be split between registers and stack
+ * -- on stack, 8byte values are aligned % 8 == 0
+ */
+int lt_stack_process(struct lt_config_shared *cfg, struct lt_args_sym *asym,
+ La_regs *regs, struct lt_args_data *data)
+{
+ int i;
+
+ for (i = 1; i < asym->argcnt; ++i) {
+ struct lt_arg *arg;
+ void *p;
+ unsigned int o, lastp;
+
+ lastp = i+1 == asym->argcnt;
+ arg = asym->args[i];
+ if (!arch_valid(arg))
+ calcofs(asym);
+ /* POD */
+ if (arg->dtype != LT_ARGS_DTYPE_STRUCT) {
+ p = get(arch_get_offs(arg), arch_get_size(arg), regs);
+ lt_args_cb_arg(cfg, arg, p, data, lastp, 1);
+ continue;
+ }
+ /* struct pointer */
+ if (arg->pointer) {
+ p = get(arch_get_offs(arg), sizeof(void *), regs);
+ p = *(void **)p;
+ lt_args_cb_arg(cfg, arg, p, data, lastp, 1);
+ if (cfg->args_detailed)
+ process_struct_mem(cfg, arg, p, data);
+ continue;
+ }
+ /* struct by value */
+ o = arch_get_offs(arg);
+ /* If part of the struct is in registers this outputs 'REG',
+ * otherwise, the stack address is printed. */
+ lt_args_cb_arg(cfg, arg,
+ (void *)(o < 16 ? 0 : regs->lr_sp + o-16),
+ data, lastp, 1);
+ if (cfg->args_detailed) {
+ int j;
+ struct lt_arg *m;
+
+ j = 0;
+ lt_args_cb_struct(cfg, LT_ARGS_STRUCT_ITSELF, arg,
+ 0, data, 0);
+ lt_list_for_each_entry(m, arg->args_head, args_list) {
+ unsigned int o;
+
+ o = arch_get_offs(arg) + arch_get_offs(m);
+ p = get(o, arch_get_size(m), regs);
+ lt_args_cb_struct(cfg, LT_ARGS_STRUCT_ARG, m,
+ p, data, j+1 == arg->mmbcnt);
+ ++j;
+ }
+ }
+ }
+ return 0;
+}
+
+/*
+ * -- 32bit return values in r0
+ * -- 64bit in {r0, r1}
+ * -- composite < 4bytes in r0
+ * -- composite > 4bytes in memory (address is passed as the first parameter
+ * of the call)
+ */
+int lt_stack_process_ret(struct lt_config_shared *cfg,
+ struct lt_args_sym *asym, La_retval *regs,
+ struct lt_args_data *data)
+{
+ struct lt_arg *arg;
+ void *pval;
+
+ /* I think this works for both 32 and 64 bit values (r0 and r1
+ * are consecutive in lrv_reg[]). */
+ pval = &(regs->lrv_reg[0]);
+ arg = asym->args[LT_ARGS_RET];
+ lt_args_cb_arg(cfg, arg, pval, data, 1, 0);
+ if (cfg->args_detailed && arg->dtype == LT_ARGS_DTYPE_STRUCT) {
+ unsigned int asize;
+ /* AAPCS says: a composite type less than 4 bytes is
+ * returned in r0. Larger types have memory allocated
+ * by caller and its address passed as the (hidden)
+ * 1st argument.
+ *
+ * NB: Though I, personally, haven't found it in the
+ * AAPCS, it's both logical (and apparently gcc does
+ * so) to return this address in r0. */
+ asize = arch_get_size(arg);
+ if (arg->pointer || asize > 4)
+ pval = (void *)regs->lrv_reg[0];
+ else if (asize > 4)
+ pval = &regs->lrv_reg[0];
+ process_struct_mem(cfg, arg, pval, data);
+ }
+ return 0;
+}
+/* End of stack.c */
diff --git a/src/sysdeps/i686/stack.c b/src/sysdeps/i686/stack.c
new file mode 100644
index 0000000..5d2c539
--- /dev/null
+++ b/src/sysdeps/i686/stack.c
@@ -0,0 +1,131 @@
+/*
+ Copyright (C) 2008, 2009 Jiri Olsa <olsajiri@gmail.com>
+
+ This file is part of the latrace.
+
+ The latrace 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 3 of the License, or
+ (at your option) any later version.
+
+ The latrace 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 the latrace (file COPYING). If not, see
+ <http://www.gnu.org/licenses/>.
+*/
+
+
+#include "config.h"
+#include "stack.h"
+
+static int process_struct(struct lt_config_shared *cfg, struct lt_arg *arg,
+ void *pval, struct lt_args_data *data)
+{
+ struct lt_arg *a;
+ int i = 0;
+
+ lt_args_cb_struct(cfg, LT_ARGS_STRUCT_ITSELF, arg, pval, data, 0);
+
+ if (arg->pointer)
+ pval = *((void**) pval);
+
+ lt_list_for_each_entry(a, arg->args_head, args_list) {
+ int last = (i + 1) == arg->mmbcnt;
+
+ /* For the type size up to word (4), the offset of the member
+ is aligned to its size. For the type size over the word,
+ the offset of the member is aligned to word. */
+
+ int nsize = a->type_len > 4 ? 4 : a->type_len;
+ int naligned = (u_int) pval % nsize;
+
+ if (naligned)
+ pval += nsize - naligned;
+
+ lt_args_cb_struct(cfg, LT_ARGS_STRUCT_ARG, a, pval, data, last);
+
+ pval += a->type_len;
+ i++;
+ }
+
+ return 0;
+}
+
+/*
+ the traced program stack (in regs)
+ should look like this:
+
+ ...
+ esp + 12 2nd argument
+ esp + 8 1st argument
+ esp + 4 possible return structure/union address
+ esp return function address
+
+*/
+int lt_stack_process(struct lt_config_shared *cfg, struct lt_args_sym *asym,
+ La_regs *regs, struct lt_args_data *data)
+{
+ int i;
+ void *pval;
+ struct lt_arg *argret;
+
+ /* get the esp reg and skip the return address */
+ pval = (void*) regs->lr_esp;
+ pval += sizeof(void*);
+
+
+ /* if the function returns structure by value,
+ there's a hidden first argument we need to skip */
+ argret = asym->args[LT_ARGS_RET];
+ if ((!argret->pointer) &&
+ (argret->dtype == LT_ARGS_DTYPE_STRUCT))
+ pval += sizeof(void*);
+
+
+ for(i = 1; i < asym->argcnt; i++) {
+
+ struct lt_arg *arg = asym->args[i];
+ int last = (i + 1) == asym->argcnt;
+
+ lt_args_cb_arg(cfg, arg, pval, data, last, 1);
+
+ if ((cfg->args_detailed) &&
+ (LT_ARGS_DTYPE_STRUCT == arg->dtype))
+ process_struct(cfg, arg, pval, data);
+
+ pval += arg->pointer ? sizeof(void*) : LT_STACK_ALIGN(arg->type_len);
+ }
+
+ return 0;
+}
+
+/* x86 is easy, everything is in eax register */
+int lt_stack_process_ret(struct lt_config_shared *cfg, struct lt_args_sym *asym,
+ La_retval *regs, struct lt_args_data *data)
+{
+ struct lt_arg *arg;
+ void *pval;
+
+ pval = (void*) &(regs->lrv_eax);
+ arg = asym->args[LT_ARGS_RET];
+
+ lt_args_cb_arg(cfg, arg, pval, data, 1, 0);
+
+ if ((cfg->args_detailed) &&
+ (LT_ARGS_DTYPE_STRUCT == arg->dtype)) {
+
+ /* The process_struct function does its own
+ dereference of pval value in case of pointer
+ argument, so we need to prepare pval correctly. */
+ if (!arg->pointer)
+ pval = (void*) regs->lrv_eax;
+
+ process_struct(cfg, arg, pval, data);
+ }
+
+ return 0;
+}
diff --git a/src/sysdeps/i686/stack.h b/src/sysdeps/i686/stack.h
new file mode 100644
index 0000000..0060132
--- /dev/null
+++ b/src/sysdeps/i686/stack.h
@@ -0,0 +1,27 @@
+/*
+ Copyright (C) 2008, 2009 Jiri Olsa <olsajiri@gmail.com>
+
+ This file is part of the latrace.
+
+ The latrace 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 3 of the License, or
+ (at your option) any later version.
+
+ The latrace 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 the latrace (file COPYING). If not, see
+ <http://www.gnu.org/licenses/>.
+*/
+
+
+#ifndef STACK_H
+#define STACK_H
+
+#define LT_STACK_ALIGN(arg) ((arg + 3) & ~3)
+
+#endif // !STACK_H
diff --git a/src/sysdeps/x86_64/stack.c b/src/sysdeps/x86_64/stack.c
new file mode 100644
index 0000000..2273506
--- /dev/null
+++ b/src/sysdeps/x86_64/stack.c
@@ -0,0 +1,615 @@
+/*
+ Copyright (C) 2008, 2009 Jiri Olsa <olsajiri@gmail.com>
+
+ This file is part of the latrace.
+
+ The latrace 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 3 of the License, or
+ (at your option) any later version.
+
+ The latrace 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 the latrace (file COPYING). If not, see
+ <http://www.gnu.org/licenses/>.
+*/
+
+
+#include "config.h"
+#include "stack.h"
+
+static __thread int ass_integer;
+static __thread int ass_sse;
+static __thread int ass_memory;
+
+#define ASS_CLEANUP() \
+do { \
+ ass_integer = ass_sse = ass_memory = 0; \
+} while(0)
+
+/* INTEGER registers used for function arguments. */
+static long ass_regs_integer[] = {
+ LT_64_REG_RDI,
+ LT_64_REG_RSI,
+ LT_64_REG_RDX,
+ LT_64_REG_RCX,
+ LT_64_REG_R8,
+ LT_64_REG_R9,
+};
+#define ASS_REGS_INTEGER_CNT (sizeof(ass_regs_integer)/sizeof(long))
+#define ASS_REGS_INTEGER_SIZE (sizeof(ass_regs_integer))
+
+/* INTEGER registers used for function return arguments. */
+static long ass_regs_integer_ret[] = {
+ LT_64_REG_RAX,
+ LT_64_REG_RDX,
+};
+#define ASS_REGS_INTEGER_RET_CNT (sizeof(ass_regs_integer_ret)/sizeof(long))
+#define ASS_REGS_INTEGER_RET_SIZE (sizeof(ass_regs_integer_ret))
+
+/* SSE registers used for function arguments. */
+static long ass_regs_sse[] = {
+ LT_64_REG_XMM0,
+ LT_64_REG_XMM1,
+ LT_64_REG_XMM2,
+ LT_64_REG_XMM3,
+ LT_64_REG_XMM4,
+ LT_64_REG_XMM5,
+ LT_64_REG_XMM6,
+ LT_64_REG_XMM7,
+};
+#define ASS_REGS_SSE_CNT (sizeof(ass_regs_sse)/sizeof(long))
+
+/* SSE registers used for function return arguments. They
+ are xmm0 and xmm1, so we reuse the ass_regs_sse array.*/
+#define ASS_REGS_SSE_RET_CNT (2)
+
+static int classificate_arg(struct lt_config_shared *cfg, struct lt_arg *arg,
+ int ret, int align);
+
+static int classificate_memory(struct lt_config_shared *cfg,
+ struct lt_arg *arg, int align)
+{
+ if (align)
+ ass_memory = LT_STACK_ALIGN(ass_memory);
+ else {
+ int naligned = ass_memory % arg->type_len;
+
+ if (naligned)
+ ass_memory += arg->type_len - naligned;
+ }
+
+ PRINT_VERBOSE(cfg->verbose, 2, "%s - ass %d\n",
+ arg->name, ass_memory);
+
+ ARCH_SET(arg, ARCH_FLAG_MEM, ass_memory);
+
+ if (arg->pointer)
+ ass_memory += sizeof(void*);
+ else
+ ass_memory += arg->type_len;
+
+ return 0;
+}
+
+static int classificate_integer(struct lt_config_shared *cfg,
+ struct lt_arg *arg, int align, int regs_size)
+{
+ if (!align) {
+ int ass = LT_STACK_ALIGN(ass_integer);
+ int naligned = ass_integer % arg->type_len;
+
+ if (naligned)
+ ass_integer += arg->type_len - naligned;
+
+ if ((ass_integer + arg->type_len) > ass)
+ ass_integer = LT_STACK_ALIGN(ass_integer);
+ }
+
+ PRINT_VERBOSE(cfg->verbose, 2,
+ "ass %s - reg size %d - ass_integer %d\n",
+ arg->name, regs_size, ass_integer);
+
+ if (ass_integer >= regs_size)
+ return -1;
+
+ ARCH_SET(arg, ARCH_FLAG_REG_INTEGER, ass_integer);
+
+ if (arg->pointer)
+ ass_integer += sizeof(void*);
+ else
+ ass_integer += align ? sizeof(void*) : arg->type_len;
+
+ return 0;
+}
+
+static int classificate_sse(struct lt_config_shared *cfg, struct lt_arg *arg,
+ int sse_cnt)
+{
+ PRINT_VERBOSE(cfg->verbose, 2, "ass %s %d %d\n",
+ arg->name, ASS_REGS_SSE_CNT, ass_sse);
+
+ if (sse_cnt == ass_sse)
+ return -1;
+
+ ARCH_SET(arg, ARCH_FLAG_REG_SSE, ass_sse++);
+ return 0;
+}
+
+static void struct_arch(struct lt_config_shared *cfg, struct lt_arg *sarg,
+ struct lt_arg *farg)
+{
+ if (sarg->pointer)
+ return;
+
+ /* Structures passed by value dont have the arch assigned by default.
+ If the first argument is returned in memory, the structure takes
+ this pointer, if it is register, we keep it NULL, and lt_args_cb_arg
+ will print out the REG kw for value.*/
+ PRINT_VERBOSE(cfg->verbose, 2,
+ "first argument for struct %s has flag: %d\n",
+ sarg->name, ARCH_GET_FLAG(farg));
+
+ if (ARCH_GET_FLAG(farg) == ARCH_FLAG_MEM)
+ sarg->arch = farg->arch;
+ else
+ ARCH_SET(sarg, ARCH_FLAG_SVREG, 0);
+}
+
+
+static int classificate_struct_try(struct lt_config_shared *cfg,
+ struct lt_arg *arg, int allmem, int ret)
+{
+ struct lt_arg *a;
+ int first = 1;
+ int saved_ass_integer = ass_integer;
+ int saved_ass_sse = ass_sse;
+ int saved_ass_memory = ass_memory;
+
+ lt_list_for_each_entry(a, arg->args_head, args_list) {
+
+ if (allmem)
+ classificate_memory(cfg, a, first);
+ else {
+ if (-1 == classificate_arg(cfg, a, ret, 0))
+ return -1;
+
+ if (ARCH_GET_FLAG(arg) == ARCH_FLAG_MEM) {
+ /* There is not enough registers, reset to
+ have the structure in memory only. */
+ ass_integer = saved_ass_integer;
+ ass_sse = saved_ass_sse;
+ ass_memory = saved_ass_memory;
+ return -1;
+ }
+
+ }
+
+ if (first) {
+ struct_arch(cfg, arg, a);
+ first = 0;
+ }
+ }
+
+ return 0;
+}
+
+static int get_sizeof(struct lt_config_shared *cfg, struct lt_arg *arg)
+{
+ struct lt_arg *a;
+ int size = 0;
+
+ lt_list_for_each_entry(a, arg->args_head, args_list) {
+
+ int naligned = (u_int) size % a->type_len;
+
+ if (naligned)
+ size += a->type_len - naligned;
+
+ size += a->type_len;
+ }
+
+ PRINT_VERBOSE(cfg->verbose, 2, "sizeof(struct %s) = %d\n",
+ arg->type_name, size);
+
+ return size;
+}
+
+static int classificate_struct(struct lt_config_shared *cfg, struct lt_arg *arg,
+ int ret)
+{
+ int allmem = 0;
+ int size = get_sizeof(cfg, arg);
+
+ /* If the structure is bigger than 16B or passed as pointer then
+ it is in the memory (no registers). If the structure is up to
+ 16B and passed by value, we might need t classificate its members,
+ because they could fit in registers. */
+ if ((size > 16) || (arg->pointer))
+ allmem = 1;
+
+ PRINT_VERBOSE(cfg->verbose, 2,
+ "struct %s - length sum %d - allmem %d\n",
+ arg->type_name, arg->type_len, allmem);
+
+ if (-1 == classificate_struct_try(cfg, arg, allmem, ret))
+ classificate_struct_try(cfg, arg, 1, ret);
+
+ return 0;
+}
+
+static int classificate_arg_type(struct lt_config_shared *cfg,
+ struct lt_arg *arg)
+{
+ int class;
+
+ do {
+ /* pointers are INTEGER class by default */
+ if (arg->pointer) {
+ class = LT_CLASS_INTEGER;
+ break;
+ }
+
+ switch(arg->type_id) {
+ case LT_ARGS_TYPEID_CHAR:
+ case LT_ARGS_TYPEID_UCHAR:
+ case LT_ARGS_TYPEID_SHORT:
+ case LT_ARGS_TYPEID_USHORT:
+ case LT_ARGS_TYPEID_INT:
+ case LT_ARGS_TYPEID_UINT:
+ case LT_ARGS_TYPEID_LONG:
+ case LT_ARGS_TYPEID_ULONG:
+ case LT_ARGS_TYPEID_LLONG:
+ case LT_ARGS_TYPEID_ULLONG:
+ class = LT_CLASS_INTEGER;
+ break;
+
+ case LT_ARGS_TYPEID_DOUBLE:
+ case LT_ARGS_TYPEID_FLOAT:
+ class = LT_CLASS_SSE;
+ break;
+
+ default:
+ class = LT_CLASS_NONE;
+ break;
+ }
+
+ } while(0);
+
+ PRINT_VERBOSE(cfg->verbose, 2,
+ "argument %s dtype %d - type %s(%d) - class %d\n",
+ arg->name, arg->dtype, arg->type_name, arg->type_id,
+ class);
+ return class;
+}
+
+static int classificate_arg(struct lt_config_shared *cfg, struct lt_arg *arg,
+ int ret, int align)
+{
+ int class;
+ int class_failed = 0;
+
+ PRINT_VERBOSE(cfg->verbose, 2, "got arg \"%s\"\n",
+ arg->name);
+
+ ARCH_ZERO(arg);
+
+ if (arg->dtype != LT_ARGS_DTYPE_POD) {
+
+ if (-1 == classificate_struct(cfg, arg, ret))
+ return -1;
+
+ /* If the structure is passed by pointer, we
+ still need the pointer classification. */
+ if (!arg->pointer)
+ return 0;
+ }
+
+ class = classificate_arg_type(cfg, arg);
+ if (-1 == class)
+ return -1;
+
+ /* Nothing to be done for NONE class (void type) */
+ if (LT_CLASS_NONE == class)
+ return 0;
+
+ switch(class) {
+ case LT_CLASS_SSE:
+ class_failed = classificate_sse(cfg, arg,
+ ret ? ASS_REGS_SSE_RET_CNT :
+ ASS_REGS_SSE_CNT);
+ break;
+
+ case LT_CLASS_INTEGER:
+ class_failed = classificate_integer(cfg, arg, align,
+ ret ? ASS_REGS_INTEGER_RET_SIZE :
+ ASS_REGS_INTEGER_SIZE);
+ break;
+
+ case LT_CLASS_MEMORY:
+ classificate_memory(cfg, arg, 1);
+ break;
+ }
+
+ /* If class INTEGER or SSE ran out of registers,
+ then arg is in memory. */
+ if (class_failed)
+ classificate_memory(cfg, arg, 1);
+
+ return 0;
+}
+
+static int classificate(struct lt_config_shared *cfg, struct lt_args_sym *sym)
+{
+ int i;
+ struct lt_arg *arg = sym->args[LT_ARGS_RET];
+
+ PRINT_VERBOSE(cfg->verbose, 2, "got symbol \"%s\"\n",
+ sym->name);
+
+ ASS_CLEANUP();
+
+ /* Classificate the return value first. */
+ if (-1 == classificate_arg(cfg, arg, 1, 1))
+ return -1;
+
+ ASS_CLEANUP();
+
+ /* If the return value is memory class,
+ then the edi register is used as a first hidden arg.*/
+ if (ARCH_GET_FLAG(arg) == ARCH_FLAG_MEM)
+ ass_integer += 8;
+
+ for(i = 1; i < sym->argcnt; i++) {
+ arg = sym->args[i];
+
+ if (-1 == classificate_arg(cfg, arg, 0, 1))
+ return -1;
+ }
+
+ return 0;
+}
+
+static void *get_value_mem(struct lt_config_shared *cfg, struct lt_arg *arg,
+ void *regs, int ret)
+{
+ long offset = ARCH_GET_OFFSET(arg);
+ void *pval;
+
+ if (ret) {
+ void *base = (void*) ((struct La_x86_64_retval*) regs)->lrv_rax;
+ pval = base + offset;
+ } else {
+ void *base = (void*) ((struct La_x86_64_regs*) regs)->lr_rsp;
+ pval = base + /* current stack pointer */
+ sizeof(void*) + /* return function address */
+ offset;
+ }
+
+ PRINT_VERBOSE(cfg->verbose, 2, "offset = %ld, %s = %p, ret = %d\n",
+ offset, arg->name, pval, ret);
+ return pval;
+}
+
+static void *get_value_reg_integer(struct lt_config_shared *cfg,
+ struct lt_arg *arg, void *regs, int ret)
+{
+ struct La_x86_64_retval *regs_ret = regs;
+ struct La_x86_64_regs *regs_in = regs;
+ void *pval = NULL;
+ long offset = ARCH_GET_OFFSET(arg);
+ long qoff = offset % sizeof(long);
+ long reg = ret ? ass_regs_integer_ret[offset / sizeof(long)] :
+ ass_regs_integer[offset / sizeof(long)];
+
+
+ PRINT_VERBOSE(cfg->verbose, 2,
+ "offset %ld - reg %ld - qoff %ld - ASS_REGS_CNT %ld - ret %d\n",
+ offset, reg, qoff, ASS_REGS_INTEGER_CNT, ret);
+
+ switch(reg) {
+ case LT_64_REG_RAX:
+ pval = &regs_ret->lrv_rax;
+ break;
+ case LT_64_REG_RDX:
+ pval = ret ? &regs_ret->lrv_rdx : &regs_in->lr_rdx;
+ break;
+ case LT_64_REG_RDI:
+ pval = &regs_in->lr_rdi;
+ break;
+ case LT_64_REG_RSI:
+ pval = &regs_in->lr_rsi;
+ break;
+ case LT_64_REG_RCX:
+ pval = &regs_in->lr_rcx;
+ break;
+ case LT_64_REG_R8:
+ pval = &regs_in->lr_r8;
+ break;
+ case LT_64_REG_R9:
+ pval = &regs_in->lr_r9;
+ break;
+ }
+
+ pval += qoff;
+
+ PRINT_VERBOSE(cfg->verbose, 2, "argument %s = %p (%lx)\n",
+ arg->name, pval, *((u_long*)pval));
+ return pval;
+}
+
+static void *get_value_reg_sse(struct lt_config_shared *cfg,
+ struct lt_arg *arg, void *regs, int ret)
+{
+ int i = ARCH_GET_OFFSET(arg);
+ void *pval = NULL;
+
+ if (ret) {
+ struct La_x86_64_retval *regs_ret = regs;
+
+ switch(i) {
+ case 0:
+ pval = &regs_ret->lrv_xmm0;
+ break;
+ case 1:
+ pval = &regs_ret->lrv_xmm1;
+ break;
+ }
+ } else {
+ struct La_x86_64_regs *regs_in = regs;
+
+ pval = &regs_in->lr_xmm[i];
+ }
+
+
+ PRINT_VERBOSE(cfg->verbose, 2, "argument %s = %p (%lx), ret %d\n",
+ arg->name, pval, *((u_long*)pval), ret);
+ return pval;
+}
+
+static void* get_value(struct lt_config_shared *cfg, struct lt_arg *arg,
+ void *regs, int ret)
+{
+ void *pval = NULL;
+
+ PRINT_VERBOSE(cfg->verbose, 2, "get value for %s - arch = %lx, flag = %d\n",
+ arg->name, ARCH_GET(arg), ARCH_GET_FLAG(arg));
+
+ switch(ARCH_GET_FLAG(arg)) {
+ case ARCH_FLAG_MEM:
+ pval = get_value_mem(cfg, arg, regs, ret);
+ break;
+
+ case ARCH_FLAG_REG_INTEGER:
+ pval = get_value_reg_integer(cfg, arg, regs, ret);
+ break;
+
+ case ARCH_FLAG_REG_SSE:
+ pval = get_value_reg_sse(cfg, arg, regs, ret);
+ break;
+ }
+
+ return pval;
+}
+
+/* Process structure stored completelly in the
+ memory - pointed to by 'pval' arg. */
+static int process_struct_mem(struct lt_config_shared *cfg, struct lt_arg *arg,
+ void *pval, struct lt_args_data *data)
+{
+ struct lt_arg *a;
+ int i = 0;
+
+ PRINT_VERBOSE(cfg->verbose, 2, "for %s - arch = %llx\n",
+ arg->name, ARCH_GET(arg));
+
+ lt_args_cb_struct(cfg, LT_ARGS_STRUCT_ITSELF, arg, NULL, data, 0);
+
+ lt_list_for_each_entry(a, arg->args_head, args_list) {
+ int last = (i + 1) == arg->mmbcnt;
+ void *pv = pval + ARCH_GET_OFFSET(a);
+
+ lt_args_cb_struct(cfg, LT_ARGS_STRUCT_ARG, a, pv, data, last);
+
+ i++;
+ }
+
+ return 0;
+}
+
+static int process_struct_arg(struct lt_config_shared *cfg, struct lt_arg *arg,
+ void *regs, struct lt_args_data *data, int ret)
+{
+ struct lt_arg *a;
+ int i = 0;
+
+ PRINT_VERBOSE(cfg->verbose, 2, "for %s - arch = %llx\n",
+ arg->name, ARCH_GET(arg));
+
+ lt_args_cb_struct(cfg, LT_ARGS_STRUCT_ITSELF, arg, NULL, data, 0);
+
+ lt_list_for_each_entry(a, arg->args_head, args_list) {
+ int last = (i + 1) == arg->mmbcnt;
+ void *pval = NULL;
+
+ pval = get_value(cfg, a, regs, ret);
+
+ lt_args_cb_struct(cfg, LT_ARGS_STRUCT_ARG, a, pval, data, last);
+ i++;
+ }
+
+ return 0;
+}
+
+static void process_detailed_struct(struct lt_config_shared *cfg,
+ struct lt_arg *arg, void *pval, struct lt_args_data *data,
+ void *regs, int ret)
+{
+ if (arg->pointer)
+ pval = *((void**) pval);
+
+ if (ARCH_GET_FLAG(arg) == ARCH_FLAG_MEM) {
+ process_struct_mem(cfg, arg, pval, data);
+ } else {
+ if (arg->pointer)
+ process_struct_mem(cfg, arg, pval, data);
+ else
+ process_struct_arg(cfg, arg, regs, data, ret);
+ }
+}
+
+
+int lt_stack_process(struct lt_config_shared *cfg, struct lt_args_sym *asym,
+ La_regs *regs, struct lt_args_data *data)
+{
+ int i;
+
+ if (!ARCH_GET(asym->args[LT_ARGS_RET]) &&
+ (-1 == classificate(cfg, asym)))
+ return -1;
+
+ for(i = 1; i < asym->argcnt; i++) {
+ void *pval = NULL;
+ struct lt_arg *arg = asym->args[i];
+ int last = (i + 1) == asym->argcnt;
+
+ pval = get_value(cfg, arg, regs, 0);
+ if ((!pval) &&
+ (arg->pointer || (LT_ARGS_DTYPE_STRUCT != arg->dtype))) {
+ PRINT_VERBOSE(cfg->verbose, 2,
+ "THIS SHOULD NEVER HAPPEN - arg '%s %s'\n",
+ arg->type_name, arg->name);
+ continue;
+ }
+
+ lt_args_cb_arg(cfg, arg, pval, data, last, 1);
+
+ if ((cfg->args_detailed) &&
+ (LT_ARGS_DTYPE_STRUCT == arg->dtype))
+ process_detailed_struct(cfg, arg, pval, data, regs, 0);
+ }
+
+ return 0;
+}
+
+int lt_stack_process_ret(struct lt_config_shared *cfg, struct lt_args_sym *asym,
+ La_retval *regs, struct lt_args_data *data)
+{
+ struct lt_arg *arg;
+ void *pval;
+
+ arg = asym->args[LT_ARGS_RET];
+ pval = get_value(cfg, arg, regs, 1);
+
+ lt_args_cb_arg(cfg, arg, pval, data, 1, 0);
+
+ if ((cfg->args_detailed) &&
+ (LT_ARGS_DTYPE_STRUCT == arg->dtype))
+ process_detailed_struct(cfg, arg, pval, data, regs, 0);
+
+ return 0;
+}
diff --git a/src/sysdeps/x86_64/stack.h b/src/sysdeps/x86_64/stack.h
new file mode 100644
index 0000000..7a24617
--- /dev/null
+++ b/src/sysdeps/x86_64/stack.h
@@ -0,0 +1,90 @@
+/*
+ Copyright (C) 2008, 2009 Jiri Olsa <olsajiri@gmail.com>
+
+ This file is part of the latrace.
+
+ The latrace 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 3 of the License, or
+ (at your option) any later version.
+
+ The latrace 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 the latrace (file COPYING). If not, see
+ <http://www.gnu.org/licenses/>.
+*/
+
+
+#ifndef STACK_H
+#define STACK_H
+
+/*
+ TODO Describe the implementation in more details TODO
+
+ Architecture specific data inside lt_arg.
+
+ bits 64 32|31 0
+ --------------------|--------------------
+ fields flags | offset
+
+
+ offset
+ - offset or memory or registers
+ flags
+ - memory/registers switch
+*/
+
+#define LT_STACK_ALIGN(arg) ((arg + 7) & ~7)
+
+#define ARCH_POS_FLAGS 32
+
+#define ARCH_FLAG_MEM 1L
+#define ARCH_FLAG_REG_INTEGER 2L
+#define ARCH_FLAG_REG_SSE 3L
+#define ARCH_FLAG_SVREG 4L
+
+#define ARCH_GET(arg) ((int64_t) ((arg)->arch))
+#define ARCH_GET_FLAG(arg) ((int) ((long) arg->arch >> ARCH_POS_FLAGS))
+#define ARCH_GET_OFFSET(arg) ((long) ((long) arg->arch & 0xFFFFFFFFL))
+
+#define ARCH_ZERO(arg) \
+do {\
+ arg->arch = NULL; \
+} while(0)
+
+#define ARCH_SET(arg, flags, offset) \
+do { \
+ arg->arch = (void*) (offset + \
+ (flags << ARCH_POS_FLAGS)); \
+} while(0)
+
+/* registers index */
+#define LT_64_REG_RAX 1
+#define LT_64_REG_RCX 2
+#define LT_64_REG_RDX 3
+#define LT_64_REG_RDI 4
+#define LT_64_REG_RSI 5
+#define LT_64_REG_R8 6
+#define LT_64_REG_R9 7
+#define LT_64_REG_RBP 8
+#define LT_64_REG_RSP 9
+#define LT_64_REG_XMM0 10
+#define LT_64_REG_XMM1 11
+#define LT_64_REG_XMM2 12
+#define LT_64_REG_XMM3 13
+#define LT_64_REG_XMM4 14
+#define LT_64_REG_XMM5 15
+#define LT_64_REG_XMM6 16
+#define LT_64_REG_XMM7 17
+
+/* argument classes */
+#define LT_CLASS_NONE 1
+#define LT_CLASS_INTEGER 2
+#define LT_CLASS_SSE 3
+#define LT_CLASS_MEMORY 4096
+
+#endif // !STACK_H
diff --git a/src/thread.c b/src/thread.c
new file mode 100644
index 0000000..70ff1ef
--- /dev/null
+++ b/src/thread.c
@@ -0,0 +1,61 @@
+/*
+ Copyright (C) 2008, 2009 Jiri Olsa <olsajiri@gmail.com>
+
+ This file is part of the latrace.
+
+ The latrace 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 3 of the License, or
+ (at your option) any later version.
+
+ The latrace 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 the latrace (file COPYING). If not, see
+ <http://www.gnu.org/licenses/>.
+*/
+
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "config.h"
+
+
+struct lt_thread *lt_thread_add(struct lt_config_app *cfg, int fd, pid_t pid)
+{
+ struct lt_thread *t;
+
+ if (NULL == (t = (struct lt_thread*) malloc(sizeof(struct lt_thread)))) {
+ perror("malloc failed");
+ return NULL;
+ }
+
+ memset(t, 0x0, sizeof(*t));
+
+ if (-1 == lt_stats_alloc(cfg, t)) {
+ free(t);
+ return NULL;
+ }
+
+ t->fifo_fd = fd;
+ t->tid = pid;
+ gettimeofday(&t->tv_start, NULL);
+
+ t->next = cfg->threads;
+ cfg->threads = t;
+ return t;
+}
+
+struct lt_thread *lt_thread_first(struct lt_config_app *cfg)
+{
+ return cfg->iter = cfg->threads;
+}
+
+struct lt_thread *lt_thread_next(struct lt_config_app *cfg)
+{
+ return cfg->iter = (cfg->iter ? cfg->iter->next : NULL);
+}
diff --git a/test/test1.c b/test/test1.c
new file mode 100644
index 0000000..fb4df35
--- /dev/null
+++ b/test/test1.c
@@ -0,0 +1,278 @@
+#if 0
+
+# Copyright (C) 2009 Akos Pasztory <akos.pasztory@gmail.com>
+#
+# This file is part of the latrace.
+#
+# The latrace 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 3 of the License, or
+# (at your option) any later version.
+#
+# The latrace 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 the latrace (file COPYING). If not, see
+# <http://www.gnu.org/licenses/>.
+
+b="${0%.c}";
+cc -Wall -g -shared -fPIC -DTHE_SO -DTHE_CONFIG $0 -o "$b.so";
+cc -Wall -g -DTHE_APP -DTHE_CONFIG -Wl,-rpath . "$b.so" $0 -o "$b.bin";
+cpp -P -DTHE_CONFIG $0 > "$b.conf";
+latrace -a "$b.conf" -D "./$b.bin" | less;
+exit 0;
+#endif
+#if defined(THE_APP) || defined(THE_SO)
+#include <stdio.h>
+
+typedef unsigned long long u_llong;
+typedef long long llong;
+
+#endif
+#ifdef THE_CONFIG
+
+struct st1 {
+ char a; char b;
+};
+struct st2 {
+ int a; int b; int c; int d;
+};
+struct st3 {
+ int a; int b; int c; int d; int e; int f;
+};
+struct st4 {
+ int x; char y; int z;
+};
+struct st5 {
+ short a; int b; char c; int d; short e; char f; int g; char h; char i; short j; int k;
+};
+struct st6 {
+ char a; double b; short c; float d;
+};
+struct st7 {
+ double a;
+};
+struct st8 {
+ double a; char b; int c;
+};
+
+extern void a1(char x);
+void a2(short x);
+void a3(int x);
+void a4(llong x);
+
+void b1(char x, int y);
+void b2(int x, char y);
+void b3(int x, int y, int z, int q, int xx, int yy);
+
+struct st3 c1(int x);
+const struct st3 *c2(int x, char y, double z);
+char c3(int x, double y, char z);
+struct st1 c4(int x, double y);
+struct st7 c5(double x, double y);
+struct st8 c6(float x, double y);
+struct st4 c7(char x, long b);
+
+u_llong d1(void);
+void d2(u_llong x);
+void d3(int a, u_llong x);
+void d4(struct st3 x);
+void d5(char a, int y, struct st3 x);
+double d6(char a, int y);
+
+int l1(int x);
+int l2(int x, int y);
+int l3(int x, int y, int z);
+int l4(int x, int y, int z, int q);
+int l5(int x, int y, int z, int q, int xx);
+int l6(int x, int y, int z, int q, int xx, int yy);
+int l7(int x, int y, int z, int q, int xx, int yy, int zz);
+int l8(int x, int y, int z, int q, int xx, int yy, int zz, int qq);
+
+void s1(struct st1 x);
+void s1p(struct st1 *x);
+void s2(struct st2 x);
+void s3(struct st3 x);
+void s4(struct st4 x);
+void s5(struct st5 x);
+void s6(struct st6 x);
+
+struct st1 r1(void);
+struct st3 r3(void);
+struct st4 r4(void);
+
+void q1(int x, struct st1 y);
+void q2(int x, char y, struct st1 z);
+void q3(int x, int y, struct st2 z);
+void q4(int x, int y, struct st4 z);
+void q5(int x, int y, char z, char q, struct st4 w);
+
+int real1(const char *w);
+void real2(void);
+
+#endif
+#if defined(THE_APP) || defined(THE_SO)
+
+static struct st1 sx = {'a', 'b'};
+static struct st2 sy = {10, 20, 30, 40};
+static struct st3 sz = {10, 20, 30, 40, 50, 60};
+static struct st4 sq = {10, 'x', 30};
+static struct st5 sa = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
+static struct st6 sb = {1, 2, 3, 4};
+#endif
+#ifdef THE_SO
+
+void real2(void) { puts("i am beta"); }
+int real1(const char *w) { puts(w); real2(); return 3; }
+
+u_llong d1(void) { return 1LL + (1LL << 32); }
+void d2(u_llong x) { x;}
+void d3(int a, u_llong x) { a+x;}
+void d4(struct st3 x) { x; }
+void d5(char c, int y, struct st3 x) { x; }
+double d6(char a, int y) { return 1.0; }
+
+struct st3 c1(int x)
+{
+ static struct st3 e = {5,6,7,8,9,10};
+ return e;
+}
+
+const struct st3 *c2(int x, char y, double z)
+{
+ static struct st3 e = {5,6,7,8,9,10};
+ return &e;
+}
+
+char c3(int x, double y, char z)
+{
+ return z+1;
+}
+
+struct st1 c4(int x, double y)
+{
+ struct st1 p = { 'x', 'y' };
+ return p;
+}
+
+struct st7 c5(double x, double y)
+{
+ struct st7 p = { 1 };
+ return p;
+}
+
+struct st8 c6(float x, double y)
+{
+ struct st8 p = { 1, 'w', 0x10 };
+ return p;
+}
+
+struct st4 c7(char x, long b)
+{
+ struct st4 p = { 1, 'a', 2 };
+ return p;
+}
+
+int l1(int x) { return 2*x; }
+int l2(int x, int y) { return 3*y; }
+int l3(int x, int y, int z) { return x+y+z; }
+int l4(int x, int y, int z, int q) { return x+y+z; }
+int l5(int x, int y, int z, int q, int xx) { return x+y+z; }
+int l6(int x, int y, int z, int q, int xx, int yy) { return x+y+z; }
+int l7(int x, int y, int z, int q, int xx, int yy, int zz) { return x+y+z; }
+int l8(int x, int y, int z, int q, int xx, int yy, int zz, int qq) { return x+y+z; }
+
+void a1(char x) {}
+void a2(short x) {}
+void a3(int x) {}
+void a4(llong x) {}
+
+void b1(char x, int y) {}
+void b2(int x, char y) {}
+void b3(int x, int y, int z, int q, int xx, int yy) {}
+
+void s1(struct st1 x) {}
+void s1p(struct st1 *x) {}
+void s2(struct st2 x) {}
+void s3(struct st3 x) {}
+void s4(struct st4 x) {}
+void s5(struct st5 x) {}
+void s6(struct st6 x) {}
+
+struct st1 r1(void) { return sx; }
+struct st3 r3(void) { return sz; }
+struct st4 r4(void) { return sq; }
+
+void q1(int x, struct st1 y) {}
+void q2(int x, char y, struct st1 z) {}
+void q3(int x, int y, struct st2 z) {}
+void q4(int x, int y, struct st4 z) {}
+void q5(int x, int y, char z, char q, struct st4 w) {}
+
+
+#endif
+#ifdef THE_APP
+int main(void)
+{
+ static const struct st3 a = {1, 2, 3, 4, 5, 6};
+
+ l1(100);
+ l2(100, 200);
+ l3(100, 200, 300);
+ l4(100, 200, 300, 400);
+ l5(100, 200, 300, 400, 500);
+ l6(100, 200, 300, 400, 500, 600);
+ l7(100, 200, 300, 400, 500, 600, 700);
+ l8(100, 200, 300, 400, 500, 600, 700, 800);
+
+ d1();
+ d2(43);
+ d3(100, 200);
+ d4(a);
+ d5('a', 43, a);
+ d6('a', 1);
+
+ c1(44);
+ c2(100, 'a', 3.4);
+ c3(200, 2.777, 'q');
+ c4(200, 1);
+ c5(1.1, 2.2);
+ c6(1.23, 45.6);
+ c7('z', 0x200);
+
+ a1('a');
+ a2(10);
+ a3(20);
+ a4(102030405060LL);
+
+ b1('a', 20);
+ b2(30, 'b');
+ b3(10, 20, 30, 40, 50, 60);
+
+ s1(sx);
+ s1p(&sx);
+ s2(sy);
+ s3(sz);
+ s4(sq);
+ s5(sa);
+ s6(sb);
+
+ r1();
+ r3();
+ r4();
+
+ q1(200, sx);
+ q2(300, 't', sx);
+ q3(400, 410, sy);
+ q4(500, 510, sq);
+ q5(600, 610, 'z', 'q', sq);
+
+ real1("fresh air");
+ real2();
+
+ return 0;
+}
+#endif