diff options
author | Jiri Olsa <jolsa@shell.devel.redhat.com> | 2009-09-04 02:29:08 -0400 |
---|---|---|
committer | Jiri Olsa <jolsa@shell.devel.redhat.com> | 2009-09-04 02:29:08 -0400 |
commit | 04f3fbbfdb3a5dd197dbc25ca18ad244f1fbf6a5 (patch) | |
tree | 8e53039a4f5d1a4571000bc06214053261aebf8d | |
download | latrace-04f3fbbfdb3a5dd197dbc25ca18ad244f1fbf6a5.tar.gz latrace-04f3fbbfdb3a5dd197dbc25ca18ad244f1fbf6a5.tar.xz latrace-04f3fbbfdb3a5dd197dbc25ca18ad244f1fbf6a5.zip |
initial commit - 0.5.7
77 files changed, 10014 insertions, 0 deletions
@@ -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 @@ -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 @@ -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 = ®s->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 = ®s_ret->lrv_rax; + break; + case LT_64_REG_RDX: + pval = ret ? ®s_ret->lrv_rdx : ®s_in->lr_rdx; + break; + case LT_64_REG_RDI: + pval = ®s_in->lr_rdi; + break; + case LT_64_REG_RSI: + pval = ®s_in->lr_rsi; + break; + case LT_64_REG_RCX: + pval = ®s_in->lr_rcx; + break; + case LT_64_REG_R8: + pval = ®s_in->lr_r8; + break; + case LT_64_REG_R9: + pval = ®s_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 = ®s_ret->lrv_xmm0; + break; + case 1: + pval = ®s_ret->lrv_xmm1; + break; + } + } else { + struct La_x86_64_regs *regs_in = regs; + + pval = ®s_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 |